cc65 help

millenniumtree

New Member
Oct 2, 2019
24
16
3
I've got the cc65 toolchain producing and running binaries, but I've got questions about using some of the functions.

I'm in a loop, watching for escape, and printing the characters pressed and the decimal value of each key, but pressing the arrow keys moves the cursor, then prints the output in a weird place. How do I prevent the arrow key press from altering the position of the cursor? I just want to eat the keypress and print info about it. Should I use something other than cgetc()?

Code:
#include <stdint.h>
#include <stdio.h>
#include <conio.h>

void main(void) {
  uint8_t c;
  cbm_k_bsout(CH_FONT_UPPER);
  do {
    c = cgetc();
    printf("user pressed %c, with a decimal value of %d\n", c, c);
  } while (c != 3);
}
 

millenniumtree

New Member
Oct 2, 2019
24
16
3
You know what, I'm wrong.
The simple act of PRINTING the arrow character (up/down/left/right), is what is moving the cursor around.
I noticed that half my output line was on one line, and the rest was below it.

It's doing _precisely_ what it should do.

Images attached of what I was seeing, first with printing the arrow characters, second without.

Now to do something useful with it!
 

Attachments

  • Like
Reactions: BruceMcF

Hiraghm

New Member
May 18, 2019
24
5
3
You know what, I'm wrong.
The simple act of PRINTING the arrow character (up/down/left/right), is what is moving the cursor around.
I noticed that half my output line was on one line, and the rest was below it.

It's doing _precisely_ what it should do.

Images attached of what I was seeing, first with printing the arrow characters, second without.

Now to do something useful with it!
I just downloaded a snapshot for Windows, and I just installed cc65 for debian Linux following instructions here:
Installing CC65
Not sure now how best to go about using it; I'll need to probably configure Geany to build for/with cc65.
But I'm excited at the idea of both programming the X16 *and* the C64 in C!
I have fond memories of 6502 assembler, but C is still my favorite language.
 
  • Like
Reactions: Swift34

millenniumtree

New Member
Oct 2, 2019
24
16
3
I've played around with this a bit now, and am exploring the different character sets.

Here's a 'bare minimum' C source to get you started.

Code:
#include <stdint.h>
#include <stdio.h>
#include <conio.h>

#define POKE(addr,val)     (*(unsigned char*) (addr) = (val))
#define POKEW(addr,val)    (*(unsigned*) (addr) = (val))
#define PEEK(addr)         (*(unsigned char*) (addr))
#define PEEKW(addr)        (*(unsigned*) (addr))

static void vpoke(uint8_t bank, uint16_t address, uint8_t data) {
  // Set port 0's address.
  VERA.control = 0;
  VERA.address_hi = bank;
  VERA.address = address;
  // Store data through port 0.
  VERA.data0 = data;
}

void main(void) {
  uint8_t small_unsigned_int;
  uint16_t bigger_unsigned_int;
  int8_t small_signed_int;
  int16_t bigger_signed_int;

  // Now you can do stuff
}
And here's a bash script to compile/link and run a file called petscii.c
Code:
#!/bin/bash

rm petscii.prg
cl65 -O -t cx16 petscii.c -o petscii.prg
x16emu -scale 2 -prg petscii.prg -run
If you're in windows, you can do something similar with a batch file or whatever Windows is passing off as scripting these days. ;)
 
  • Like
Reactions: mobluse and Swift34

millenniumtree

New Member
Oct 2, 2019
24
16
3
Some other things I've discovered:

// These switch between upper and lowercase charsets, without clearing the screen
cbm_k_bsout(CH_FONT_UPPER);
cbm_k_bsout(CH_FONT_LOWER);
// These are equivalent, but less obvious
printf("%c",142);
printf("%c",14);
// You can clear the screen with either of these (they are equivalent)
cbm_k_bsout(147);
printf("%c",147);

// Clear the screen and switch charsets in one line
printf("%c%c",147,CH_FONT_UPPER);

// There's a hidden character set (decimal 15) that contains many foreign characters, but it also appears to break stuff

// You can move the cursor around by printing these 4 characters (these and many other defines are in include/cbm.h)
CH_CURS_UP == 145
CH_CURS_DOWN == 17
CH_CURS_LEFT == 157
CH_CURS_RIGHT == 29

I've attached an image showing the charsets (with hex and decimal next to each row)
And I also made a graphic of the ASCII charset (codepage 437).
I suspect some of the characters you enter in C strings are coming in with ASCII, so may need to be converted before printing.
 

Attachments

Last edited:
  • Like
Reactions: mobluse and Swift34

Hiraghm

New Member
May 18, 2019
24
5
3
Some other things I've discovered:

// These switch between upper and lowercase charsets, without clearing the screen
cbm_k_bsout(CH_FONT_UPPER);
cbm_k_bsout(CH_FONT_LOWER);
// These are equivalent, but less obvious
printf("%c",142);
printf("%c",14);
// You can clear the screen with either of these (they are equivalent)
cbm_k_bsout(147);
printf("%c",147);

// Clear the screen and switch charsets in one line
printf("%c%c",147,CH_FONT_UPPER);

// There's a hidden character set (decimal 15) that contains many foreign characters, but it also appears to break stuff

// You can move the cursor around by printing these 4 characters (these and many other defines are in include/cbm.h)
CH_CURS_UP == 145
CH_CURS_DOWN == 17
CH_CURS_LEFT == 157
CH_CURS_RIGHT == 29

I've attached an image showing the charsets (with hex and decimal next to each row)
Cool! Thanks so much!
 

millenniumtree

New Member
Oct 2, 2019
24
16
3
Some weird behavior when printing characters.
I think it has to do with strings being entered in ASCII.

I've written an 'a2p' (ASCII TO PETSCII) function to pipe strings through, and will post it later if anyone is interested.

(sorry for all the edits - I want this information to be accurate, and I'm still figuring stuff out)
 
Last edited:
  • Like
Reactions: Swift34

millenniumtree

New Member
Oct 2, 2019
24
16
3
I was still trying to figure out how to convert typed character codes into something you'd expect to be output, without having multiple 512 byte lookup tables, or huge if/else blocks.

So the problem is that there are 3 different character codes being used when you write strings in C.

1) strings entered in the code are in ASCII, or something like it.
2) keys typed into the emulator are in something else, though I'm not sure what - maybe the C64 key codes.
3) then there are 2 charsets available, that the above char/key codes need to be translated into.

I'm not sure if most people will want to use the lowercase or uppercase charsets. I've been using the lowercase one for testing to try to get both LC and UC.

Also be aware that caps lock doesn't work as you'd expect on a PC. To change case, you have to hold shift.

Maybe there could be a preprocessor tool to convert C strings before execution, which would prevent the system having to do it runtime.

There are several characters missing from PETSCII too. Some can be easily substituted with graphical characters, such as underscore and pipe. Others are harder, like tilde and backslash.
Maybe I'm overthinking that though. :D
 
  • Like
Reactions: DarwinNE

mobluse

New Member
Sep 20, 2019
21
8
3
You could switch to ISO8859-15 by printing '\x0f'. Otherwise in PETSCII-UC there is a character that looks like a backslash: '\x6d', i.e. ╲.
 
May 22, 2019
409
211
43
I was still trying to figure out how to convert typed character codes into something you'd expect to be output, without having multiple 512 byte lookup tables, or huge if/else blocks.

So the problem is that there are 3 different character codes being used when you write strings in C.

1) strings entered in the code are in ASCII, or something like it.
2) keys typed into the emulator are in something else, though I'm not sure what - maybe the C64 key codes.
3) then there are 2 charsets available, that the above char/key codes need to be translated into.
The problem is that you're trying to translate PS/2 scan codes to ASCII or PETSCII characters. There is no linear relationship between the two, and so the only way to convert them is with a scan code table. And since the Commander ROM can't be turned off, it makes the most sense to simply use the built-in KERNAL API calls (GETIN seems like the one you're looking for.)

There are several characters missing from PETSCII too. Some can be easily substituted with graphical characters, such as underscore and pipe. Others are harder, like tilde and backslash.
Maybe I'm overthinking that though.
The problem is that if you're using those in something like C code, they won't mean the same thing, since you'd be using a different binary value. It might be better to replace the character definition with the original ASCII character. You can put those back into the character set by simply re-writing the character definitions in VERA. Custom character sets in VERA are easy to do; you just need to write 8 bytes to the correct location. Finding that location requires reading some registers (since you should never assume VERA is in the boot configuration), but that's straightforward. I'll try to write up a simple custom character generator tonight - something that just puts the missing ASCII symbols back into the character set.
 

millenniumtree

New Member
Oct 2, 2019
24
16
3
I don't use ANSI C much... isn't it getc() or getch()?
Everything posted above used cgetc or scanf, but what those do under the hood, I'm not sure. Do they actually call the ROM functions, or something else?

UPDATE:
Found it. In the cc65 libsrc/cx16/cgetc.s file, we have assembler code that looks like the following... And clearly, it uses the ROM call GETIN

Code:
;
; 2019-10-01, Greg King
;
; char cgetc (void);
; /* Return a character from the keyboard. */
;

        .export         _cgetc

        .import         cursor, GETIN

        .include        "cx16.inc"
        .macpack        generic


_cgetc: ldx     KEY_COUNT       ; Get number of characters
        bnz     L3              ; Jump if there are already chars waiting

; Switch the cursor on if wanted.

        lda     CURS_FLAG       ; Save cursor's current enable flag
        tay
        lda     cursor
        jsr     setcursor
L1:     lda     KEY_COUNT
        bze     L1              ; Wait for key
        tya
        eor     #%00000001      ; (Cursor flag uses negative logic)
        jsr     setcursor       ; Restore previous cursor condition

; An internal Kernal function can't be used because it might be moved in future
; revisions.  Use an official function; but, make sure that it reads
; the keyboard.

L3:     ldy     IN_DEV          ; Save current input device
        stz     IN_DEV          ; Keyboard
        phy
        jsr     GETIN           ; Read char, and return in .A
        ply
        sty     IN_DEV          ; Restore input device
        ldx     #>$0000
        rts

; Switch the cursor on or off.

setcursor:
        tax                     ; On or off?
        bnz     seton           ; Go set it on
        lda     CURS_FLAG       ; Is the cursor currently off?
        bnz     crs9            ; Jump if yes
        inc     CURS_FLAG       ; Mark it as off
        ldx     CURS_STATE      ; Cursor currently displayed?
        bze     crs9            ; Jump if not

; Restore the current character in video RAM.
; Restore that character's colors.

        stz     VERA::CTRL      ; Use port 0
        lda     CURS_Y
        sta     VERA::ADDR+1    ; Set row number
        lda     #VERA::INC1     ; Increment address by one
        sta     VERA::ADDR+2
        lda     CURS_X          ; Get character column
        asl     a
        sta     VERA::ADDR
        ldx     CURS_CHAR
        stx     VERA::DATA0
        ldx     CURS_COLOR
        stx     VERA::DATA0
        stz     CURS_STATE      ; Cursor not displayed
crs9:   rts

seton:  stz     CURS_FLAG
        rts
 
Last edited: