Michael Steil, mist64@mac.com
This is the PRELIMINARY Programmer's Reference Guide for the Commander X16 computer. Every and any information in this document can change, as the product is still in development!
Table of contents
The Commander X16 is a modern home computer in the philosophy of Commodore computers like the VIC-20 and the C64.
Features:
As a modern sibling of the line of Commodore home computers, the Commander X16 is resaonably compatible with computers of that line.
The Commander X16 BASIC interpreter is 100% backwards-compatible with the Commodore 64 one. This includes the following features:
CHR$(147)
: clear screenCHR$(5)
: white textCHR$(18)
: reverseCHR$(14)
: switch to upper/lowercase fontCHR$(142)
: switch to uppercase/graphics fontBecause of the differences in hardware, the following functions and statements are incompatible between C64 and X16 BASIC programs.
POKE
: write to a memory addressPEEK
: read from a memory addressWAIT
: wait for memory contentsSYS
: execute machine language codeThe BASIC interpreter also currently shares all problems of the C64 version, like the slow garbage collector.
In addition to PETSCII, the X16 also supports the ISO-8859-15 character encoding. In ISO-8859-15 mode ("ISO mode"):
CHR$()
in BASIC and BSOUT
in machine language) now complies with ASCII and ISO-8859-15.This is the encoding:
0123456789ABCDEF
0x| |
1x| |
2x| !"#$%&'()*+,-./|
3x|0123456789:;<=>?|
4x|@ABCDEFGHIJKLMNO|
5x|PQRSTUVWXYZ[\]^_|
6x|`abcdefghijklmno|
7x|pqrstuvwxyz{|}~ |
8x| |
9x| |
Ax| ¡¢£€¥Š§š©ª«¬ ®¯|
Bx|°±²³Žµ¶·ž¹º»ŒœŸ¿|
Cx|ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏ|
Dx|ÐÑÒÓÔÕÖרÙÚÛÜÝÞß|
Ex|àáâãäåæçèéêëìíîï|
Fx|ðñòóôõö÷øùúûüýþÿ|
ISO mode can be enabled and disabled using two new control codes:
CHR$($0F)
: enable ISO modeCHR$($8F)
: disable ISO mode (default)You can also enable ISO mode in direct mode by pressing Ctrl+O
.
Important: In ISO mode, BASIC keywords need to be written in upper case, that is, they have to be entered with the Shift key down, and abbreviating keywords is no longer possible.
In regular BASIC text mode, the video controller supports 16 foreground colors and 16 background colors for each character on the screen.
The new "swap fg/bg color" code is useful to change the background color of the cursor, like this:
PRINT CHR$(1); : REM SWAP FG/BG
PRINT CHR$($1C); : REM SET FG COLOR TO RED
PRINT CHR$(1); : REM SWAP FG/BG
The new BASIC instruction COLOR
makes this easier, but the trick above can also be used from machine code programs.
To set the background color of the complete screen, it just has to be cleared after setting the color:
PRINT CHR$(147);
This is the set of all supported PETSCII control characters. Descriptions in bold indicate new codes compared to the C64:
Code | Code | ||||
---|---|---|---|---|---|
$00 | NULL | - | $80 | ||
$01 | SWAP COLORS | COLOR: ORANGE | $81 | ||
$02 | - | $82 | |||
$03 | STOP/RUN | $83 | |||
$04 | ATTRIBUTES: UNDERLINE | HELP | $84 | ||
$05 | COLOR: WHITE | F1 | $85 | ||
$06 | ATTRIBUTES: BOLD | F3 | $86 | ||
$07 | BELL | F5 | $87 | ||
$08 | BACKSPACE | F7 | $88 | ||
$09 | TAB | F2 | $89 | ||
$0A | LF | F4 | $8A | ||
$0B | ATTRIBUTES: ITALICS | F6 | $8B | ||
$0C | ATTRIBUTES: OUTLINE | F8 | $8C | ||
$0D | REGULAR/SHIFTED RETURN | $8D | |||
$0E | CHARSET: LOWER/UPPER CASE | $8E | |||
$0F | CHARSET: ISO ON/OFF | $8F | |||
$10 | F9 | COLOR: BLACK | $90 | ||
$11 | CURSOR: DOWN/UP | $91 | |||
$12 | ATTRIBUTES: REVERSE | ATTRIBUTES: CLEAR ALL | $92 | ||
$13 | HOME/CLEAR | $93 | |||
$14 | DEL/INSERT | $94 | |||
$15 | F10 | COLOR: BROWN | $95 | ||
$16 | F11 | COLOR: LIGHT RED | $96 | ||
$17 | F12 | COLOR: DARK GRAY | $97 | ||
$18 | SHIFT+TAB | COLOR: MIDDLE GRAY | $98 | ||
$19 | - | COLOR: LIGHT GREEN | $99 | ||
$1A | - | COLOR: LIGHT BLUE | $9A | ||
$1B | - | COLOR: LIGHT GRAY | $9B | ||
$1C | COLOR: RED | COLOR: PURPLE | $9C | ||
$1D | CURSOR: RIGHT | CURSOR: LEFT | $9D | ||
$1E | COLOR: GREEN | COLOR: YELLOW | $9E | ||
$1F | COLOR: BLUE | COLOR: CYAN | $9F |
Notes:
Pressing the F9
key cycles through the available keyboard layouts.
There are several new statement and functions. Note that all BASIC keywords (such as FOR
) get converted into tokens (such as $81
), and the tokens for the new keywords have not been finalized yet. Therefore, loading BASIC program saved from a different revision of BASIC may mix up keywords.
TYPE: Command FORMAT: CHAR <x>,<y>,<color>,<string>
Action: This command draws a text string on the graphics screen in a given color.
The string can contain printable ASCII characters (CHR$($20)
to CHR$($7E)
), as well most PETSCII control codes.
EXAMPLE of CHAR Statement:
10 SCREEN$80
20 A$="The quick brown fox jumps over the lazy dog."
24 CHAR0,6,0,A$
30 CHAR0,6+12,0,CHR$($04)+A$ :REM UNDERLINE
40 CHAR0,6+12*2,0,CHR$($06)+A$ :REM BOLD
50 CHAR0,6+12*3,0,CHR$($0B)+A$ :REM ITALICS
60 CHAR0,6+12*4,0,CHR$($0C)+A$ :REM OUTLINE
70 CHAR0,6+12*5,0,CHR$($12)+A$ :REM REVERSE
TYPE: Command FORMAT: CLS
Action: Clears the screen. Same effect as ?CHR$(147);
.
EXAMPLE of CLS Statement:
CLS
TYPE: Command FORMAT: COLOR <fgcol>[,<bgcol>]
Action: This command works sets the text mode foreground color, and optionally the background color.
EXAMPLES of COLOR Statement:
COLOR 2 : SET FG COLOR TO RED, KEEP BG COLOR
COLOR 2,0 : SET FG COLOR TO RED, BG COLOR TO BLACK
TYPE: Command FORMAT: DOS <string>
Action: This command works with the command/status channel or the directory of a Commodore DOS device and has different functionality depending on the type of argument.
DOS
prints the status string of the current device."8"
or "9"
, it switches the current device to the given number."$"
, it shows the directory of the device.EXAMPLES of DOS Statement:
DOS"$" : REM SHOWS DIRECTORY
DOS"S:BAD_FILE" : REM DELETES "BAD_FILE"
DOS : REM PRINTS DOS STATUS, E.G. "01,FILES SCRATCHED,01,00"
TYPE: Command FORMAT: FRAME <x1>,<y1>,<x2>,<y2>,<color>
Action: This command draws a rectangle frame on the graphics screen in a given color.
EXAMPLE of FRAME Statement:
10 SCREEN$80
20 FORI=1TO20:FRAMERND(1)*320,RND(1)*200,RND(1)*320,RND(1)*200,RND(1)*128:NEXT
30 GOTO20
TYPE: Command FORMAT: GEOS
Action: Enter the GEOS UI.
TYPE: Integer Function FORMAT: JOY(n)
Action: Return the state a joystick.
JOY(1)
returns the state the first joystick, and JOY(2)
the state of the second joystick. The result is a bit field, with pressed buttons OR
ed together:
Value | NES | SNES | Keyboard |
---|---|---|---|
$80 | A | B | Ctrl |
$40 | B | Y | Alt |
$20 | SELECT | SELECT | Space |
$10 | START | START | Enter |
$08 | UP | UP | Cursor Up |
$04 | DOWN | DOWN | Cursor Down |
$02 | LEFT | LEFT | Cursor Left |
$01 | RIGHT | RIGHT | Cursor Right |
EXAMPLE of JOY Function:
10 J=JOY(1)
20 PRINT CHR$(147);J;": ";
30 IF J AND 8 THEN PRINT"UP ";
40 IF J AND 4 THEN PRINT"DOWN ";
50 IF J AND 2 THEN PRINT"LEFT ";
60 IF J AND 1 THEN PRINT"RIGHT ";
70 GOTO10
TYPE: Command FORMAT: LINE <x1>,<y1>,<x2>,<y2>,<color>
Action: This command draws a line on the graphics screen in a given color.
EXAMPLE of LINE Statement:
10 SCREEN128
20 FORA=0TO2*\XFFSTEP2*\XFF/200
30 LINE100,100,100+SIN(A)*100,100+COS(A)*100
40 NEXT
TYPE: Command FORMAT: MON (Alternative: MONITOR)
Action: This command enters the machine language monitor. See the dedicated chapter for a description.
EXAMPLE of MON Statement:
MON
MONITOR
TYPE: Command FORMAT: MOUSE <mode>
Action: This command configures the mouse pointer.
Mode | Description |
---|---|
0 | Hide mouse |
1 | Show mouse, set default mouse pointer |
$FF | Show mouse, don't configure mouse cursor |
MOUSE 1
turns on the mouse pointer and MOUSE 0
turns it off. If the BASIC program has its own mouse pointer sprite configured, it can use MOUSE $FF
, which will turn the mouse pointer on, but not set the default pointer sprite.
EXAMPLES of MOUSE Statement:
MOUSE 1 : REM ENABLE MOUSE
MOUSE 0 : REM DISABLE MOUSE
TYPE: Integer Function FORMAT: MX FORMAT: MY FORMAT: MB
Action: Return the horizontal (MX
) or vertical (MY
) position of the mouse pointer, or the mouse button state (MB
).
MB
returns the sum of the following values depending on the state of the buttons:
Value | Button |
---|---|
0 | none |
1 | left |
2 | right |
4 | third |
EXAMPLE of MX/MY/MB Functions:
REM SIMPLE DRAWING PROGRAM
10 SCREEN$80
20 MOUSE1
25 OB=0
30 TX=MX:TY=MY:TB=MB
35 IFTB=0GOTO25
40 IFOBTHENLINEOX,OY,TX,TY,16
50 IFOB=0THENPSETTX,TY,16
60 OX=TX:OY=TY:OB=TB
70 GOTO30
TYPE: Command FORMAT: OLD
Action: This command recovers the BASIC program in RAM that has been previously deleted using the NEW
command or through a RESET.
EXAMPLE of OLD Statement:
OLD
TYPE: Command FORMAT: PSET <x>,<y>,<color>
Action: This command sets a pixel on the graphics screen to a given color.
EXAMPLE of PSET Statement:
10 SCREEN$80
20 FORI=1TO20:PSETRND(1)*320,RND(1)*200,RND(1)*256:NEXT
30 GOTO20
TYPE: Command FORMAT: RECT <x1>,<y1>,<x2>,<y2>,<color>
Action: This command draws a solid rectangle on the graphics screen in a given color.
EXAMPLE of RECT Statement:
10 SCREEN$80
20 FORI=1TO20:RECTRND(1)*320,RND(1)*200,RND(1)*320,RND(1)*200,RND(1)*256:NEXT
30 GOTO20
TYPE: Command FORMAT: RESET
Action: Performs a software reset of the system.
EXAMPLE of RESET Statement:
RESET
TYPE: Command FORMAT: SCREEN <mode>
Action: This command switches the screen mode. Modes $80 (128) and above are graphics modes.
Mode | Description | Comment |
---|---|---|
$00 | 40x30 text | |
$01 | 80x30 text | (currently unsupported) |
$02 | 80x60 text | |
$80 | 320x200@256c 40x25 text |
|
$81 | 640x400@16c | (currently unsupported) |
The value of $FF (255) toggles between modes $00 and $02.
Note that in text/graphics mode ($80), text color 0 is now translucent instead of black.
TYPE: Integer Function FORMAT: VPEEK (<bank>, <address>)
Action: Return a byte from the video address space. The video address space has 20 bit addresses, which is exposed as 16 banks of 65536 addresses each.
EXAMPLE of VPEEK Function:
PRINT (VPEEK($F,$2000) AND $E0) / 32 : REM PRINTS THE CURRENT MODE (0-7)
TYPE: Command FORMAT: VPOKE <bank>, <address>, <value>
Action: Set a byte in the video address space. The video address space has 20 bit addresses, which is exposed as 16 banks of 65536 addresses each.
EXAMPLE of VPOKE Statement:
VPOKE 0,1,1 * 16 + 2 : REM SETS THE COLORS OF THE CHARACTER
REM AT 0/0 TO RED ON WHITE
TODO
The numeric constants parser supports both hex ($
) and binary (%
) literals, like this:
PRINT $EA31 + %1010
The size of hex and binary values is only restricted by the range that can be represented by BASIC's internal floating point representation.
In BASIC, both an 80x60 and a 40x30 character text mode is supported. To switch modes, use the BASIC statement SCREEN
:
SCREEN 0 : REM SWITCH TO 40 CHARACTER MODE
SCREEN 2 : REM SWITCH TO 80 CHARACTER MODE
SCREEN 255 : REM SWITCH BETWEEN 40 and 80 CHARACTER MODE
In BASIC, the contents of files can be directly loaded into VRAM with the LOAD
statement. When a secondary address greater than one is used, the KERNAL will now load the file into the VERA's VRAM address space. The first two bytes of the file are used as lower 16 bits of the address. The upper 4 bits are (SA-2) & 0x0ff
where SA
is the secondary address.
Examples:
10 REM LOAD VERA SETTINGS
20 LOAD"VERA.BIN",1,17 : REM SET ADDRESS TO $FXXXX
30 REM LOAD TILES
40 LOAD"TILES.BIN",1,3 : REM SET ADDRESS TO $1XXXX
50 REM LOAD MAP
60 LOAD"MAP.BIN",1,2 : REM SET ADDRESS TO $0XXXX
In BASIC, the LOAD, SAVE and OPEN statements default to the last-used IEEE device (device numbers 8 and above), or 8.
Like on the C64, BASIC keywords are tokenized.
END
) to $CB (GO
).RGR
) to $FD (WHILE
).POT
) to $CE-$0A (POINTER
), and the $FE escape code for statement tokens $FE-$02 (BANK
) to $FE-$38 (SLOW
).RPALETTE
) and $FE-$45 (EDIT
).The X16 BASIC aims to be as compatible as possible with this encoding. Keywords added to X16 BASIC that also exist in other versions of BASIC match the token, and new keywords are encoded in the ranges $CE-$80+ and $FE-$80+.
The Commander X16 contains a version of KERNAL as its operating system in ROM. It contains
The KERNAL version can be read from location $FF80 in ROM. A value of $FF indicates a custom build. All other values encode the build number. Positive numbers are release versions ($02 = release version 2), two's complement negative numbers are prerelease versions ($FE = $100 - 2 = prerelease version 2).
For applications to remain compatible between different versions of the ROM, they can rely upon:
The following features must not be relied upon:
The KERNAL fully supports the C64 KERNAL API.
Channel I/O: $FF90: SETMSG
– set verbosity $FFB7: READST
– return status byte $FFBA: SETLFS
– set LA, FA and SA $FFBD: SETNAM
– set filename $FFC0: OPEN
– open a channel $FFC3: CLOSE
– close a channel $FFC6: CHKIN
– set channel for character input $FFC9: CHKOUT
– set channel for character output $FFCC: CLRCHN
– restore character I/O to screen/keyboard $FFCF: BASIN
– get character $FFD2: BSOUT
– write character $FFD5: LOAD
– load a file into memory $FFD8: SAVE
– save a file from memory $FFE7: CLALL
– close all channels
Commodore Peripheral Bus: $FFB4: TALK
– send TALK command $FFB1: LISTEN
– send LISTEN command $FFAE: UNLSN
– send UNLISTEN command $FFAB: UNTLK
– send UNTALK command $FFA8: IECOUT
– send byte to serial bus $FFA5: IECIN
– read byte from serial bus $FFA2: SETTMO
– set timeout $FF96: TKSA
– send TALK secondary address $FF93: SECOND
– send LISTEN secondary address
Memory: $FF9C: MEMBOT
– read/write address of start of usable RAM $FF99: MEMTOP
– read/write address of end of usable RAM
Time: $FFDE: RDTIM
– read system clock $FFDB: SETTIM
– write system clock $FFEA: UDTIM
– advance clock
Other: $FFE1: STOP
– test for STOP key $FFE4: GETIN
– get character from keyboard $FFED: SCREEN
– get the screen resolution $FFF0: PLOT
– read/write cursor position $FFF3: IOBASE
– return start of I/O area
Some notes:
IOBASE
call returns $9F60, the location of the first VIA controller.SETTMO
call has been a no-op since the Commodore VIC-20, and has no function on the X16 either.MEMTOP
call additionally returns the number of available RAM banks in the .A register.In addition, the X16 supports a subset of the C128 API additions:
$FF4A: CLOSE_ALL
– close all files on a device $FF8D: LKUPLA
– search tables for given LA $FF8A: LKUPSA
– search tables for given SA $FF62: DLCHR
- activate a text mode font in the video hardware [not yet implemented] $FF65: PFKEY
– program a function key [not yet implemented] $FF74: FETCH
– LDA (fetvec),Y from any bank $FF77: STASH
– STA (stavec),Y to any bank $FF7A: CMPARE
– CMP (cmpvec),Y to any bank $FF7D: PRIMM
– print string following the caller’s code
Some notes:
FETCH
, STASH
and CMPARE
require the caller to set the zero page location containing the address in memory beforehand. These are different than on the C128:Call | Label | Address |
---|---|---|
FETCH |
FETVEC |
$03AF |
STASH |
STAVEC |
$XXXX |
CMPARE |
CMPVEC |
$XXXX |
[Note: STASH
and CMPARE
are currently non-functional.]
There are lots of new APIs. Please note that their addresses and their behavior is still prelimiary and can change between revisions.
Some new APIs use the "16 bit" ABI, which uses virtual 16 bit registers r0 through r15, which are located in zero page locations $02 through $21: r0 = r0L = $02, r0H = $03, r1 = r1L = $04 etc. (The registers start at $02 instead of $00 to allow compatibility with 65xx systems that have a processor port at $00/$01.)
The 16 bit ABI generally follows the following conventions:
$FF4D: clock_set_date_time
- set date and time $FF50: clock_get_date_time
- get date and time
Purpose: Set the date and time Call address: $FF4D Communication registers: r0, r1, r2, r3L Preparatory routines: None Error returns: None Stack requirements: 0 Registers affected: .A, .X, .Y
Description: The routine clock_set_date_time
sets the system's real-time-clock.
Register | Contents |
---|---|
r0L | year (1900-based) |
r0H | month (1-12) |
r1L | day (1-31) |
r1H | hours (0-23) |
r2L | minutes (0-59) |
r2H | seconds (0-59) |
r3L | jiffies (0-59) |
Jiffies are 1/60th seconds.
Purpose: Get the date and time Call address: $FF50 Communication registers: r0, r1, r2, r3L Preparatory routines: None Error returns: None Stack requirements: 0 Registers affected: .A, .X, .Y
Description: The routine clock_get_date_time
returns the state of the system's real-time-clock. The register assignment is identical to clock_set_date_time
.
On the Commander X16, the jiffies field is unsupported and will always read back as 0.
$FF68: mouse_config
- configure mouse pointer $FF71: mouse_scan
- query mouse $FF6B: mouse_get
- get state of mouse
Purpose: Configure the mouse pointer Call address: $FF68 Communication registers: .A, .X Preparatory routines: None Error returns: None Stack requirements: 0 Registers affected: .A, .X, .Y
Description: The routine mouse_config
configures the mouse pointer.
The argument in .A specifies whether the mouse pointer should be visible or not, and what shape it should have. For a list of possible values, see the basic statement MOUSE
.
The argument in .X specifies the scale. Use a scale of 1 for a 640x480 screen, and a scale of 2 for a 320x240 screen. A value of 0 does not change the scale.
EXAMPLE:
LDA #1
JSR mouse_config ; show the default mouse pointer
Purpose: Query the mouse and save its state Call address: $FF71 Communication registers: None Preparatory routines: None Error returns: None Stack requirements: ? Registers affected: .A, .X, .Y
Description: The routine mouse_scan
retrieves all state from the mouse and saves it. It can then be retrieved using mouse_get
. The default interrupt handler already takes care of this, so this routine should only be called if the interrupt handler has been completely replaced.
Purpose: Get the mouse state Call address: $FF6B Communication registers: .X Preparatory routines: mouse_config
Error returns: None Stack requirements: 0 Registers affected: .A
Description: The routine mouse_get
returns the state of the mouse. The caller passes the offset of a zero-page location in .X, which the routine will populate with the mouse position in 4 consecutive bytes:
Offset | Size | Description |
---|---|---|
0 | 2 | X Position |
2 | 2 | Y Position |
The state of the mouse buttons is returned in the .A register:
Bit | Description |
---|---|
0 | Left Button |
1 | Right Button |
2 | Middle Button |
If a button is pressed, the corresponding bit is set.
EXAMPLE:
LDX #$70
JSR mouse_get ; get mouse position in $70/$71 (X) and $72/$73 (Y)
AND #1
BNE BUTTON_PRESSED
$FF53: joystick_scan
- query joysticks $FF56: joystick_get
- get state of one joystick
Purpose: Query the joysticks and save their state Call address: $FF53 Communication registers: None Preparatory routines: None Error returns: None Stack requirements: 0 Registers affected: .A, .X, .Y
Description: The routine joystick_scan
retrieves all state from the two joysticks and saves it. It can then be retrieved using joystick_get
. The default interrupt handler already takes care of this, so this routine should only be called if the interrupt handler has been completely replaced.
Purpose: Get the state of one of the joysticks Call address: $FF56 Communication registers: .A Preparatory routines: joystick_scan
Error returns: None Stack requirements: 0 Registers affected: .A, .X, .Y
Description: The routine joystick_get
retrieves all state from one of the joysticks. The number of the joystick is passed in .A (0 or 1), and the state is returned in .A, .X and .Y.
.A, byte 0: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
NES | A | B |SEL|STA|UP |DN |LT |RT |
SNES | B | Y |SEL|STA|UP |DN |LT |RT |
.X, byte 1: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
NES | 0 | 0 | 0 | 0 | 0 | 0 | 0 | X |
SNES | A | X | L | R | 1 | 1 | 1 | 1 |
.Y, byte 2:
$00 = joystick present
$FF = joystick not present
If joystick 1 is not present, it will fall back to returning the state of the keyboard, if present:
Keyboard Key | NES Equivalent |
---|---|
Ctrl | A |
Alt | B |
Space | SELECT |
Enter | START |
Cursor Up | UP |
Cursor Down | DOWN |
Cursor Left | LEFT |
Cursor Right | RIGHT |
Value | Type |
---|---|
0000 | NES |
0001 | keyboard (NES-like) |
1111 | SNES |
How to Use:
If the default interrupt handler is used:
If the default interrupt handler is disabled or replaced:
joystick_scan
to have the system query the joysticks.EXAMPLE:
JSR joystick_scan
LDA #0
JSR joystick_get
AND #128
BEQ NES_A_PRESSED
$FEF0: sprite_set_image
- set the image of a sprite $FEF3: sprite_set_position
- set the position of a sprite
Purpose: Set the image of a sprite Call address: $FEF0 Signature: bool sprite_set_image(byte number: .a, width: .x, height: .y, apply_mask: .c, word pixels: r0, word mask: r1, byte bpp: r2L); Error returns: .C = 1 in case of error
Description: This function sets the image of a sprite. The number of the sprite is given in .A, The bits per pixel (bpp) in r2L, and the width and height in .X and .Y. The pixel data at r0 is interpreted accordingly and converted into the graphics hardware's native format. If the .C flag is set, the transparency mask pointed to by r1 is applied during the conversion. The function returns .C = 0 if converting the data was successful, and .C = 1 otherwise. Note that this does not change the visibility of the sprite.
Note: There are certain limitations on the possible values of width, height, bpp and apply_mask:
Purpose: Set the position of a sprite or hide it. Call address: $FEF3 Signature: void sprite_set_position(byte number: .a, word x: r0, word y: r1); Error returns: None
Description: This function shows a given sprite (.A) at a certain position or hides it. The position is passed in r0 and r1. If the x position is negative (>$8000), the sprite will be hidden.
The framebuffer API is a low-level graphics API that completely abstracts the framebuffer by exposing a minimal set of high-performance functions. It is useful as an abstraction and as a convenience library for applications that need high performance framebuffer access.
$FEF6: FB_init
- enable graphics mode $FEF9: FB_get_info
- get screen size and color depth $FEFC: FB_set_palette
- set (parts of) the palette $FEFF: FB_cursor_position
- position the direct-access cursor $FF02: FB_cursor_next_line
- move direct-access cursor to next line $FF05: FB_get_pixel
- read one pixel, update cursor $FF08: FB_get_pixels
- copy pixels into RAM, update cursor $FF0B: FB_set_pixel
- set one pixel, update cursor $FF0E: FB_set_pixels
- copy pixels from RAM, update cursor $FF11: FB_set_8_pixels
- set 8 pixels from bit mask (transparent), update cursor $FF14: FB_set_8_pixels_opaque
- set 8 pixels from bit mask (opaque), update cursor $FF17: FB_fill_pixels
- fill pixels with constant color, update cursor $FF1A: FB_filter_pixels
- apply transform to pixels, update cursor $FF1D: FB_move_pixels
- copy horizontally consecutive pixels to a different position
All calls are vectored, which allows installing a replacement framebuffer driver.
$02E4: I_FB_init $02E6: I_FB_get_info $02E8: I_FB_set_palette $02EA: I_FB_cursor_position $02EC: I_FB_cursor_next_line $02EE: I_FB_get_pixel $02F0: I_FB_get_pixels $02F2: I_FB_set_pixel $02F4: I_FB_set_pixels $02F6: I_FB_set_8_pixels $02F8: I_FB_set_8_pixels_opaque $02FA: I_FB_fill_pixels $02FC: I_FB_filter_pixels $02FE: I_FB_move_pixels
The model of this API is based on the direct-access cursor. In order to read and write pixels, the cursor has to be set to a specific x/y-location, and all subsequent calls will access consecutive pixels at the cursor position and update the cursor.
The default driver supports the VERA framebuffer at a resolution of 320x200 pixels and 256 colors. Using screen_set_mode
to set mode $80 will enable this driver.
Signature: void FB_init(); Purpose: Enter graphics mode.
Signature: void FB_get_info(out word width: r0, out word height: r1, out byte color_depth: .a); Purpose: Return the resolution and color depth
Signature: void FB_set_palette(word pointer: r0, index: .a, byte count: .x); Purpose: Set (parts of) the palette
[Note: This is not yet implemented.]
Signature: void FB_cursor_position(word x: r0, word y: r1); Purpose: Position the direct-access cursor
Description: FB_cursor_position
sets the direct-access cursor to the given screen coordinate. Future operations will access pixels at the cursor location and update the cursor.
Signature: void FB_cursor_next_line(word x: r0); Purpose: Move the direct-access cursor to next line
Description: FB_cursor_next_line
increments the y position of the direct-access cursor, and sets the x position to the same one that was passed to the previous FB_cursor_position
call. This is useful for drawing rectangular shapes, and faster than explicitly positioning the cursor.
Signature: byte FB_get_pixel(); Purpose: Read one pixel, update cursor
Signature: void FB_get_pixels(word ptr: r0, word count: r1); Purpose: Copy pixels into RAM, update cursor
Description: This function copies pixels into an array in RAM. The array consists of one byte per pixel.
Signature: void FB_set_pixel(byte color: .a); Purpose: Set one pixel, update cursor
Signature: void FB_set_pixels(word ptr: r0, word count: r1); Purpose: Copy pixels from RAM, update cursor
Description: This function sets pixels from an array of pixels in RAM. The array consists of one byte per pixel.
Signature: void FB_set_8_pixels(byte pattern: .a, byte color: .x); Purpose: Set 8 pixels from bit mask (transparent), update cursor
Description: This function sets all 1-bits of the pattern to a given color and skips a pixel for every 0 bit. The order is MSB to LSB. The cursor will be moved by 8 pixels.
Signature: void FB_set_8_pixels_opaque(byte pattern: .a, byte mask: r0L, byte color1: .x, byte color2: .y); Purpose: Set 8 pixels from bit mask (opaque), update cursor
Description: For every 1-bit in the mask, this function sets the pixel to color1 if the corresponding bit in the pattern is 1, and to color2 otherwise. For every 0-bit in the mask, it skips a pixel. The order is MSB to LSB. The cursor will be moved by 8 pixels.
Signature: void FB_fill_pixels(word count: r0, word step: r1, byte color: .a); Purpose: Fill pixels with constant color, update cursor
Description: FB_fill_pixels
sets pixels with a constant color. The argument step
specifies the increment between pixels. A value of 0 or 1 will cause consecutive pixels to be set. Passing a step
value of the screen width will set vertically adjacent pixels going top down. Smaller values allow drawing dotted horizontal lines, and multiples of the screen width allow drawing dotted vertical lines.
[Note: Only the values 0/1 and screen width are currently supported.]
Signature: void FB_filter_pixels(word ptr: r0, word count: r1); Purpose: Apply transform to pixels, update cursor
Description: This function allows modifying consecutive pixels. The function pointer will be called for every pixel, with the color in .a, and it needs to return the new color in .a.
Signature: void FB_move_pixels(word sx: r0, word sy: r1, word tx: r2, word ty: r3, word count: r4); Purpose: Copy horizontally consecutive pixels to a different position
[Note: Overlapping regions are not yet supported.]
The high-level graphics API exposes a set of standard functions. It allows applications to easily perform some common high-level actions like drawing lines, rectangles and images, as well as moving parts of the screen. All commands are completely implemented on top of the framebuffer API, that is, they will continue working after replacing the framebuffer driver with one that supports a different resolution, color depth or even graphics device.
$FF20: GRAPH_init
- initialize graphics $FF23: GRAPH_clear
- clear screen $FF26: GRAPH_set_window
- set clipping region $FF29: GRAPH_set_colors
- set stroke, fill and background colors $FF2C: GRAPH_draw_line
- draw a line $FF2F: GRAPH_draw_rect
- draw a rectangle (optionally filled) $FF32: GRAPH_move_rect
- move pixels $FF35: GRAPH_draw_oval
- draw an oval or circle $FF38: GRAPH_draw_image
- draw a rectangular image $FF3B: GRAPH_set_font
- set the current font $FF3E: GRAPH_get_char_size
- get size and baseline of a character $FF41: GRAPH_put_char
- print a character
Signature: void GRAPH_init(word vectors: r0); Purpose: Activate framebuffer driver, enter and initialize graphics mode
Description: This call activates the framebuffer driver whose vector table is passed in r0. If r0 is 0, the default driver is activated. It then switches the video hardware into graphics mode, sets the window to full screen, initializes the colors and activates the system font.
Signature: void GRAPH_clear(); Purpose: Clear the current window with the current background color.
Signature: void GRAPH_set_window(word x: r0, word y: r1, word width: r2, word height: r3); Purpose: Set the clipping region
Description: All graphics commands are clipped to the window. This function configures the origin and size of the window. All 0 arguments set the window to full screen.
[Note: Only text output and GRAPH_clear currently respect the clipping region.]
Signature: void GRAPH_set_colors(byte stroke: .a, byte fill: .x, byte background: .y); Purpose: Set the three colors
Description: This function sets the three colors: The stroke color, the fill color and the background color.
Signature: void GRAPH_draw_line(word x1: r0, word y1: r1, word x2: r2, word y2: r3); Purpose: Draw a line using the stroke color
Signature: void GRAPH_draw_rect(word x: r0, word y: r1, word width: r2, word height: r3, word corner_radius: r4, bool fill: .c); Purpose: Draw a rectangle.
Description: This function will draw the frame of a rectangle using the stroke color. If fill
is true
, it will also fill the area using the fill color. To only fill a rectangle, set the stroke color to the same value as the fill color.
[Note: The border radius is currently unimplemented.]
Signature: void GRAPH_move_rect(word sx: r0, word sy: r1, word tx: r2, word ty: r3, word width: r4, word height: r5); Purpose: Copy a rectangular screen area to a different location
Description: GRAPH_move_rect
coll copy a rectangular area of the screen to a different location. The two areas may overlap.
[Note: Support for overlapping is not currently implemented.]
Signature: void GRAPH_draw_oval(word x: r0, word y: r1, word width: r2, word height: r3, bool fill: .c); Purpose: Draw an oval or a circle
Description: This function draws an oval filling the given bounding box. If width equals height, the resulting shape is a circle. The oval will be outlined by the stroke color. If fill
is true
, it will be filled using the fill color. To only fill an oval, set the stroke color to the same value as the fill color.
Signature: void GRAPH_draw_image(word x: r0, word y: r1, word ptr: r2, word width: r3, word height: r4); Purpose: Draw a rectangular image from data in memory
Description: This function copies pixel data from memory onto the screen. The representation of the data in memory has to have one byte per pixel, with the pixels organized line by line top to bottom, and within the line left to right.
Signature: void GRAPH_set_font(void ptr: r0); Purpose: Set the current font
Description: This function sets the current font to be used for the remaining font-related functions. The argument is a pointer to the font data structure in memory, which must be in the format of a single point size GEOS font (i.e. one GEOS font file VLIR chunk). An argument of 0 will activate the built-in system font.
Signature: (byte baseline: .a, byte width: .x, byte height_or_style: .y, bool is_control: .c) GRAPH_get_char_size(byte c: .a, byte format: .x); Purpose: Get the size and baseline of a character, or interpret a control code
Description: This functionality of GRAPH_get_char_size
depends on the type of code that is passed in: For a printable character, this function returns the metrics of the character in a given format. For a control code, it returns the resulting format. In either case, the current format is passed in .x, and the character in .a.
0
, which is plain text.Signature: void GRAPH_put_char(inout word x: r0, inout word y: r1, byte c: .a); Purpose: Print a character onto the graphics screen
Description: This function prints a single character at a given location on the graphics screen. The location is then updated. The following control codes are supported:
Notes:
$FEDB: console_init
- initialize console mode $FEDE: console_put_char
- print character to console $FED8: console_put_image
- draw image as if it was a character $FEE1: console_get_char
- get character from console $FED5: console_set_paging_message
- set paging message or disable paging
The console is a screen mode that allows text output and input in proportional fonts that support the usual styles. It is useful for rich text-based interfaces.
Signature: void console_init(word x: r0, word y: r1, word width: r2, word height: r3); Purpose: Initialize console mode. Call address: $FEDB
Description: This function initializes console mode. It sets up the window (text clipping area) passed into it, clears the window and positions the cursor at the top left. All 0 arguments create a full screen console. You have to switch to graphics mode using screen_set_mode
beforehand.
Signature: void console_put_char(byte char: .a, bool wrapping: .c); Purpose: Print a character to the console. Call address: $FEDE
Description: This function prints a character to the console. The .C flag specifies whether text should be wrapped at character (.C=0) or word (.C=1) boundaries. In the latter case, characters will be buffered until a SPACE, CR or LF character is sent, so make sure the text that is printed always ends in one of these characters.
Note: If the bottom of the screen is reached, this function will scroll its contents up to make extra room.
Signature: void console_put_image(word ptr: r0, word width: r1, word height: r2); Purpose: Draw image as if it was a character. Call address: $FEE1
Description: This function draws an image (in GRAPH_draw_image format) at the current cursor position and advances the cursor accordingly. This way, an image can be presented inline. A common example would be an emoji bitmap, but it is also possible to show full-width pictures if you print a newline before and after the image.
Notes:
Signature: (byte char: .a) console_get_char(); Purpose: Get a character from the console. Call address: $FEE1
Description: This function gets a character to the console. It does this by collecting a whole line of character, i.e. until the user presses RETURN. Then, the line will be sent character by character.
This function allows editing the line using BACKSPACE/DEL, but does not allow moving the cursor within the line, write more than one line, or using control codes.
Signature: void console_set_paging_message(word message: r0); Purpose: Set the paging message or disable paging. Call address: $FED5
Description: The console can halt printing after a full screen height worth of text has been printed. It will then show a message, wait for any key, and continue printing. This function sets this message. A zero-terminated text is passed in r0. To turn off paging, call this function with r0 = 0 - this is the default.
Note: It is possible to use control codes to change the text style and color. Do not use codes that change the cursor position, like CR or LF. Also, the text must not overflow one line on the screen.
$FEE4: memory_fill
- fill memory region with a byte value $FEE7: memory_copy
- copy memory region $FEEA: memory_crc
- calculate CRC16 of memory region $FEED: memory_decompress
- decompress LZSA2 block $FECF: entropy_get
- get 24 random bits $FF44: monitor
- enter machine language monitor $FF47: enter_basic
- enter BASIC $FF5F: screen_set_mode
- set screen mode $FF62: screen_set_charset
- activate 8x8 text mode charset
Signature: void memory_fill(word address: r0, word num_bytes: r1, byte value: .a); Purpose: Fill a memory region with a byte value. Call address: $FEE4
Description: This function fills the memory region specified by an address (r0) and a size in bytes (r1) with the constant byte value passed in .A.
Signature: void memory_copy(word source: r0, word target: r1, word num_bytes: r2); Purpose: Copy a memory region to a different region. Call address: $FEE7
Description: This function copies one memory region specified by an address (r0) and a size in bytes (r2) to a different region specified by its start address (r1). The two regions may overlap.
Signature: (word result: r2) memory_crc(word address: r0, word num_bytes: r1); Purpose: Calculate the CRC16 of a memory region. Call address: $FEEA
Description: This function calculates the CRC16 checksum of the memory region specified by an address (r0) and a size in bytes (r1). The result is returned in r2.
Signature: void memory_decompress(word input: r0, inout word output: r1); Purpose: Decompress an LZSA2 block Call address: $FEED
Description: This function decompresses an LZSA2-compressed data block from the location passed in r0 and outputs the decompressed data at the location passed in r1. After the call, r1 will be updated with the location of the last output byte plus one.
Notes:
lzsa
tool^4 like this: lzsa -r -f2 <original_file> <compressed_file>
Purpose: Get 24 random bits Call address: $FECF Communication registers: .A, .X, .Y Preparatory routines: None Error returns: None Registers affected: .A, .X, .Y
Description: This routine returns 24 somewhat random bits in registers .A, .X, and .Y. In order to get higher-quality random numbers, this data should be fed into a pseudo-random number generator.
How to Use:
EXAMPLE:
; throw a dice
again:
JSR entropy_get
STX tmp ; combine 24 bits
EOR tmp ; using exclusive-or
STY tmp ; to get a higher-quality
EOR tmp ; 8 bit random value
STA tmp
LSR
LSR
LSR
LSR ; combine resulting 8 bits
EOR tmp ; to get 4 bits
AND #7 ; we're down to values 0-7
CMP #0
BEQ again ; 0 is illegal
CMP #7
BEQ again ; 7 is illegal
ORA #$30 ; convert to ASCII
JMP $FFD2 ; print character
Purpose: Enter the machine language monitor Call address: $FF44 Communication registers: None Preparatory routines: None Error returns: Does not return Stack requirements: Does not return Registers affected: Does not return
Description: This routine switches from BASIC to machine language monitor mode. It does not return to the caller. When the user quits the monitor, it will restart BASIC.
How to Use:
EXAMPLE:
JMP monitor
Purpose: Enter BASIC Call address: $FF47 Communication registers: .C Preparatory routines: None Error returns: Does not return
Description: Call this to enter BASIC mode, either through a cold start (.C=1) or a warm start (.C=0).
EXAMPLE:
CLC
JMP enter_basic ; returns to the "READY." prompt
Purpose: Set the screen mode Call address: $FF5F Communication registers: .A Preparatory routines: None Error returns: .C = 1 in case of error Stack requirements: [?] Registers affected: .A, .X, .Y
Description: A call to this routine sets the current screen mode to the value in .A. For a list of possible values, see the basic statement SCREEN
.
EXAMPLE:
LDA #$80
JSR screen_set_mode ; SET 320x200@256C MODE
BCS FAILURE
Purpose: Activate a 8x8 text mode charset Call address: $FF62
Communication registers: .A, .X, .Y Preparatory routines: None Stack requirements: [?] Registers affected: .A, .X, .Y
Description: A call to this routine uploads a character set to the video hardware and activates it. The value of .A decides what charset to upload:
Value | Description |
---|---|
0 | use pointer in .X/.Y |
1 | ISO |
2 | PET upper/graph |
3 | PET upper/lower |
If .A is zero, .X (lo) and .Y (hi) contain a pointer to a 2 KB RAM area that gets uploaded as the new 8x8 character set. The data has to consist of 256 characters of 8 bytes each, top to bottom, with the MSB on the left and set bits representing the foreground color.
EXAMPLE:
LDA #0
LDX #<MY_CHARSET
LDY #>MY_CHARSET
JSR screen_set_charset ; UPLOAD CUSTOM CHARSET "MY_CHARSET"
Purpose: Execute a routine on another RAM or ROM bank Call address: $FF6E Communication registers: None Preparatory routines: None Error returns: None Stack requirements: 4 Registers affected: None
Description: The routine JSRFAR
enables code to execute some other code located on a specific RAM or ROM bank. This works independently of which RAM or ROM bank the currently executing code is residing in. The 16 bit address and the 8 bit bank number have to follow the instruction stream. The JSRFAR
routine will switch both the ROM and the RAM bank to the specified bank and restore it after the routine's RTS
. Execution resumes after the 3 byte arguments. Note: The C128 also has a JSRFAR
function at $FF6E, but it is incompatible with the X16 version.
How to Use:
EXAMPLE:
JSR JSRFAR
.WORD $C000 ; ADDRESS
.BYTE 1 ; BANK
The built-in machine language monitor can be started with the MON
BASIC command. It is based on the monitor of the Final Cartridge III and supports all its features. See the Final Cartridge III Manual more more information.
If you invoke the monitor by mistake, you can exit with by typing X
, followed by the RETURN
key.
Some features specific to this monitor are:
I
command prints a CBM-ASCII-encoded memory dump.EC
command prints a binary memory dump. This is also useful for character sets.The following additions have been made:
The instruction set extensions of the 65C02 are supported.
The O
command takes an 8 bit hex value as an argument and sets it as the ROM and RAM bank for reading and writing memory contents. The following example disassembles the beginning of the CBDOS ROM on bank 5:
O05
DC000 C015
The OV
command takes a 4 bit hex value as an argument and sets it as the bank in the video address space for reading and writing memory contents. The following example shows the character ROM in the video controller's address space:
OV1
ECF000 F00F
[TODO: Full documentation]
The Commander X16 has 64 KB of ROM and 2,088 KB (2 MB[^1] + 40 KB) of RAM. Some of the ROM and RAM is always visible at certain address ranges, while the remaining ROM and RAM is banked into one of two address windows.
This is an overview of the X16 memory map:
Addresses | Description |
---|---|
$0000-$9EFF | Fixed RAM (40 KB minus 256 bytes) |
$9F00-$9FFF | I/O Area (256 bytes) |
$A000-$BFFF | Banked RAM (8 KB window into one of 256 banks for a total of 2 MB) |
$C000-$FFFF | Banked ROM (16 KB window into one of 8 banks for a total of 128 KB) |
The RAM bank (0-255) defaults to 0, and the ROM bank (0-7) defaults to 0 on RESET. The RAM bank can be configured through VIA#1 PA0-7 ($9F61), and the ROM bank through VIA#1 PB0-2 ($9F60). See section "I/O Programming" for more information.
This is the allocation of the banks of banked ROM:
Bank | Name | Description |
---|---|---|
0 | KERNAL | character sets (uploaded into VRAM), MONITOR, KERNAL |
1 | KEYBD | Keyboard layout tables |
2 | CBDOS | The computer-based CBM-DOS for FAT32 SD cards |
3 | GEOS | GEOS KERNAL |
4 | BASIC | BASIC interpreter |
5 | MONITOR | Machine Language Monitor |
6-7 | – | [Currently unused] |
Important: The layout of the banks is still constantly changing.
This is the allocation of fixed RAM in the KERNAL/BASIC environment.
Addresses | Description |
---|---|
$0000-$007F | User zero page |
$0080-$00FF | KERNAL and BASIC zero page variables |
$0100-$01FF | CPU stack |
$0200-$03FF | KERNAL and BASIC variables, vectors |
$0400-$07FF | Available for machine code programs or custom data storage |
$0800-$9EFF | BASIC program/variables; available to the user |
The following zero page locations are completely unused by KERNAL/BASIC/FPLIB and are available to the user:
Addresses |
---|
$0000-$007F |
In a machine language application that only uses KERNAL (no BASIC or floating point), the following zero page locations are also available:
Addresses |
---|
$00A9-$00FF |
This is the allocation of banked RAM in the KERNAL/BASIC environment.
Bank | Description |
---|---|
0 | Used for KERNAL/CBDOS variables and buffers |
1-255 | Available to the user |
(On systems with only 512 KB RAM, banks 64-255 are unavailable.)
During startup, the KERNAL activates RAM bank 1 as the default for the user.
This is the memory map of the I/O Area:
Addresses | Description |
---|---|
$9F00-$9F1F | Reserved for audio controller |
$9F20-$9F3F | VERA video controller |
$9F40-$9F5F | Reserved |
$9F60-$9F6F | VIA I/O controller #1 |
$9F70-$9F7F | VIA I/O controller #2 |
$9F80-$9F9F | Real time clock |
$9FA0-$9FBF | Future Expansion |
$9FC0-$9FDF | Future Expansion |
$9FE0-$9FFF | Future Expansion |
The VERA video chip supports resolutions up to 640x480 with up to 256 colors from a palette of 4096, two layers of either a bitmap or tiles, 128 sprites of up to 64x64 pixels in size. It can output VGA as well as a 525 line interlaced signal, either as NTSC or as RGB (Amiga-style).
See the VERA Programmer's Reference for the complete reference.
IMPORTANT: The VERA register layout has changed between 0.7 and 0.8. Here is the old documentation: vera-module v0.7.pdf
The KERNAL uploads the current character sets (PETSCII graphics, PETSCII upper/lower or ISO-8859-15) to $0F800, i.e. the top of video RAM bank 0.
Application software is free to reuse this part of video RAM if it does not need the character set. If it needs them again later, it can use the KERNAL call CINT
($FF81), which initializes the VERA chip and uploads the PETSCII graphics character set, or call screen_set_charset
($FF62) to upload a particular charset.
[TODO]
There are two 65C22 "Versatile Interface Adapter" (VIA) I/O controllers in the system, VIA#1 at address $9F60 and VIA#2 at address $9F70. The IRQ out lines of both VIAs are connected to the IRQ in line of the CPU.
The following tables describe the connections of the GPIO ports:
VIA#1
Pin | Description |
---|---|
PA0-7 | RAM bank |
PB0-2 | ROM bank |
PB3-7 | [TBD] |
VIA#2
Pin | Description |
---|---|
PA0 | KBD PS/2 DAT |
PA1 | KBD PS/2 CLK |
PA2 | TBD |
PA3 | JOY1/2 LATCH[^3] |
PA4 | JOY1 DATA |
PA5 | JOY1/2 CLK |
PA6 | JOY2 DATA |
PA7 | [TBD] |
PB0 | MOUSE PS/2 DAT |
PB1 | MOUSE PS/2 CLK |
PB2-7 | [TBD] |
The GPIO connections for the Commodore Serial Bus and the mouse PS/2 connection have not been finalized.
[^1]: Current development systems have 2 MB of bankable RAM. Actual hardware is currently planned to have an option of either 512 KB or 2 MB of RAM.
[^3]: The pin assignment of the NES/SNES controller is likely to change.