From 18afc7c7038280e2443c64e31cf2f0092a484004 Mon Sep 17 00:00:00 2001
From: Greg King <gregdk@users.sf.net>
Date: Fri, 27 Sep 2019 03:38:51 -0400
Subject: [PATCH 039/170] Created a target and a library for the Commander X16
prototype computer.
---
asminc/cbm_kernal.inc | 36 ++--
asminc/cx16.inc | 316 ++++++++++++++++++++++++++++++++++
cfg/cx16-asm.cfg | 37 ++++
cfg/cx16-bank.cfg | 112 ++++++++++++
cfg/cx16.cfg | 45 +++++
doc/ca65.sgml | 3 +-
doc/cc65.sgml | 4 +
doc/cx16.sgml | 311 +++++++++++++++++++++++++++++++++
doc/index.sgml | 3 +
doc/intro.sgml | 27 ++-
include/cbm.h | 4 +-
include/cx16.h | 189 ++++++++++++++++++++
libsrc/Makefile | 1 +
libsrc/cx16/_scrsize.s | 14 ++
libsrc/cx16/bankramaddr.s | 50 ++++++
libsrc/cx16/bordercolor.s | 27 +++
libsrc/cx16/break.s | 109 ++++++++++++
libsrc/cx16/cgetc.s | 72 ++++++++
libsrc/cx16/clrscr.s | 26 +++
libsrc/cx16/color.s | 43 +++++
libsrc/cx16/conio.s | 9 +
libsrc/cx16/cpeekc.s | 48 ++++++
libsrc/cx16/cpeekcolor.s | 27 +++
libsrc/cx16/cpeekrevers.s | 32 ++++
libsrc/cx16/cpeeks.s | 0
libsrc/cx16/cputc.s | 98 +++++++++++
libsrc/cx16/crt0.s | 115 +++++++++++++
libsrc/cx16/devnum.s | 8 +
libsrc/cx16/get_ostype.s | 20 +++
libsrc/cx16/get_tv.s | 31 ++++
libsrc/cx16/irq.s | 48 ++++++
libsrc/cx16/joy/cx16-stdjoy.s | 119 +++++++++++++
libsrc/cx16/joy_stat_stddrv.s | 10 ++
libsrc/cx16/joy_stddrv.s | 13 ++
libsrc/cx16/kbhit.s | 17 ++
libsrc/cx16/kernal.s | 59 +++++++
libsrc/cx16/libref.s | 18 ++
libsrc/cx16/mainargs.s | 137 +++++++++++++++
libsrc/cx16/revers.s | 23 +++
libsrc/cx16/set_tv.s | 32 ++++
libsrc/cx16/status.s | 6 +
libsrc/cx16/sysuname.s | 37 ++++
libsrc/cx16/videomode.s | 30 ++++
libsrc/cx16/waitvsync.s | 17 ++
src/ca65/main.c | 6 +-
src/cc65/main.c | 4 +
src/common/target.c | 16 +-
src/common/target.h | 4 +-
testcode/lib/joy-test.c | 86 +++++----
49 files changed, 2440 insertions(+), 59 deletions(-)
create mode 100644 asminc/cx16.inc
create mode 100644 cfg/cx16-asm.cfg
create mode 100644 cfg/cx16-bank.cfg
create mode 100644 cfg/cx16.cfg
create mode 100644 doc/cx16.sgml
create mode 100644 include/cx16.h
create mode 100644 libsrc/cx16/_scrsize.s
create mode 100644 libsrc/cx16/bankramaddr.s
create mode 100644 libsrc/cx16/bordercolor.s
create mode 100644 libsrc/cx16/break.s
create mode 100644 libsrc/cx16/cgetc.s
create mode 100644 libsrc/cx16/clrscr.s
create mode 100644 libsrc/cx16/color.s
create mode 100644 libsrc/cx16/conio.s
create mode 100644 libsrc/cx16/cpeekc.s
create mode 100644 libsrc/cx16/cpeekcolor.s
create mode 100644 libsrc/cx16/cpeekrevers.s
create mode 100644 libsrc/cx16/cpeeks.s
create mode 100644 libsrc/cx16/cputc.s
create mode 100644 libsrc/cx16/crt0.s
create mode 100644 libsrc/cx16/devnum.s
create mode 100644 libsrc/cx16/get_ostype.s
create mode 100644 libsrc/cx16/get_tv.s
create mode 100644 libsrc/cx16/irq.s
create mode 100644 libsrc/cx16/joy/cx16-stdjoy.s
create mode 100644 libsrc/cx16/joy_stat_stddrv.s
create mode 100644 libsrc/cx16/joy_stddrv.s
create mode 100644 libsrc/cx16/kbhit.s
create mode 100644 libsrc/cx16/kernal.s
create mode 100644 libsrc/cx16/libref.s
create mode 100644 libsrc/cx16/mainargs.s
create mode 100644 libsrc/cx16/revers.s
create mode 100644 libsrc/cx16/set_tv.s
create mode 100644 libsrc/cx16/status.s
create mode 100644 libsrc/cx16/sysuname.s
create mode 100644 libsrc/cx16/videomode.s
create mode 100644 libsrc/cx16/waitvsync.s
diff --git a/asminc/cbm_kernal.inc b/asminc/cbm_kernal.inc
index 29a6e5dd..79edce06 100644
--- a/asminc/cbm_kernal.inc
+++ b/asminc/cbm_kernal.inc
@@ -1,30 +1,45 @@
;
; Olli Savia <ops@iki.fi>
;
-; Commodore kernal functions
+; Commodore Kernal functions
;
+.if .def(__CX16__)
+ ; CX16 extended jump table
+ GETJOY := $FF06
+.endif
+
.if .def(__C128__)
- ; C128 Extended jump table
+ ; C128 extended jump table
C64MODE := $FF4D
- SWAPPER := $FF5F
SETBNK := $FF68
.endif
-.if .def(__C64__) || .def(__C128__) || .def(__C16__)
+.if .def(__C128__) || .def(__CX16__)
+ ; Extended jump table
+ CLSALL := $FF4A
+ SWAPPER := $FF5F
+ JSRFAR := $FF6E
+ INDFET := $FF74
+ INDSTA := $FF77
+ INDCMP := $FF7A
+ PRIMM := $FF7D
+.endif
+
+.if .def(__C64__) || .def(__C128__) || .def(__C16__) || .def(__CX16__)
CINT := $FF81
IOINIT := $FF84
RAMTAS := $FF87
.elseif .def(__VIC20__)
- CINT := $E518 ; No entries are in the kernal jump table of the Vic20 for these three (3) functions.
+ CINT := $E518 ; No entries are in the Kernal jump table of the VIC-20 for these three (3) functions.
IOINIT := $FDF9 ; The entries for these functions have been set to point directly to the functions
- RAMTAS := $FD8D ; in the kernal to maintain compatibility with the other Commodore platforms.
+ RAMTAS := $FD8D ; in the Kernal, to maintain compatibility with the other Commodore platforms.
.elseif .def(__CBM510__) || .def(__CBM610__)
IOINIT := $FF7B
CINT := $FF7E
.endif
-.if .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__)
+.if .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__) || .def(__CX16__)
RESTOR := $FF8A
VECTOR := $FF8D
.elseif .def(__CBM510__) || .def(__CBM610__)
@@ -32,7 +47,7 @@
RESTOR := $FF87
.endif
-.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__)
+.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__) || .def(__CX16__)
SETMSG := $FF90
SECOND := $FF93
TKSA := $FF96
@@ -64,7 +79,7 @@ CHRIN := $FFCF
BSOUT := $FFD2
CHROUT := $FFD2
-.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__)
+.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__) || .def(__CX16__)
LOAD := $FFD5
SAVE := $FFD8
SETTIM := $FFDB
@@ -77,7 +92,7 @@ GETIN := $FFE4
CLALL := $FFE7
UDTIM := $FFEA
-.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__)
+.if .def(__CBM510__) || .def(__CBM610__) || .def(__VIC20__) || .def(__C64__) || .def(__C128__) || .def(__C16__) || .def(__CX16__)
SCREEN := $FFED
PLOT := $FFF0
IOBASE := $FFF3
@@ -102,7 +117,6 @@ UDTIM := $FFEA
CURS_SET := $CD57
CURS_ON := $CD6F
CURS_OFF := $CD9F
- INDFET := $FF74
.elseif .def(__C16__)
CLRSCR := $D88B
KBDREAD := $D8C1
diff --git a/asminc/cx16.inc b/asminc/cx16.inc
new file mode 100644
index 00000000..6f3f1c73
--- /dev/null
+++ b/asminc/cx16.inc
@@ -0,0 +1,316 @@
+;
+; CX16 definitions
+;
+
+; ---------------------------------------------------------------------------
+; Constants
+
+.enum COLOR
+ BLACK = $00
+ WHITE
+ RED
+ CYAN
+ VIOLET
+ PURPLE = VIOLET
+ GREEN
+ BLUE
+ YELLOW
+ ORANGE
+ BROWN
+ LIGHTRED
+ GRAY1
+ GRAY2
+ LIGHTGREEN
+ LIGHTBLUE
+ GRAY3
+.endenum
+
+; Special keys
+.enum KEY
+ F1 = $85
+ F3
+ F5
+ F7
+ F2
+ F4
+ F6
+ F8
+ F9 = $10
+ F10 = $15
+ F11
+ F12
+.endenum
+
+; ---------------------------------------------------------------------------
+; Zero page
+
+; BASIC
+VARTAB := $2D ; Pointer to start of BASIC variables
+MEMSIZE := $37 ; Pointer to highest BASIC RAM location (+1)
+TXTPTR := $7A ; Pointer into BASIC source code
+
+; Kernal
+IN_DEV := $99 ; Current input device number
+OUT_DEV := $9A ; Current output device number
+IMPARM := $9B ; Pointer for PRIMM function
+TIME := $A0 ; 60 Hz. clock
+FNAM_LEN := $B7 ; Length of filename
+SECADR := $B9 ; Secondary address
+DEVNUM := $BA ; Device number
+FNAM := $BB ; Pointer to filename
+KEY_COUNT := $C6 ; Number of keys in input buffer
+RVS := $C7 ; Reverse flag
+CURS_FLAG := $CC ; 1 = cursor off
+CURS_BLINK := $CD ; Blink counter
+CURS_CHAR := $CE ; Character under the cursor
+CURS_STATE := $CF ; Cursor blink state
+SCREEN_PTR := $D1 ; Pointer to current row on text screen (16 bits)
+CURS_X := $D3 ; Cursor column
+CURS_Y := $D6 ; Cursor row
+LLEN := $D9 ; Line length
+NLINES := $DA ; Number of screen lines
+JOY1 := $EF ; 3 bytes of NES/SNES gamepad data
+JOY2 := $F2
+FREKZP := $FB ; Five unused bytes
+
+; Page two
+
+BASIC_BUF := $200 ; Location of command-line
+BASIC_BUF_LEN = 89 ; Maximum length of command-line
+
+CHARCOLOR := $286
+CURS_COLOR := $287 ; Color under the cursor
+
+; ---------------------------------------------------------------------------
+; Vector and other locations
+
+IRQVec := $0314
+BRKVec := $0316
+NMIVec := $0318
+
+; ---------------------------------------------------------------------------
+; I/O locations
+
+; Video Enhanced Retro Adapter
+; Has audio, SPI, and UART.
+.scope VERA
+ ; External registers
+ .struct
+ .org $9F20
+ ADDR .faraddr ; Address for data port access
+ DATA0 .byte ; First data port
+ DATA1 .byte ; Second data port
+ CTRL .byte ; Control register
+ IRQ_EN .byte ; Interrupt enable bits
+ IRQ_FLAGS .byte ; Interrupt flags
+ .endstruct
+ .enum ; Address automatic increment amounts
+ INC0 = 0 << 4
+ INC1 = 1 << 4
+ INC2 = 2 << 4
+ INC4 = 3 << 4
+ INC8 = 4 << 4
+ INC16 = 5 << 4
+ INC32 = 6 << 4
+ INC64 = 7 << 4
+ INC128 = 8 << 4
+ INC256 = 9 << 4
+ INC512 = 10 << 4
+ INC1024 = 11 << 4
+ INC2048 = 12 << 4
+ INC4096 = 13 << 4
+ INC8192 = 14 << 4
+ INC16384 = 15 << 4
+ .endenum
+ ; Internal RAM and registers
+ VRAM := $000000
+ .scope COMPOSER ; Display composer
+ .struct
+ .org $0F0000
+ VIDEO .byte
+ HSCALE .byte
+ VSCALE .byte
+ FRAME .byte
+ HSTART_LO .byte
+ HSTOP_LO .byte
+ VSTART_LO .byte
+ VSTOP_LO .byte
+ STRTSTOP_HI .byte
+ IRQ_LINE .word
+ .endstruct
+ .enum MODE ; Output mode
+ DISABLE = 0
+ VGA
+ NTSC
+ RGB ; Interlaced, composite sync
+ .endenum
+ .enum
+ ENABLE_COLOR = 0 << 2
+ DISABLE_COLOR = 1 << 2 ; NTSC monochrome
+ .endenum
+ .endscope
+ PALETTE := $0F1000
+ .struct L0 ; Layer 0 registers
+ .org $0F2000
+ CTRL0 .byte ; Display mode control
+ CTRL1 .byte ; Geometry control
+ MAP_BASE .addr
+ TILE_BASE .addr
+ HSCROLL .word ; Horizontal scroll
+ VSCROLL .word ; Vertical scroll
+ .endstruct
+ .struct L1 ; Layer 1 registers (same as layer 0)
+ .org $0F3000
+ CTRL0 .byte
+ CTRL1 .byte
+ MAP_BASE .addr
+ TILE_BASE .addr
+ HSCROLL .word
+ VSCROLL .word
+ .endstruct
+ .enum MAP ; Map geometry
+ WIDTH32 = 0
+ WIDTH64
+ WIDTH128
+ WIDTH256
+ HEIGHT32 = 0 << 2
+ HEIGHT64 = 1 << 2
+ HEIGHT128 = 2 << 2
+ HEIGHT256 = 3 << 2
+ .endenum
+ .scope TILE ; Tile geometry
+ .enum
+ WIDTH8 = 0 << 4
+ WIDTH16 = 1 << 4
+ WIDTH320 = WIDTH8
+ WIDTH640 = WIDTH16
+ HEIGHT8 = 0 << 5
+ HEIGHT16 = 1 << 5
+ .endenum
+ .enum FLIP
+ NONE = 0 << 2
+ HORIZ = 1 << 2
+ VERT = 2 << 2
+ BOTH = 3 << 2
+ .endenum
+ .endscope
+ .enum DMODE ; Display modes
+ TEXT16 = 0 << 5
+ TEXT256 = 1 << 5
+ TILE4 = 2 << 5
+ TILE16 = 3 << 5
+ TILE256 = 4 << 5
+ BITMAP4 = 5 << 5
+ BITMAP16 = 6 << 5
+ BITMAP256 = 7 << 5
+ .endenum
+ .scope SPRITE
+ .struct
+ .org $0F4000
+ CTRL .byte ; Enables sprites
+ COLLISION .byte
+ .endstruct
+ .enum FLIP
+ NONE = 0
+ HORIZ
+ VERT
+ BOTH
+ .endenum
+ .enum ; Sprite geometry
+ WIDTH8 = 0 << 4
+ WIDTH16 = 1 << 4
+ WIDTH32 = 2 << 4
+ WIDTH64 = 3 << 4
+ HEIGHT8 = 0 << 6
+ HEIGHT16 = 1 << 6
+ HEIGHT32 = 2 << 6
+ HEIGHT64 = 3 << 6
+ COLORS16 = 0 << 7
+ COLORS256 = 1 << 7
+ .endenum
+ .enum DEPTH
+ DISABLE = 0 << 2
+ CANVAS = 1 << 2
+ LAYER0 = 2 << 2
+ LAYER1 = 3 << 2
+ .endenum
+ ATTRIB := $0F5000 ; Sprite attributes
+ .endscope
+ AUDIO := $0F6000
+ .scope SPI
+ .struct
+ .org $0F7000
+ DATA .byte
+ CONTROL .byte
+ .endstruct
+ .enum
+ DESELECT = 0
+ SELECT
+ BUSY_MASK = 1 << 1
+ .endenum
+ .endscope
+ .scope UART ; Universal Asyncronous Receiver Transmitter
+ .struct
+ .org $0F8000
+ DATA .byte
+ STATUS .byte
+ BPS_DIV .word
+ .endstruct
+ .enum MASK
+ RECEIVE = 1 << 0
+ TRANSMIT = 1 << 1
+ .endenum
+ .endscope
+.endscope
+
+; 65c22
+.struct VIA1 ; Versatile Interface Adapter
+ .org $9F60
+ PRB .byte ; ROM bank, IEC (Port Register B)
+ PRA .byte ; RAM bank (Port Register A)
+ DDRB .byte ; (Data Direction Register B)
+ DDRA .byte ; (Data Direction Register A)
+ T1 .word ; (Timer 1)
+ T1L .word ; (Timer 1 Latch)
+ T2 .word ; (Timer 2)
+ SR .byte ; (Shift Register)
+ ACR .byte ; (Auxiliary Control Register)
+ PCR .byte ; (Peripheral Control Register)
+ IFR .byte ; (Interrupt Flags Register)
+ IER .byte ; (Interrupt Enable Register)
+ PRA2 .byte ; RAM bank (Port Register A without handshaking)
+.endstruct
+
+; 65c22
+.struct VIA2
+ .org $9F70
+ PRB .byte
+ PRA .byte ; NES controller communication
+ DDRB .byte
+ DDRA .byte
+ T1 .word
+ T1L .word
+ T2 .word
+ SR .byte
+ ACR .byte
+ PCR .byte
+ IFR .byte
+ IER .byte
+ PRA2 .byte
+.endstruct
+
+; Real-Time Clock
+
+; X16 Emulator device
+; This device doesn't exist on the real machine.
+.struct EMULATOR
+ .org $9FB0
+ DEBUG .byte ; Boolean: debugging enabled
+ VIDACCESSLOG .byte ; Boolean: log VERA activity
+ KEYBOARDLOG .byte ; Boolean: log keyboard data
+ ECHO .byte ; Boolean: echo enabled
+ SAVEXIT .byte ; Boolean: save on exit
+ .res $D - $5
+ KEYMAP .byte ; Current keyboard layout number
+ DETECT .byte 2 ; If is "16" string, then running on emulator
+.endstruct
diff --git a/cfg/cx16-asm.cfg b/cfg/cx16-asm.cfg
new file mode 100644
index 00000000..53f6da17
--- /dev/null
+++ b/cfg/cx16-asm.cfg
@@ -0,0 +1,37 @@
+FEATURES {
+ STARTADDRESS: default = $0801;
+}
+SYMBOLS {
+ __LOADADDR__: type = import;
+ __HIMEM__: type = weak, value = $9F00;
+}
+MEMORY {
+ ZP: file = "", start = $0004, size = $0090 - $0004, define = yes;
+ LOADADDR: file = %O, start = %S - 2, size = $0002;
+ MAIN: file = %O, start = %S, size = __HIMEM__ - %S;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ LOADADDR: load = LOADADDR, type = ro;
+ EXEHDR: load = MAIN, type = ro, optional = yes;
+ LOWCODE: load = MAIN, type = ro, optional = yes;
+ CODE: load = MAIN, type = ro;
+ RODATA: load = MAIN, type = ro;
+ DATA: load = MAIN, type = rw;
+ BSS: load = MAIN, type = bss, define = yes;
+}
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = ONCE;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+ CONDES: type = interruptor,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__,
+ segment = RODATA,
+ import = __CALLIRQ__;
+}
diff --git a/cfg/cx16-bank.cfg b/cfg/cx16-bank.cfg
new file mode 100644
index 00000000..52438fba
--- /dev/null
+++ b/cfg/cx16-bank.cfg
@@ -0,0 +1,112 @@
+FEATURES {
+ STARTADDRESS: default = $0801;
+}
+SYMBOLS {
+ __LOADADDR__: type = import;
+ __EXEHDR__: type = import;
+ __BANKRAMADDR__: type = import;
+ __STACKSIZE__: type = weak, value = $0800; # 2K stack
+ __HIMEM__: type = weak, value = $9F00;
+ __BANKRAMSTART__: type = export, value = $A000;
+ __BANKRAMSIZE__: type = weak, value = $2000; # 8K banked RAM
+}
+MEMORY {
+ ZP: file = "", define = yes, start = $0004, size = $0090 - $0004;
+ LOADADDR: file = %O, start = %S - 2, size = $0002;
+ HEADER: file = %O, define = yes, start = %S, size = $000D;
+ MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;
+ BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __ONCE_RUN__ - __STACKSIZE__;
+ BRAM00ADDR: file = "%O.00", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM00: file = "%O.00", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM01ADDR: file = "%O.01", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM01: file = "%O.01", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM02ADDR: file = "%O.02", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM02: file = "%O.02", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM03ADDR: file = "%O.03", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM03: file = "%O.03", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM04ADDR: file = "%O.04", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM04: file = "%O.04", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM05ADDR: file = "%O.05", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM05: file = "%O.05", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM06ADDR: file = "%O.06", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM06: file = "%O.06", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM07ADDR: file = "%O.07", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM07: file = "%O.07", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM08ADDR: file = "%O.08", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM08: file = "%O.08", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM09ADDR: file = "%O.09", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM09: file = "%O.09", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0AADDR: file = "%O.0a", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0A: file = "%O.0a", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0BADDR: file = "%O.0b", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0B: file = "%O.0b", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0CADDR: file = "%O.0c", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0C: file = "%O.0c", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0DADDR: file = "%O.0d", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0D: file = "%O.0d", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0EADDR: file = "%O.0e", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0E: file = "%O.0e", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+ BRAM0FADDR: file = "%O.0f", start = __BANKRAMSTART__ - 2, size = $0002;
+ BRAM0F: file = "%O.0f", start = __BANKRAMSTART__, size = __BANKRAMSIZE__;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ EXTZP: load = ZP, type = zp, optional = yes;
+ LOADADDR: load = LOADADDR, type = ro;
+ EXEHDR: load = HEADER, type = ro;
+ STARTUP: load = MAIN, type = ro;
+ LOWCODE: load = MAIN, type = ro, optional = yes;
+ CODE: load = MAIN, type = ro;
+ RODATA: load = MAIN, type = ro;
+ DATA: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw;
+ ONCE: load = MAIN, type = ro, define = yes;
+ BSS: load = BSS, type = bss, define = yes;
+ BRAM00ADDR: load = BRAM00ADDR, type = ro, optional = yes;
+ BANKRAM00: load = BRAM00, type = rw, define = yes, optional = yes;
+ BRAM01ADDR: load = BRAM01ADDR, type = ro, optional = yes;
+ BANKRAM01: load = BRAM01, type = rw, define = yes, optional = yes;
+ BRAM02ADDR: load = BRAM02ADDR, type = ro, optional = yes;
+ BANKRAM02: load = BRAM02, type = rw, define = yes, optional = yes;
+ BRAM03ADDR: load = BRAM03ADDR, type = ro, optional = yes;
+ BANKRAM03: load = BRAM03, type = rw, define = yes, optional = yes;
+ BRAM04ADDR: load = BRAM04ADDR, type = ro, optional = yes;
+ BANKRAM04: load = BRAM04, type = rw, define = yes, optional = yes;
+ BRAM05ADDR: load = BRAM05ADDR, type = ro, optional = yes;
+ BANKRAM05: load = BRAM05, type = rw, define = yes, optional = yes;
+ BRAM06ADDR: load = BRAM06ADDR, type = ro, optional = yes;
+ BANKRAM06: load = BRAM06, type = rw, define = yes, optional = yes;
+ BRAM07ADDR: load = BRAM07ADDR, type = ro, optional = yes;
+ BANKRAM07: load = BRAM07, type = rw, define = yes, optional = yes;
+ BRAM08ADDR: load = BRAM08ADDR, type = ro, optional = yes;
+ BANKRAM08: load = BRAM08, type = rw, define = yes, optional = yes;
+ BRAM09ADDR: load = BRAM09ADDR, type = ro, optional = yes;
+ BANKRAM09: load = BRAM09, type = rw, define = yes, optional = yes;
+ BRAM0AADDR: load = BRAM0AADDR, type = ro, optional = yes;
+ BANKRAM0A: load = BRAM0A, type = rw, define = yes, optional = yes;
+ BRAM0BADDR: load = BRAM0BADDR, type = ro, optional = yes;
+ BANKRAM0B: load = BRAM0B, type = rw, define = yes, optional = yes;
+ BRAM0CADDR: load = BRAM0CADDR, type = ro, optional = yes;
+ BANKRAM0C: load = BRAM0C, type = rw, define = yes, optional = yes;
+ BRAM0DADDR: load = BRAM0DADDR, type = ro, optional = yes;
+ BANKRAM0D: load = BRAM0D, type = rw, define = yes, optional = yes;
+ BRAM0EADDR: load = BRAM0EADDR, type = ro, optional = yes;
+ BANKRAM0E: load = BRAM0E, type = rw, define = yes, optional = yes;
+ BRAM0FADDR: load = BRAM0FADDR, type = ro, optional = yes;
+ BANKRAM0F: load = BRAM0F, type = rw, define = yes, optional = yes;
+}
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = ONCE;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+ CONDES: type = interruptor,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__,
+ segment = RODATA,
+ import = __CALLIRQ__;
+}
diff --git a/cfg/cx16.cfg b/cfg/cx16.cfg
new file mode 100644
index 00000000..f912e0f8
--- /dev/null
+++ b/cfg/cx16.cfg
@@ -0,0 +1,45 @@
+FEATURES {
+ STARTADDRESS: default = $0801;
+}
+SYMBOLS {
+ __LOADADDR__: type = import;
+ __EXEHDR__: type = import;
+ __STACKSIZE__: type = weak, value = $0800; # 2k stack
+ __HIMEM__: type = weak, value = $9F00;
+}
+MEMORY {
+ ZP: file = "", define = yes, start = $0004, size = $0090 - $0004;
+ LOADADDR: file = %O, start = %S - 2, size = $0002;
+ HEADER: file = %O, define = yes, start = %S, size = $000D;
+ MAIN: file = %O, define = yes, start = __HEADER_LAST__, size = __HIMEM__ - __HEADER_LAST__;
+ BSS: file = "", start = __ONCE_RUN__, size = __HIMEM__ - __ONCE_RUN__ - __STACKSIZE__;
+}
+SEGMENTS {
+ ZEROPAGE: load = ZP, type = zp;
+ EXTZP: load = ZP, type = zp, optional = yes;
+ LOADADDR: load = LOADADDR, type = ro;
+ EXEHDR: load = HEADER, type = ro;
+ STARTUP: load = MAIN, type = ro;
+ LOWCODE: load = MAIN, type = ro, optional = yes;
+ CODE: load = MAIN, type = ro;
+ RODATA: load = MAIN, type = ro;
+ DATA: load = MAIN, type = rw;
+ INIT: load = MAIN, type = rw;
+ ONCE: load = MAIN, type = ro, define = yes;
+ BSS: load = BSS, type = bss, define = yes;
+}
+FEATURES {
+ CONDES: type = constructor,
+ label = __CONSTRUCTOR_TABLE__,
+ count = __CONSTRUCTOR_COUNT__,
+ segment = ONCE;
+ CONDES: type = destructor,
+ label = __DESTRUCTOR_TABLE__,
+ count = __DESTRUCTOR_COUNT__,
+ segment = RODATA;
+ CONDES: type = interruptor,
+ label = __INTERRUPTOR_TABLE__,
+ count = __INTERRUPTOR_COUNT__,
+ segment = RODATA,
+ import = __CALLIRQ__;
+}
diff --git a/doc/ca65.sgml b/doc/ca65.sgml
index 8a5e307d..ad72189c 100644
--- a/doc/ca65.sgml
+++ b/doc/ca65.sgml
@@ -4653,9 +4653,10 @@ compiler, depending on the target system selected:
<item><tt/__C128__/ - Target system is <tt/c128/
<item><tt/__C16__/ - Target system is <tt/c16/ or <tt/plus4/
<item><tt/__C64__/ - Target system is <tt/c64/
-<item><tt/__CBM__/ - Target is a Commodore system
+<item><tt/__CBM__/ - Target is a Commodore or Commodore-alike system
<item><tt/__CBM510__/ - Target system is <tt/cbm510/
<item><tt/__CBM610__/ - Target system is <tt/cbm610/
+<item><tt/__CX16__/ - Target system is <tt/cx16/
<item><tt/__GEOS__/ - Target is a GEOS system
<item><tt/__GEOS_APPLE__/ - Target system is <tt/geos-apple/
<item><tt/__GEOS_CBM__/ - Target system is <tt/geos-cbm/
diff --git a/doc/cc65.sgml b/doc/cc65.sgml
index 601e364e..8691f947 100644
--- a/doc/cc65.sgml
+++ b/doc/cc65.sgml
@@ -901,6 +901,10 @@ The compiler defines several macros at startup:
<item><tt/__CC65_STD_CC65__/
</itemize>
+ <tag><tt>__CX16__</tt></tag>
+
+ This macro is defined if the target is the Commander X16 (-t cx16).
+
<tag><tt>__DATE__</tt></tag>
This macro expands to the date of translation of the preprocessing
diff --git a/doc/cx16.sgml b/doc/cx16.sgml
new file mode 100644
index 00000000..077458bf
--- /dev/null
+++ b/doc/cx16.sgml
@@ -0,0 +1,311 @@
+<!doctype linuxdoc system>
+
+<article>
+<title>Commander X16-specific information for cc65
+<author><url url="mailto:greg.king5@verizon.net" name="Greg King">
+
+<abstract>
+An overview over the CX16 run-time system as it's implemented for the cc65 C
+compiler.
+</abstract>
+
+<!-- Table of contents -->
+<toc>
+
+<!-- Begin the document -->
+
+<sect>Overview<p>
+
+The Commander X16 is a modern small computer with firmware that is based on
+the ROMs in Commodore's VIC-20 and 64C. It has a couple of the I/O chips that
+are in the VIC-20.
+
+This file contains an overview of the CX16 run-time system as it comes with the
+cc65 C compiler. It describes the memory layout, CX16-specific header files,
+available drivers, and any pitfalls specific to that platform.
+
+Please note that CX16-specific functions just are mentioned here; they are
+described in detail in the separate <url url="funcref.html" name="function
+reference">. Even functions marked as "platform dependent" may be available on
+more than one platform. Please see the function reference for more
+information.
+
+
+
+<sect>Binary format<p>
+
+The standard binary output format generated by the linker for the CX16 target
+is a machine language program with a one-line BASIC stub which calls the
+machine language part via SYS. That means that a program can be loaded as a
+BASIC program, and started with RUN. It is, of course, possible to change that
+behaviour by using a modified start-up file and linker config.
+
+
+
+<sect>Memory layout<p>
+
+cc65-generated programs with the default setup run with the I/O area and the
+Kernal ROM visible. That means that Kernal entry points can be called directly.
+The usable memory ranges are $0800 - $9EFF and $A000 -
+$BFFF.
+
+Special locations:
+
+<descrip>
+ <tag/Stack/
+ The C run-time stack is located at $9EFF, and grows downward.
+
+ <tag/Heap/
+ The C heap is located at the end of the program, and grows toward the C
+ run-time stack.
+
+ <tag/Bank RAM/
+ Bank RAM is located at $A000 - $BFFF. It's an eight-Kibibyte
+ window into a half Mibibyte or two Mibibytes of banked RAM.
+
+ <tag/Bank ROM/
+ Bank ROM is located at $C000 - $FFFF. It's a sixteen-Kibibyte
+ window into 128 Kibibytes of banked ROM.
+</descrip><p>
+
+
+
+<sect>Linker configurations<p>
+
+The ld65 linker comes with a default config. file for the Commander X16, which
+is used via <tt/-t cx16/. The cx16 package comes with additional secondary
+linker config. files which are used via <tt/-t cx16 -C <configfile>/.
+
+
+<sect1>Default config. file (<tt/cx16.cfg/)<p>
+
+The default configuration is tailored to C programs. It supplies the load
+address and a small BASIC stub that starts the compiled program using a SYS
+command.
+
+
+<sect1><tt/cx16-asm.cfg/<p>
+
+This configuration is made for Assembly programmers who don't need a special
+setup. The default start address is $0801. It can be changed with the
+linker command-line option <tt/--start-addr/ or <tt/-S/. All standard segments,
+with the exception of <tt/ZEROPAGE/, are written to the output file;
+and, a two-byte load address is prepended.
+
+To use that config. file, assemble with <tt/-t cx16/, and link with <tt/-C
+cx16-asm.cfg/. The former will make sure that the correct character
+translations are in effect, while the latter supplies the actual config.
+When using <tt/cl65/, use both command-line options.
+
+Sample command line for <tt/cl65/:
+<tscreen><verb>
+cl65 -o file.prg -t cx16 -C cx16-asm.cfg source.s
+</verb></tscreen>
+
+To generate code that loads to $A000:
+<tscreen><verb>
+cl65 -o file.prg -Wl -S,$A000 -t cX16 -C cX16-asm.cfg source.s
+</verb></tscreen>
+
+It also is possible to add a small BASIC header to the program, that uses SYS
+to jump to the program entry point (which is the start of the code segment).
+The advantage is that the program can be started using RUN.
+
+To generate a program with a BASIC SYS header, use
+<tscreen><verb>
+cl65 -o file.prg -u __EXEHDR__ -t cx16 -C cx16-asm.cfg source.s
+</verb></tscreen>
+
+Please note that, in this case, a changed start address doesn't make sense,
+because the program must be loaded to BASIC's start address.
+
+
+
+<sect>Platform-specific header files<p>
+
+Programs containing CX16-specific code may use the <tt/cx16.h/ or <tt/cbm.h/
+header files. Using the later may be an option when writing code for more than
+one CBM-like platform, because it includes <tt/cx16.h/, and declares several
+functions common to all CBM-like platforms.
+
+
+<sect1>CX16-specific functions<p>
+
+The functions listed below are special for the CX16. See the <url
+url="funcref.html" name="function reference"> for declarations and usage.
+
+<itemize>
+<item>get_ostype()
+<item>set_tv()
+<item>videomode()
+<item>waitvsync()
+</itemize>
+
+
+<sect1>CBM-specific functions<p>
+
+Some functions are available for all (or, at least most) of the Commodore-like
+machines. See the <url url="funcref.html" name="function reference"> for
+declarations and usage.
+
+<itemize>
+<item>cbm_close()
+<item>cbm_closedir()
+<item>cbm_k_basin()
+<item>cbm_k_bsout()
+<item>cbm_k_chkin()
+<item>cbm_k_ckout()
+<item>cbm_k_close()
+<item>cbm_k_clrch()
+<item>cbm_k_load()
+<item>cbm_k_open()
+<item>cbm_k_readst()
+<item>cbm_k_save()
+<item>cbm_k_second()
+<item>cbm_k_setlfs()
+<item>cbm_k_setnam()
+<item>cbm_k_tksa()
+<item>cbm_load()
+<item>cbm_open()
+<item>cbm_opendir()
+<item>cbm_read()
+<item>cbm_readdir()
+<item>cbm_save()
+<item>cbm_write()
+<item>get_tv()
+</itemize>
+
+
+<sect1>Hardware access<p>
+
+The following pseudo variables declared in the <tt/cx16.h/ header file do allow
+access to hardware located in the address space. Some variables are
+structures, accessing the struct fields will access the chip registers.
+
+<descrip>
+ <tag><tt/VERA/</tag>
+ The <tt/VERA/ structure allows access
+ to the Video Enhanced Retro Adapter chip.
+
+ <tag><tt/VIA1, VIA2/</tag>
+ Access to the two VIA (Versatile Interface Adapter) chips is available via
+ the <tt/VIA1/ and <tt/VIA2/ variables. The structure behind those variables
+ is explained in <tt/_6522.h/.
+
+ <tag><tt/BANK_RAM/</tag>
+ A character array that mirrors the eight-Kibibyte window, at $A000,
+ into banked RAM.
+</descrip><p>
+
+
+
+<sect>Loadable drivers<p>
+
+The names in the parentheses denote the symbols to be used for static linking of the drivers.
+
+
+<sect1>Graphics drivers<p>
+
+No graphics drivers are available currently for the CX16.
+
+
+<sect1>Extended memory drivers<p>
+
+No extended memory drivers are available currently for the CX16.
+
+
+<sect1>Joystick drivers<p>
+
+The default drivers, <tt/joy_stddrv (joy_static_stddrv)/,
+point to <tt/cX16-stdjoy.joy (cx16_stdjoy_joy)/.
+
+<descrip>
+ <tag><tt/cX16-stdjoy.joy (cX16_stdjoy_joy)/</tag>
+ Supports up to two NES and SNES controllers connected to the joystick ports
+ of the CX16. It reads the four directions, and the A, B, Select, and Start
+ buttons. Button A is the primary fire button.
+</descrip><p>
+
+
+<sect1>Mouse drivers<p>
+
+No mouse drivers are available currently for the CX16.
+
+
+<sect1>RS232 device drivers<p>
+
+No serial drivers are available currently for the CX16.
+
+
+
+<sect>Limitations<p>
+
+The Commander X16 still is being designed. It's configuration can change at
+any time. Some changes could make old programs fail to work.
+
+
+
+<sect>Other hints<p>
+
+
+<sect1>Escape code<p>
+
+For an Esc, press <tt/Ctrl/ and the <tt/[/ key.
+
+
+<sect1>Passing arguments to the program<p>
+
+Command-line arguments can be passed to <tt/main()/. Because that is not
+supported directly by BASIC, the following syntax was chosen:
+<tscreen><verb>
+ RUN:REM ARG1 " ARG2 IS QUOTED" ARG3 "" ARG5
+</verb></tscreen>
+
+<enum>
+<item>Arguments are separated by spaces.
+<item>Arguments may be quoted.
+<item>Leading and trailing spaces around an argument are ignored. Spaces within
+ a quoted argument are allowed.
+<item>The first argument passed to <tt/main()/ is the program name.
+<item>A maximum number of 10 arguments (including the program name) are
+ supported.
+</enum>
+
+
+<sect1>Program return code<p>
+
+The program return code (low byte) is passed back to BASIC by use of the
+<tt/ST/ variable.
+
+
+<sect1>Interrupts<p>
+
+The run-time for the CX16 uses routines marked as <tt/.INTERRUPTOR/ for
+interrupt handlers. Such routines must be written as simple machine language
+subroutines, and will be called automatically by the interrupt handler code
+if they are linked into a program. See the discussion of the <tt/.CONDES/
+feature in the <url url="ca65.html" name="assembler manual">.
+
+
+
+<sect>License<p>
+
+This software is provided "as-is", without any expressed or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+<enum>
+<item> The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated, but is not required.
+<item> Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+<item> This notice may not be removed or altered from any source
+ distribution.
+</enum>
+
+</article>
diff --git a/doc/index.sgml b/doc/index.sgml
index aecfb7de..01325529 100644
--- a/doc/index.sgml
+++ b/doc/index.sgml
@@ -145,6 +145,9 @@
<tag><htmlurl url="creativision.html" name="creativision.html"></tag>
Topics specific to the Creativision Console.
+ <tag><htmlurl url="cx16.html" name="cx16.html"></tag>
+ Topics specific to the Commander X16.
+
<tag><htmlurl url="gamate.html" name="gamate.html"></tag>
Topics specific to the Bit Corporation Gamate Console.
diff --git a/doc/intro.sgml b/doc/intro.sgml
index 994d30bc..b2b141d1 100644
--- a/doc/intro.sgml
+++ b/doc/intro.sgml
@@ -402,11 +402,36 @@ RUN
The emulation, also, supports that method.
+<sect1>Commander X16
+
+<sect2>x16-emulator<p>
+Available at <url
+url="https://github.com/commanderx16/x16-emulator/releases">:
+
+Emulates the Commander X16 Single Board Computer, with sound, SD card images,
+VGA and NTSC video, and a NES game controller emulation. Includes a monitor.
+It runs on all SDL2 platforms.
+
+Compile the tutorial with
+<tscreen><verb>
+cl65 -O -t cx16 hello.c text.s
+</verb></tscreen>
+
+Start the emulator. Then, type
+<tscreen><verb>
+LOAD"HELLO",1
+RUN
+</verb></tscreen>
+(Type those lines in lower-case; but, they will appear as upper-case.)
+
+On a real computer, you would type an <tt/8/ instead of a <tt/1/.
+
+
<sect1>Commodore
<sect2>VICE<p>
Available at <url
-url="http://vice-emu.sourceforge.net/">:
+url="https://vice-emu.sourceforge.net/">:
Emulates Commodore 64/128/VIC-20/PET/CBM II/Plus 4 computers. Supports
printers, serial port and adapters, stereo sound, disk drives and images, RAM expansions,
diff --git a/include/cbm.h b/include/cbm.h
index 0a2d6469..d9b31543 100644
--- a/include/cbm.h
+++ b/include/cbm.h
@@ -65,6 +65,8 @@
# include <cbm610.h>
#elif defined(__PET__) && !defined(_PET_H)
# include <pet.h>
+#elif defined(__CX16__) && !defined(_CX16_H)
+# include <cx16.h>
#endif
/* Include definitions for CBM file types */
@@ -300,5 +302,3 @@ void __fastcall__ cbm_closedir (unsigned char lfn);
/* End of cbm.h */
#endif
-
-
diff --git a/include/cx16.h b/include/cx16.h
new file mode 100644
index 00000000..db32d846
--- /dev/null
+++ b/include/cx16.h
@@ -0,0 +1,189 @@
+/*****************************************************************************/
+/* */
+/* cx16.h */
+/* */
+/* CX16 system-specific definitions */
+/* */
+/* */
+/* This software is provided "as-is", without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated, but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#ifndef _CX16_H
+#define _CX16_H
+
+
+
+/* Check for errors */
+#ifndef __CX16__
+# error This module may be used only when compiling for the CX16!
+#endif
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Additional key defines */
+#define CH_F1 0x85
+#define CH_F2 0x89
+#define CH_F3 0x86
+#define CH_F4 0x8A
+#define CH_F5 0x87
+#define CH_F6 0x8B
+#define CH_F7 0x88
+#define CH_F8 0x8C
+#define CH_F9 0x10
+#define CH_F10 0x15
+#define CH_F11 0x16
+#define CH_F12 0x17
+
+/* Color defines */
+#define COLOR_BLACK 0x00
+#define COLOR_WHITE 0x01
+#define COLOR_RED 0x02
+#define COLOR_CYAN 0x03
+#define COLOR_VIOLET 0x04
+#define COLOR_PURPLE COLOR_VIOLET
+#define COLOR_GREEN 0x05
+#define COLOR_BLUE 0x06
+#define COLOR_YELLOW 0x07
+#define COLOR_ORANGE 0x08
+#define COLOR_BROWN 0x09
+#define COLOR_LIGHTRED 0x0A
+#define COLOR_GRAY1 0x0B
+#define COLOR_GRAY2 0x0C
+#define COLOR_LIGHTGREEN 0x0D
+#define COLOR_LIGHTBLUE 0x0E
+#define COLOR_GRAY3 0x0F
+
+/* Masks for joy_read() */
+#define JOY_BTN_1_MASK 0x80
+#define JOY_BTN_2_MASK 0x40
+#define JOY_BTN_3_MASK 0x20
+#define JOY_BTN_4_MASK 0x10
+#define JOY_UP_MASK 0x08
+#define JOY_DOWN_MASK 0x04
+#define JOY_LEFT_MASK 0x02
+#define JOY_RIGHT_MASK 0x01
+
+#define JOY_BTN_A_MASK JOY_BTN_1_MASK
+#define JOY_BTN_B_MASK JOY_BTN_2_MASK
+#define JOY_SELECT_MASK JOY_BTN_3_MASK
+#define JOY_START_MASK JOY_BTN_4_MASK
+
+#define JOY_BTN_A(v) ((v) & JOY_BTN_A_MASK)
+#define JOY_BTN_B(v) ((v) & JOY_BTN_B_MASK)
+#define JOY_SELECT(v) ((v) & JOY_SELECT_MASK)
+#define JOY_START(v) ((v) & JOY_START_MASK)
+
+#define JOY_FIRE2_MASK JOY_BTN_2_MASK
+#define JOY_FIRE2(v) ((v) & JOY_FIRE2_MASK)
+
+/* get_tv() return codes
+** set_tv() argument codes
+*/
+#define TV_NONE 0
+#define TV_VGA 1
+#define TV_NTSC_COLOR 2
+#define TV_RGB 3
+#define TV_NONE2 4
+#define TV_VGA2 5
+#define TV_NTSC_MONO 6
+#define TV_RGB2 7
+
+/* Video mode defines */
+#define VIDEOMODE_40x30 40u
+#define VIDEOMODE_80x60 80u
+#define VIDEOMODE_40COL VIDEOMODE_40x30
+#define VIDEOMODE_80COL VIDEOMODE_80x60
+
+
+/* Define hardware */
+
+/* Define a structure with the Video Enhanced Retro Adapter's
+** external registers.
+*/
+struct __vera {
+ unsigned short address; /* Address for data ports */
+ unsigned char address_hi;
+ unsigned char data0; /* Data port 0 */
+ unsigned char data1; /* Data port 1 */
+ unsigned char control; /* Control register */
+ unsigned char irq_enable; /* Interrupt enable bits */
+ unsigned char irq_flags; /* Interrupt flags */
+};
+#define VERA (*(volatile struct __vera *)0x9F20)
+
+#include <_6522.h>
+#define VIA1 (*(volatile struct __6522 *)0x9F60)
+#define VIA2 (*(volatile struct __6522 *)0x9F70)
+
+/* Define a structure with the x16emu's settings registers. */
+struct __emul {
+ unsigned char debug; /* Boolean: debugging enabled */
+ unsigned char vera_action; /* Boolean: displaying VERA activity */
+ unsigned char keyboard; /* Boolean: displaying typed keys */
+ unsigned char echo; /* Boolean: Kernal output echoed to host */
+ unsigned char save_on_exit; /* Boolean: save SD card when quitting */
+ unsigned char unused[0xD - 0x5];
+ unsigned char keymap; /* Keyboard layout number */
+ const char detect[2]; /* "16" if running on x16emu */
+};
+#define EMULATOR (*(volatile struct __emul)0x9FB0)
+
+
+
+/* The addresses of the static drivers */
+
+extern void cx16_stdjoy_joy[]; /* Referred to by joy_static_stddrv[] */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+signed char get_ostype (void);
+/* Get the ROM build version.
+** -1 -- custom build
+** Negative -- prerelease build
+** Positive -- release build
+*/
+
+void __fastcall__ set_tv (unsigned char);
+/* Set the video mode the machine will use.
+** Call with a TV_xx constant.
+*/
+
+unsigned char __fastcall__ videomode (unsigned char Mode);
+/* Set the video mode, return the old mode. Call with one of the VIDEOMODE_xx
+** constants.
+*/
+
+
+
+/* End of cX16.h */
+#endif
diff --git a/libsrc/Makefile b/libsrc/Makefile
index 0ebec46b..d9ddb3cc 100644
--- a/libsrc/Makefile
+++ b/libsrc/Makefile
@@ -7,6 +7,7 @@ CBMS = c128 \
c64 \
cbm510 \
cbm610 \
+ cx16 \
pet \
plus4 \
vic20
diff --git a/libsrc/cx16/_scrsize.s b/libsrc/cx16/_scrsize.s
new file mode 100644
index 00000000..8059f04d
--- /dev/null
+++ b/libsrc/cx16/_scrsize.s
@@ -0,0 +1,14 @@
+;
+; 2019-09-16, Greg King
+;
+; Screen size info
+;
+
+ .export screensize
+
+ .include "cx16.inc"
+
+screensize:
+ ldx LLEN
+ ldy NLINES
+ rts
diff --git a/libsrc/cx16/bankramaddr.s b/libsrc/cx16/bankramaddr.s
new file mode 100644
index 00000000..53d96e91
--- /dev/null
+++ b/libsrc/cx16/bankramaddr.s
@@ -0,0 +1,50 @@
+;
+; 2019-09-16, Greg King
+;
+; This module supplies the load addresses that are expected
+; by a Commander X16 in the first two bytes of banked RAM load files.
+;
+
+ ; The following symbol is used by a linker config. to force
+ ; this module to get included into the output files.
+ .export __BANKRAMADDR__: abs = 1
+
+.segment "BRAM00ADDR"
+
+ .addr *+2
+
+.segment "BRAM01ADDR"
+
+ .addr *+2
+
+.segment "BRAM02ADDR"
+
+ .addr *+2
+
+.segment "BRAM03ADDR"
+
+ .addr *+2
+
+.segment "BRAM04ADDR"
+
+ .addr *+2
+
+.segment "BRAM05ADDR"
+
+ .addr *+2
+
+.segment "BRAM06ADDR"
+
+ .addr *+2
+
+.segment "BRAM07ADDR"
+
+ .addr *+2
+
+.segment "BRAM08ADDR"
+
+ .addr *+2
+
+.segment "BRAM09ADDR"
+
+ .addr *+2
diff --git a/libsrc/cx16/bordercolor.s b/libsrc/cx16/bordercolor.s
new file mode 100644
index 00000000..6691e2ec
--- /dev/null
+++ b/libsrc/cx16/bordercolor.s
@@ -0,0 +1,27 @@
+;
+; 2019-09-23, Greg King
+;
+; unsigned char __fastcall__ bordercolor (unsigned char color);
+; /* Set the color for the border. The old color setting is returned. */
+;
+
+ .export _bordercolor
+
+ .include "cx16.inc"
+
+_bordercolor:
+ tax
+
+ ; Point to the border color register.
+
+ stz VERA::CTRL ; Use port 0
+ lda #<VERA::COMPOSER::FRAME
+ sta VERA::ADDR
+ lda #>VERA::COMPOSER::FRAME
+ sta VERA::ADDR+1
+ ldy #^VERA::COMPOSER::FRAME | VERA::INC0
+ sty VERA::ADDR+2
+
+ lda VERA::DATA0 ; get old value
+ stx VERA::DATA0 ; set new value
+ rts
diff --git a/libsrc/cx16/break.s b/libsrc/cx16/break.s
new file mode 100644
index 00000000..ec569b9a
--- /dev/null
+++ b/libsrc/cx16/break.s
@@ -0,0 +1,109 @@
+;
+; 1998-09-27, Ullrich von Bassewitz
+; 2019-09-08, Greg King
+;
+; void __fastcall__ set_brk (unsigned Addr);
+; void reset_brk (void);
+;
+
+ .export _set_brk, _reset_brk
+ .destructor _reset_brk
+ .export _brk_a, _brk_x, _brk_y, _brk_sr, _brk_pc
+
+ .include "cx16.inc"
+
+
+.bss
+_brk_a: .res 1
+_brk_x: .res 1
+_brk_y: .res 1
+_brk_sr: .res 1
+_brk_pc: .res 2
+
+oldvec: .res 2 ; Old vector
+
+
+.data
+uservec: jmp $FFFF ; Patched at runtime
+
+
+.code
+
+; Set the break vector
+.proc _set_brk
+
+ sta uservec+1
+ stx uservec+2 ; Set the user vector
+
+ lda oldvec
+ ora oldvec+1 ; Did we save the vector already?
+ bne L1 ; Jump if we installed the handler already
+
+ lda BRKVec
+ sta oldvec
+ lda BRKVec+1
+ sta oldvec+1 ; Save the old vector
+
+L1: lda #<brk_handler ; Set the break vector to our routine
+ ldx #>brk_handler
+ sta BRKVec
+ stx BRKVec+1
+ rts
+
+.endproc
+
+
+; Reset the break vector
+.proc _reset_brk
+
+ lda oldvec
+ ldx oldvec+1
+ beq @L9 ; Jump if vector not installed
+ sta BRKVec
+ stx BRKVec+1
+ lda #$00
+ sta oldvec ; Clear the old vector
+ stx oldvec+1
+@L9: rts
+
+.endproc
+
+
+
+; Break handler, called if a break occurs
+
+.proc brk_handler
+
+ pla
+ sta _brk_y
+ pla
+ sta _brk_x
+ pla
+ sta _brk_a
+ pla
+ and #$EF ; Clear break bit
+ sta _brk_sr
+ pla ; PC low
+ sec
+ sbc #2 ; Point to start of brk
+ sta _brk_pc
+ pla ; PC high
+ sbc #0
+ sta _brk_pc+1
+
+ jsr uservec ; Call the user's routine
+
+ lda _brk_pc+1
+ pha
+ lda _brk_pc
+ pha
+ lda _brk_sr
+ pha
+ ldx _brk_x
+ ldy _brk_y
+ lda _brk_a
+ rti ; Jump back...
+
+.endproc
+
+
diff --git a/libsrc/cx16/cgetc.s b/libsrc/cx16/cgetc.s
new file mode 100644
index 00000000..14cad5f5
--- /dev/null
+++ b/libsrc/cx16/cgetc.s
@@ -0,0 +1,72 @@
+;
+; 2019-09-23, 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
+ jsr GETIN ; Read char, and return in .A
+ 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
diff --git a/libsrc/cx16/clrscr.s b/libsrc/cx16/clrscr.s
new file mode 100644
index 00000000..51fae6bf
--- /dev/null
+++ b/libsrc/cx16/clrscr.s
@@ -0,0 +1,26 @@
+;
+; 2019-09-22, Greg King
+;
+; void clrscr (void);
+; /* Clear the screen. */
+;
+
+ .export _clrscr
+
+ .import CHROUT
+
+ .include "cx16.inc"
+
+
+; 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 prints
+; to the screen.
+
+_clrscr:
+ ldy OUT_DEV ; Save current output device
+ ldx #$03 ; Screen device
+ stx OUT_DEV
+ lda #$93
+ jsr CHROUT ; Print clear-screen character
+ sty OUT_DEV ; Restore output device
+ rts
diff --git a/libsrc/cx16/color.s b/libsrc/cx16/color.s
new file mode 100644
index 00000000..1be01c47
--- /dev/null
+++ b/libsrc/cx16/color.s
@@ -0,0 +1,43 @@
+;
+; 2019-09-16, Greg King
+;
+; unsigned char __fastcall__ textcolor (unsigned char color);
+; unsigned char __fastcall__ bgcolor (unsigned char color);
+;
+
+
+ .export _textcolor, _bgcolor
+
+ .importzp tmp1
+ .include "cx16.inc"
+
+_textcolor:
+ and #$0F
+ sta tmp1
+ ldx CHARCOLOR ; get old values
+ txa
+ and #<~$0F ; keep screen color, remove text color
+ ora tmp1
+ sta CHARCOLOR ; set new values
+ txa
+ and #$0F
+ rts
+
+
+_bgcolor:
+ asl a ; move number to screen-color nybble
+ asl a
+ asl a
+ asl a
+ sta tmp1
+ ldx CHARCOLOR ; get old values
+ txa
+ and #<~$F0 ; remove screen color, keep text color
+ ora tmp1
+ sta CHARCOLOR ; set new values
+ txa
+ lsr a ; get screen color
+ lsr a
+ lsr a
+ lsr a
+ rts
diff --git a/libsrc/cx16/conio.s b/libsrc/cx16/conio.s
new file mode 100644
index 00000000..e760af21
--- /dev/null
+++ b/libsrc/cx16/conio.s
@@ -0,0 +1,9 @@
+;
+; 2019-09-23, Greg King
+;
+; Low-level stuff for screen output/console input
+;
+
+ .exportzp CURS_X, CURS_Y
+
+ .include "cx16.inc"
diff --git a/libsrc/cx16/cpeekc.s b/libsrc/cx16/cpeekc.s
new file mode 100644
index 00000000..2f02623b
--- /dev/null
+++ b/libsrc/cx16/cpeekc.s
@@ -0,0 +1,48 @@
+;
+; 2016-02-28, Groepaz
+; 2019-09-25, Greg King
+;
+; char cpeekc (void);
+; /* Return the character from the current cursor position. */
+;
+
+ .export _cpeekc
+
+ .include "cx16.inc"
+
+
+_cpeekc:
+ php
+ sei ; don't let cursor blinking interfere
+ stz VERA::CTRL ; use port 0
+ lda CURS_Y
+ sta VERA::ADDR+1 ; set row number
+ stz VERA::ADDR+2
+ lda CURS_X ; get character column
+ asl a
+ sta VERA::ADDR
+ lda VERA::DATA0 ; get screen code
+ plp
+ ldx #>$0000
+ and #<~%10000000 ; remove reverse bit
+
+; Convert the screen code into a PetSCII code.
+; $00 - $1F: +$40
+; $20 - $3F
+; $40 - $5f: +$20
+; $60 - $7F: +$40
+
+ cmp #$20
+ bcs @sk1 ;(bge)
+ ora #$40
+ rts
+
+@sk1: cmp #$40
+ bcc @end ;(blt)
+ cmp #$60
+ bcc @sk2 ;(blt)
+ ;sec
+ adc #$20 - $01
+@sk2: ;clc ; both above cmp and adc clear carry flag
+ adc #$20
+@end: rts
diff --git a/libsrc/cx16/cpeekcolor.s b/libsrc/cx16/cpeekcolor.s
new file mode 100644
index 00000000..4e3a39a2
--- /dev/null
+++ b/libsrc/cx16/cpeekcolor.s
@@ -0,0 +1,27 @@
+;
+; 2019-09-25, Greg King
+;
+; unsigned char cpeekcolor (void);
+; /* Return the colors from the current cursor position. */
+;
+
+ .export _cpeekcolor
+
+ .include "cx16.inc"
+
+
+_cpeekcolor:
+ php
+ sei ; don't let cursor blinking interfere
+ stz VERA::CTRL ; use port 0
+ lda CURS_Y
+ sta VERA::ADDR+1 ; set row number
+ stz VERA::ADDR+2
+ lda CURS_X ; get character column
+ sec ; color attribute is second byte
+ rol a
+ sta VERA::ADDR
+ lda VERA::DATA0 ; get color
+ plp
+ ldx #>$0000
+ rts
diff --git a/libsrc/cx16/cpeekrevers.s b/libsrc/cx16/cpeekrevers.s
new file mode 100644
index 00000000..d67dd295
--- /dev/null
+++ b/libsrc/cx16/cpeekrevers.s
@@ -0,0 +1,32 @@
+;
+; 2016-02-28, Groepaz
+; 2019-09-25, Greg King
+;
+; unsigned char cpeekrevers (void);
+; /* Return the reverse attribute from the current cursor position.
+; ** If the character is reversed, then return 1; return 0 otherwise.
+; */
+;
+
+ .export _cpeekrevers
+
+ .include "cx16.inc"
+
+
+_cpeekrevers:
+ php
+ sei ; don't let cursor blinking interfere
+ stz VERA::CTRL ; use port 0
+ lda CURS_Y
+ sta VERA::ADDR+1 ; set row number
+ stz VERA::ADDR+2
+ lda CURS_X ; get character column
+ asl a
+ sta VERA::ADDR
+ lda VERA::DATA0 ; get screen code
+ plp
+ and #%10000000 ; get reverse bit
+ asl a
+ tax ; ldx #>$0000
+ rol a ; return boolean value
+ rts
diff --git a/libsrc/cx16/cpeeks.s b/libsrc/cx16/cpeeks.s
new file mode 100644
index 00000000..e69de29b
diff --git a/libsrc/cx16/cputc.s b/libsrc/cx16/cputc.s
new file mode 100644
index 00000000..cf0a5fa2
--- /dev/null
+++ b/libsrc/cx16/cputc.s
@@ -0,0 +1,98 @@
+;
+; 2019-09-23, Greg King
+;
+; void __fastcall__ cputcxy (unsigned char x, unsigned char y, char c);
+; void __fastcall__ cputc (char c);
+;
+
+ .export _cputcxy, _cputc, cputdirect, putchar
+ .export newline, plot
+
+ .import gotoxy, PLOT
+
+ .include "cx16.inc"
+ .macpack generic
+
+
+; First, move to a new position.
+
+_cputcxy:
+ pha ; Save C
+ jsr gotoxy ; Set cursor, drop x and y
+ pla ; Restore C
+
+; Print a character.
+
+_cputc: cmp #$0D ; LF?
+ beq newline
+ cmp #$0A ; CR?
+ beq plotx0
+
+; Printable char of some sort
+
+ cmp #' '
+ blt cputdirect ; Other control char
+ tay
+ bmi L10
+ cmp #$60
+ blt L2
+ and #<~%00100000
+ bra cputdirect
+
+; Handle character if high bit set
+
+L10: and #<~%10000000 ; Remove high bit
+ ora #%01000000
+ bra cputdirect
+
+L2: and #<~%01000000
+
+cputdirect:
+ jsr putchar ; Write character to screen, return .Y
+
+; Advance cursor position.
+
+ iny
+ cpy LLEN ; Reached end of line?
+ bne L3
+ jsr newline ; Next line
+ ldy #$00 ; + CR
+L3: sty CURS_X
+ rts
+
+; Move down.
+
+newline:
+ inc SCREEN_PTR+1
+ inc CURS_Y
+ rts
+
+
+; Set the cursor's position, calculate RAM pointer.
+
+plotx0: stz CURS_X
+plot: ldy CURS_X
+ ldx CURS_Y
+ clc
+ jmp PLOT ; Set the new cursor
+
+
+; Write one screen-code and color to the video RAM without doing anything else.
+; Return the x position in Y.
+
+putchar:
+ ora RVS ; Set revers bit
+ tax
+ 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
+ ldy CURS_X ; Get character column
+ tya
+ asl a
+ sta VERA::ADDR
+ stx VERA::DATA0
+ lda CHARCOLOR
+ sta VERA::DATA0
+ rts
diff --git a/libsrc/cx16/crt0.s b/libsrc/cx16/crt0.s
new file mode 100644
index 00000000..181e6308
--- /dev/null
+++ b/libsrc/cx16/crt0.s
@@ -0,0 +1,115 @@
+;
+; Start-up code for cc65 (CX16 version)
+;
+
+ .export _exit
+ .export __STARTUP__ : absolute = 1 ; Mark as start-up
+
+ .import initlib, donelib
+ .import zerobss, callmain
+ .import BSOUT
+ .import __MAIN_START__, __MAIN_SIZE__ ; Linker-generated
+ .importzp ST
+
+ .include "zeropage.inc"
+ .include "cx16.inc"
+
+
+; ------------------------------------------------------------------------
+; Start-up code
+
+.segment "STARTUP"
+
+Start: tsx
+ stx spsave ; Save the system stack ptr
+
+; Save space by putting some of the start-up code in the ONCE segment,
+; which will be re-used by the BSS segment, the heap, and the C stack.
+
+ jsr init
+
+; Clear the BSS data.
+
+ jsr zerobss
+
+; Push the command-line arguments; and, call main().
+
+ jsr callmain
+
+; Back from main() [this is also the exit() entry]. Run the module destructors.
+
+_exit: pha ; Save the return code on stack
+ jsr donelib
+
+; Copy back the zero-page stuff.
+
+ ldx #zpspace-1
+L2: lda zpsave,x
+ sta sp,x
+ dex
+ bpl L2
+
+; Place the program return code into BASIC's status variable.
+
+ pla
+ sta ST
+
+; Restore the system stuff.
+
+ ldx spsave
+ txs ; Restore stack pointer
+ ldx banksave
+ stx VIA1::PRA2 ; Restore former RAM bank
+
+; Back to BASIC.
+
+ rts
+
+
+; ------------------------------------------------------------------------
+
+.segment "ONCE"
+
+init:
+
+; Change to the first RAM bank.
+
+ lda VIA1::PRA2
+ sta banksave ; Save the current bank number
+ lda #$00 ; Choose RAM bank zero
+ sta VIA1::PRA2
+
+; Save the zero-page locations that we need.
+
+ ldx #zpspace-1
+L1: lda sp,x
+ sta zpsave,x
+ dex
+ bpl L1
+
+; Set up the stack.
+
+ lda #<(__MAIN_START__ + __MAIN_SIZE__)
+ ldx #>(__MAIN_START__ + __MAIN_SIZE__)
+ sta sp
+ stx sp+1 ; Set argument stack ptr
+
+; Switch to the second charset.
+
+ lda #$0E
+ jsr BSOUT
+
+; Call the module constructors.
+
+ jmp initlib
+
+
+; ------------------------------------------------------------------------
+; Data
+
+.segment "INIT"
+
+banksave:
+ .res 1
+spsave: .res 1
+zpsave: .res zpspace
diff --git a/libsrc/cx16/devnum.s b/libsrc/cx16/devnum.s
new file mode 100644
index 00000000..6a59d6ec
--- /dev/null
+++ b/libsrc/cx16/devnum.s
@@ -0,0 +1,8 @@
+;
+; 2010-02-14, Oliver Schmidt
+; 2019-09-08, Greg King
+;
+
+ .include "cx16.inc"
+
+ .exportzp devnum := DEVNUM
diff --git a/libsrc/cx16/get_ostype.s b/libsrc/cx16/get_ostype.s
new file mode 100644
index 00000000..a778b6ea
--- /dev/null
+++ b/libsrc/cx16/get_ostype.s
@@ -0,0 +1,20 @@
+;
+; 2019-09-09, Greg King
+;
+; signed char get_ostype(void)
+; /* Return a "build version". */
+;
+; Positive number -- release build
+; Negative number -- prerelease build
+; -1 -- custom build
+;
+
+ .export _get_ostype
+
+.proc _get_ostype
+ ldx #>$0000
+ lda $ff80
+ bpl :+
+ dex ; negative
+: rts
+.endproc
diff --git a/libsrc/cx16/get_tv.s b/libsrc/cx16/get_tv.s
new file mode 100644
index 00000000..79a577df
--- /dev/null
+++ b/libsrc/cx16/get_tv.s
@@ -0,0 +1,31 @@
+;
+; 2019-09-20, Greg King
+;
+; unsigned char get_tv (void);
+; /* Return the video mode the machine is using. */
+;
+
+ .export _get_tv
+
+ .include "cx16.inc"
+
+
+.proc _get_tv
+ php
+ sei ; Don't let interrupts interfere
+
+ ; Point to the video output register.
+
+ stz VERA::CTRL ; Use port 0
+ lda #<VERA::COMPOSER::VIDEO
+ ldx #>VERA::COMPOSER::VIDEO
+ ldy #^VERA::COMPOSER::VIDEO
+ sta VERA::ADDR
+ stx VERA::ADDR+1
+ sty VERA::ADDR+2
+
+ lda VERA::DATA0
+ plp ; Re-enable interrupts
+ and #$07 ; Get the type of output signal
+ rts
+.endproc
diff --git a/libsrc/cx16/irq.s b/libsrc/cx16/irq.s
new file mode 100644
index 00000000..0d9d54c6
--- /dev/null
+++ b/libsrc/cx16/irq.s
@@ -0,0 +1,48 @@
+;
+; IRQ handling (CX16 version)
+;
+
+ .export initirq, doneirq
+ .import callirq
+
+ .include "cx16.inc"
+
+; ------------------------------------------------------------------------
+
+.segment "ONCE"
+
+initirq:
+ lda IRQVec
+ ldx IRQVec+1
+ sta IRQInd+1
+ stx IRQInd+2
+ lda #<IRQStub
+ ldx #>IRQStub
+ jmp setvec
+
+; ------------------------------------------------------------------------
+
+.code
+
+doneirq:
+ lda IRQInd+1
+ ldx IRQInd+2
+setvec: sei
+ sta IRQVec
+ stx IRQVec+1
+ cli
+ rts
+
+; ------------------------------------------------------------------------
+
+.segment "LOWCODE"
+
+IRQStub:
+ jsr callirq ; Call the functions
+ jmp IRQInd ; Jump to the saved IRQ vector
+
+; ------------------------------------------------------------------------
+
+.data
+
+IRQInd: jmp $0000
diff --git a/libsrc/cx16/joy/cx16-stdjoy.s b/libsrc/cx16/joy/cx16-stdjoy.s
new file mode 100644
index 00000000..8c7ddd2f
--- /dev/null
+++ b/libsrc/cx16/joy/cx16-stdjoy.s
@@ -0,0 +1,119 @@
+;
+; Standard joystick driver for the CX16.
+; May be used multiple times when statically linked to the application.
+;
+; 2019-09-23, Greg King
+;
+
+ .include "joy-kernel.inc"
+ .include "joy-error.inc"
+
+ .include "cbm_kernal.inc"
+ .include "cx16.inc"
+
+ .macpack generic
+ .macpack module
+
+
+; ------------------------------------------------------------------------
+; Header. Includes jump table
+
+ module_header _cx16_stdjoy_joy
+
+; Driver signature
+
+ .byte $6A, $6F, $79 ; ASCII "joy"
+ .byte JOY_API_VERSION ; Driver API version number
+
+; Library reference
+
+ .addr $0000
+
+; Jump table.
+
+ .addr INSTALL
+ .addr UNINSTALL
+ .addr COUNT
+ .addr READ
+
+; ------------------------------------------------------------------------
+; Constant
+
+JOY_COUNT = 2 ; Number of joysticks we support
+
+; ------------------------------------------------------------------------
+; Data.
+
+
+.code
+
+; ------------------------------------------------------------------------
+; INSTALL routine. Is called after the driver is loaded into memory.
+; If possible, check if the hardware is present, and determine the amount
+; of memory available.
+; Must return a JOY_ERR_xx code in a/x.
+;
+
+INSTALL:
+ lda #<JOY_ERR_OK
+ ldx #>JOY_ERR_OK
+; rts ; Run into UNINSTALL instead
+
+; ------------------------------------------------------------------------
+; UNINSTALL routine. Is called before the driver is removed from memory.
+; Can do clean-up or whatever. Must not return anything.
+;
+
+UNINSTALL:
+ rts
+
+; ------------------------------------------------------------------------
+; COUNT: Return the total number of possible joysticks in a/x.
+;
+
+COUNT: lda #<JOY_COUNT
+ ldx #>JOY_COUNT
+ rts
+
+; ------------------------------------------------------------------------
+; READ: Read a particular joystick passed in A.
+;
+; TODO: Find a way to report the SNES controller's extra four lines.
+;
+
+READ: pha
+ jsr GETJOY
+ pla
+ bne pad2
+
+; Read game pad 1
+
+pad1: lda JOY1 + 1
+ bit #%00001110
+ beq nes1
+ asl JOY1 ; Get SNES's B button
+ ror a ; Put it next to the A button
+ asl JOY1 ; Drop SNES's Y button
+ asl a ; Get the B button
+ ror JOY1
+ asl a ; Get SNES's A button
+ ror JOY1 ; Make byte look like NES pad
+nes1: lda JOY1
+ eor #%11111111 ; We don't want the pad's negative logic
+ rts
+
+; Read game pad 2
+
+pad2: lda JOY2 + 1
+ bit #%00001110
+ beq nes2
+ asl JOY2
+ ror a
+ asl JOY2
+ asl a
+ ror JOY2
+ asl a
+ ror JOY2
+nes2: lda JOY2
+ eor #%11111111
+ rts
diff --git a/libsrc/cx16/joy_stat_stddrv.s b/libsrc/cx16/joy_stat_stddrv.s
new file mode 100644
index 00000000..0e1a3e94
--- /dev/null
+++ b/libsrc/cx16/joy_stat_stddrv.s
@@ -0,0 +1,10 @@
+;
+; Address of the static standard joystick driver
+;
+; 2019-09-19, Greg King
+;
+; const void joy_static_stddrv[];
+;
+
+ .import _cx16_stdjoy_joy
+ .export _joy_static_stddrv := _cx16_stdjoy_joy
diff --git a/libsrc/cx16/joy_stddrv.s b/libsrc/cx16/joy_stddrv.s
new file mode 100644
index 00000000..4edf9afc
--- /dev/null
+++ b/libsrc/cx16/joy_stddrv.s
@@ -0,0 +1,13 @@
+;
+; Name of the standard joystick driver
+;
+; 2019-09-19, Greg King
+;
+; const char joy_stddrv[];
+;
+
+ .export _joy_stddrv
+
+.rodata
+
+_joy_stddrv: .asciiz "cx16-stdjoy.joy"
diff --git a/libsrc/cx16/kbhit.s b/libsrc/cx16/kbhit.s
new file mode 100644
index 00000000..8ceba64b
--- /dev/null
+++ b/libsrc/cx16/kbhit.s
@@ -0,0 +1,17 @@
+;
+; 2019-09-20, Greg King
+;
+; unsigned char kbhit (void);
+; /* Returns non-zero (true) if a typed character is waiting. */
+;
+
+ .export _kbhit
+
+ .include "cx16.inc"
+
+
+.proc _kbhit
+ ldx #>$0000 ; High byte of return
+ lda KEY_COUNT ; Get number of characters
+ rts
+.endproc
diff --git a/libsrc/cx16/kernal.s b/libsrc/cx16/kernal.s
new file mode 100644
index 00000000..faf91385
--- /dev/null
+++ b/libsrc/cx16/kernal.s
@@ -0,0 +1,59 @@
+;
+; 2019-09-22, Greg King
+;
+; CX16 Kernal functions
+;
+
+ .include "cbm_kernal.inc"
+
+ .export GETJOY
+
+ .export CLSALL
+ .export SWAPPER
+ .export JSRFAR
+ .export INDFET
+ .export INDSTA
+ .export INDCMP
+ .export PRIMM
+
+ .export CINT
+ .export IOINIT
+ .export RAMTAS
+ .export RESTOR
+ .export VECTOR
+ .export SETMSG
+ .export SECOND
+ .export TKSA
+ .export MEMTOP
+ .export MEMBOT
+ .export SCNKEY
+ .export SETTMO
+ .export ACPTR
+ .export CIOUT
+ .export UNTLK
+ .export UNLSN
+ .export LISTEN
+ .export TALK
+ .export READST
+ .export SETLFS
+ .export SETNAM
+ .export OPEN
+ .export CLOSE
+ .export CHKIN
+ .export CKOUT
+ .export CLRCH
+ .export BASIN
+ .export CHRIN
+ .export BSOUT
+ .export CHROUT
+ .export LOAD
+ .export SAVE
+ .export SETTIM
+ .export RDTIM
+ .export STOP
+ .export GETIN
+ .export CLALL
+ .export UDTIM
+ .export SCREEN
+ .export PLOT
+ .export IOBASE
diff --git a/libsrc/cx16/libref.s b/libsrc/cx16/libref.s
new file mode 100644
index 00000000..54ebb91d
--- /dev/null
+++ b/libsrc/cx16/libref.s
@@ -0,0 +1,18 @@
+;
+; 2013-05-31, Oliver Schmidt
+; 2019-09-22, Greg King
+;
+
+ .export em_libref
+ .export joy_libref
+ .export mouse_libref
+ .export ser_libref
+ .export tgi_libref
+
+ .import _exit
+
+em_libref := _exit
+joy_libref := _exit
+mouse_libref := _exit
+ser_libref := _exit
+tgi_libref := _exit
diff --git a/libsrc/cx16/mainargs.s b/libsrc/cx16/mainargs.s
new file mode 100644
index 00000000..fe4a071c
--- /dev/null
+++ b/libsrc/cx16/mainargs.s
@@ -0,0 +1,137 @@
+; mainargs.s
+;
+; Ullrich von Bassewitz, 2003-03-07
+; Based on code from Stefan A. Haubenthal, <polluks@web.de>
+; 2005-02-26, Ullrich von Bassewitz
+; 2019-09-08, Greg King
+;
+; Scan a group of arguments that are in BASIC's input-buffer.
+; Build an array that points to the beginning of each argument.
+; Send, to main(), that array and the count of the arguments.
+;
+; Command-lines look like these lines:
+;
+; run
+; run : rem
+; run:rem arg1 " arg 2 is quoted " arg3 "" arg5
+;
+; "run" and "rem" are entokenned; the args. are not. Leading and trailing
+; spaces outside of quotes are ignored.
+;
+; TO-DO:
+; - The "file-name" might be a path-name; don't copy the directory-components.
+; - Add a control-character quoting mechanism.
+
+ .constructor initmainargs, 24
+ .import __argc, __argv
+
+ .include "cx16.inc"
+
+
+MAXARGS = 10 ; Maximum number of arguments allowed
+REM = $8f ; BASIC token-code
+NAME_LEN = 16 ; Maximum length of command-name
+
+; Get possible command-line arguments. Goes into the special ONCE segment,
+; which may be reused after the startup code is run
+
+.segment "ONCE"
+
+initmainargs:
+
+; Assume that the program was loaded, a moment ago, by the traditional LOAD
+; statement. Save the "most-recent filename" as argument #0.
+
+ lda #0 ; The terminating NUL character
+ ldy FNAM_LEN
+ cpy #NAME_LEN + 1
+ bcc L1
+ ldy #NAME_LEN ; Limit the length
+ bne L1 ; Branch always
+L0: lda (FNAM),y
+L1: sta name,y
+ dey
+ bpl L0
+ inc __argc ; argc always is equal to, at least, 1
+
+; Find the "rem" token.
+
+ ldx #0
+L2: lda BASIC_BUF,x
+ beq done ; No "rem," no args.
+ inx
+ cmp #REM
+ bne L2
+ ldy #1 * 2
+
+; Find the next argument
+
+next: lda BASIC_BUF,x
+ beq done ; End of line reached
+ inx
+ cmp #' ' ; Skip leading spaces
+ beq next
+
+; Found start of next argument. We've incremented the pointer in X already, so
+; it points to the second character of the argument. This is useful since we
+; will check now for a quoted argument, in which case we will have to skip this
+; first character.
+
+found: cmp #'"' ; Is the argument quoted?
+ beq setterm ; Jump if so
+ dex ; Reset pointer to first argument character
+ lda #' ' ; A space ends the argument
+setterm:sta term ; Set end of argument marker
+
+; Now store a pointer to the argument into the next slot. Since the BASIC
+; input buffer is located at the start of a RAM page, no calculations are
+; necessary.
+
+ txa ; Get low byte
+ sta argv,y ; argv[y]= &arg
+ iny
+ lda #>BASIC_BUF
+ sta argv,y
+ iny
+ inc __argc ; Found another arg
+
+; Search for the end of the argument
+
+argloop:lda BASIC_BUF,x
+ beq done
+ inx
+ cmp term
+ bne argloop
+
+; We've found the end of the argument. X points one character behind it, and
+; A contains the terminating character. To make the argument a valid C string,
+; replace the terminating character by a zero.
+
+ lda #0
+ sta BASIC_BUF-1,x
+
+; Check if the maximum number of command line arguments is reached. If not,
+; parse the next one.
+
+ lda __argc ; Get low byte of argument count
+ cmp #MAXARGS ; Maximum number of arguments reached?
+ bcc next ; Parse next one if not
+
+; (The last vector in argv[] already is NULL.)
+
+done: lda #<argv
+ ldx #>argv
+ sta __argv
+ stx __argv + 1
+ rts
+
+.segment "INIT"
+
+term: .res 1
+name: .res NAME_LEN + 1
+
+.data
+
+; char* argv[MAXARGS+1]={name};
+argv: .addr name
+ .res MAXARGS * 2
diff --git a/libsrc/cx16/revers.s b/libsrc/cx16/revers.s
new file mode 100644
index 00000000..300237ee
--- /dev/null
+++ b/libsrc/cx16/revers.s
@@ -0,0 +1,23 @@
+;
+; 2019-09-16, Greg King
+;
+; unsigned char __fastcall__ revers (unsigned char onoff);
+;
+
+ .export _revers
+
+ .include "cx16.inc"
+
+.proc _revers
+ ldy #$00 ; Assume revers off
+ tax ; Test on/off
+ beq :+ ; Jump if off
+ ldy #$80 ; Load "on" value
+ ldx #>$0000 ; Zero high byte of result
+: lda RVS ; Load old value
+ sty RVS ; Set new value
+ clc
+ rol a ; Convert bit-mask into boolean
+ rol a
+ rts
+.endproc
diff --git a/libsrc/cx16/set_tv.s b/libsrc/cx16/set_tv.s
new file mode 100644
index 00000000..0cf49aff
--- /dev/null
+++ b/libsrc/cx16/set_tv.s
@@ -0,0 +1,32 @@
+;
+; 2019-09-20, Greg King
+;
+; void __fastcall__ set_tv (unsigned char);
+; /* Set the video mode the machine will use. */
+;
+
+ .export _set_tv
+
+ .include "cx16.inc"
+
+
+.proc _set_tv
+ php
+ pha
+ sei ; Don't let interrupts interfere
+
+ ; Point to the video output register.
+
+ stz VERA::CTRL ; Use port 0
+ lda #<VERA::COMPOSER::VIDEO
+ ldx #>VERA::COMPOSER::VIDEO
+ ldy #^VERA::COMPOSER::VIDEO
+ sta VERA::ADDR
+ stx VERA::ADDR+1
+ sty VERA::ADDR+2
+
+ pla
+ sta VERA::DATA0
+ plp ; Re-enable interrupts
+ rts
+.endproc
diff --git a/libsrc/cx16/status.s b/libsrc/cx16/status.s
new file mode 100644
index 00000000..6292dc27
--- /dev/null
+++ b/libsrc/cx16/status.s
@@ -0,0 +1,6 @@
+;
+; 2012-09-30, Oliver Schmidt
+; 2019-09-08, Greg King
+;
+
+ .exportzp ST := $90 ; IEC status byte
diff --git a/libsrc/cx16/sysuname.s b/libsrc/cx16/sysuname.s
new file mode 100644
index 00000000..f8500936
--- /dev/null
+++ b/libsrc/cx16/sysuname.s
@@ -0,0 +1,37 @@
+;
+; 2003-08-12, Ullrich von Bassewitz
+; 2019-09-08, Greg King
+;
+; unsigned char __fastcall__ _sysuname (struct utsname* buf);
+;
+
+ .export __sysuname, utsdata
+
+ .import utscopy
+
+__sysuname := utscopy
+
+;--------------------------------------------------------------------------
+; Data. We define a fixed utsname struct here, and just copy it.
+
+.rodata
+
+utsdata:
+ ; sysname
+ .asciiz "cc65"
+
+ ; nodename
+ .asciiz ""
+
+ ; release
+ .byte ((.VERSION >> 8) & $0F) + '0'
+ .byte '.'
+ .byte ((.VERSION >> 4) & $0F) + '0'
+ .byte $00
+
+ ; version
+ .byte (.VERSION & $0F) + '0'
+ .byte $00
+
+ ; machine
+ .asciiz "Commander X16"
diff --git a/libsrc/cx16/videomode.s b/libsrc/cx16/videomode.s
new file mode 100644
index 00000000..4582ec1b
--- /dev/null
+++ b/libsrc/cx16/videomode.s
@@ -0,0 +1,30 @@
+;
+; 2009-09-07, Ullrich von Bassewitz
+; 2019-09-23, Greg King
+;
+; unsigned __fastcall__ videomode (unsigned Mode);
+; /* Set the video mode, return the old mode. */
+;
+
+ .export _videomode
+ .import SWAPPER
+
+ .include "cx16.inc"
+
+
+.proc _videomode
+ cmp LLEN ; Do we have this mode already?
+ beq @L9
+
+ lda LLEN ; Get current mode ...
+ pha ; ... and save it
+
+ jsr SWAPPER ; Toggle the mode
+
+ pla ; Get old mode into A
+
+; Done, old mode is in .A
+
+@L9: ldx #>$0000 ; Clear high byte
+ rts
+.endproc
diff --git a/libsrc/cx16/waitvsync.s b/libsrc/cx16/waitvsync.s
new file mode 100644
index 00000000..3fb6354f
--- /dev/null
+++ b/libsrc/cx16/waitvsync.s
@@ -0,0 +1,17 @@
+;
+; 2019-09-26, Greg King
+;
+; void waitvsync (void);
+;
+; VERA's vertical sync. causes IRQs which increment the jiffy clock.
+;
+
+ .export _waitvsync
+
+ .include "cx16.inc"
+
+_waitvsync:
+ lda TIME + 2
+: cmp TIME + 2
+ beq :- ; Wait for next jiffy
+ rts
diff --git a/src/ca65/main.c b/src/ca65/main.c
index 33e0a74b..ab19d0b4 100644
--- a/src/ca65/main.c
+++ b/src/ca65/main.c
@@ -296,7 +296,7 @@ static void SetSys (const char* Sys)
case TGT_ATMOS:
NewSymbol ("__ATMOS__", 1);
- break;
+ break;
case TGT_TELESTRAT:
NewSymbol ("__TELESTRAT__", 1);
@@ -330,6 +330,10 @@ static void SetSys (const char* Sys)
NewSymbol ("__PCE__", 1);
break;
+ case TGT_CX16:
+ CBMSystem ("__CX16__");
+ break;
+
default:
AbEnd ("Invalid target name: '%s'", Sys);
diff --git a/src/cc65/main.c b/src/cc65/main.c
index 871e21eb..a4f794fb 100644
--- a/src/cc65/main.c
+++ b/src/cc65/main.c
@@ -285,6 +285,10 @@ static void SetSys (const char* Sys)
DefineNumericMacro ("__PCE__", 1);
break;
+ case TGT_CX16:
+ cbmsys ("__CX16__");
+ break;
+
default:
AbEnd ("Unknown target system type %d", Target);
}
diff --git a/src/common/target.c b/src/common/target.c
index 56ea0a2f..a21ef212 100644
--- a/src/common/target.c
+++ b/src/common/target.c
@@ -135,11 +135,11 @@ static const unsigned char CTPET[256] = {
typedef struct TargetEntry TargetEntry;
struct TargetEntry {
char Name[13]; /* Target name */
- target_t Id; /* Target id */
+ target_t Id; /* Target ID */
};
-/* Table that maps target names to ids. Sorted alphabetically for bsearch.
-** Allows multiple entries for one target id (target name aliases).
+/* Table that maps target names to IDs. Sorted alphabetically for bsearch().
+** Allows multiple entries for one target ID (target name aliases).
*/
static const TargetEntry TargetMap[] = {
{ "apple2", TGT_APPLE2 },
@@ -157,6 +157,7 @@ static const TargetEntry TargetMap[] = {
{ "cbm510", TGT_CBM510 },
{ "cbm610", TGT_CBM610 },
{ "creativision", TGT_CREATIVISION },
+ { "cx16", TGT_CX16 },
{ "gamate", TGT_GAMATE },
{ "geos", TGT_GEOS_CBM },
{ "geos-apple", TGT_GEOS_APPLE },
@@ -179,7 +180,7 @@ static const TargetEntry TargetMap[] = {
#define MAP_ENTRY_COUNT (sizeof (TargetMap) / sizeof (TargetMap[0]))
-/* Table with target properties by target id */
+/* Table with target properties by target ID */
static const TargetProperties PropertyTable[TGT_COUNT] = {
{ "none", CPU_6502, BINFMT_BINARY, CTNone },
{ "module", CPU_6502, BINFMT_O65, CTNone },
@@ -213,6 +214,7 @@ static const TargetProperties PropertyTable[TGT_COUNT] = {
{ "pce", CPU_HUC6280, BINFMT_BINARY, CTNone },
{ "gamate", CPU_6502, BINFMT_BINARY, CTNone },
{ "c65", CPU_4510, BINFMT_BINARY, CTPET },
+ { "cx16", CPU_65C02, BINFMT_BINARY, CTPET },
};
/* Target system */
@@ -235,7 +237,7 @@ static int Compare (const void* Key, const void* Entry)
target_t FindTarget (const char* Name)
-/* Find a target by name and return the target id. TGT_UNKNOWN is returned if
+/* Find a target by name and return the target ID. TGT_UNKNOWN is returned if
** the given name is no valid target.
*/
{
@@ -243,7 +245,7 @@ target_t FindTarget (const char* Name)
const TargetEntry* T;
T = bsearch (Name, TargetMap, MAP_ENTRY_COUNT, sizeof (TargetMap[0]), Compare);
- /* Return the target id */
+ /* Return the target ID */
return (T == 0)? TGT_UNKNOWN : T->Id;
}
@@ -252,7 +254,7 @@ target_t FindTarget (const char* Name)
const TargetProperties* GetTargetProperties (target_t Target)
/* Return the properties for a target */
{
- /* Must have a valid target id */
+ /* Must have a valid target ID */
PRECONDITION (Target >= 0 && Target < TGT_COUNT);
/* Return the array entry */
diff --git a/src/common/target.h b/src/common/target.h
index 5b086e40..50c400e2 100644
--- a/src/common/target.h
+++ b/src/common/target.h
@@ -84,6 +84,7 @@ typedef enum {
TGT_PCENGINE,
TGT_GAMATE,
TGT_C65,
+ TGT_CX16,
TGT_COUNT /* Number of target systems */
} target_t;
@@ -102,7 +103,7 @@ extern target_t Target;
/* Types of available output formats */
#define BINFMT_DEFAULT 0 /* Default (binary) */
#define BINFMT_BINARY 1 /* Straight binary format */
-#define BINFMT_O65 2 /* Andre Fachats o65 format */
+#define BINFMT_O65 2 /* Andre Fachat's o65 format */
#define BINFMT_ATARIEXE 3 /* Standard Atari binary load */
@@ -127,5 +128,4 @@ const char* GetTargetName (target_t Target);
/* End of target.h */
-
#endif
diff --git a/testcode/lib/joy-test.c b/testcode/lib/joy-test.c
index 3d584bf9..53d63c5c 100644
--- a/testcode/lib/joy-test.c
+++ b/testcode/lib/joy-test.c
@@ -1,4 +1,3 @@
-#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
@@ -14,16 +13,15 @@
# define DYN_DRV 0
/*
-** link existing drivers like this:
+** Link existing drivers this way:
**
** cl65 -DJOYSTICK_DRIVER=c64_hitjoy_joy -o joy-test.prg joy-test.c
**
-** for testing a new driver you will have to uncomment the define below, and
-** link your driver like this:
+** For testing a new driver, you need to uncomment the declaration below,
+** and link your driver this way:
**
** co65 ../../target/c64/drv/joy/c64-hitjoy.joy -o hitjoy.s --code-label _hitjoy
** cl65 -DJOYSTICK_DRIVER=hitjoy -o joy-test.prg joy-test.c hitjoy.s
-**
*/
/* extern char JOYSTICK_DRIVER; */
@@ -40,10 +38,8 @@
int main (void)
{
unsigned char j;
- unsigned char count;
- unsigned char i;
+ unsigned char i, count;
unsigned char Res;
- unsigned char ch, kb;
clrscr ();
@@ -58,47 +54,69 @@ int main (void)
if (Res != JOY_ERR_OK) {
cprintf ("Error in joy_load_driver: %u\r\n", Res);
#if DYN_DRV
- cprintf ("os: %u, %s\r\n", _oserror, _stroserror (_oserror));
+ cprintf ("OS: %u, %s\r\n", _oserror, _stroserror (_oserror));
#endif
- exit (EXIT_FAILURE);
+ return EXIT_FAILURE;
}
count = joy_count ();
#if defined(__ATARI5200__) || defined(__CREATIVISION__)
- cprintf ("JOYSTICKS: %d", count);
+ cprintf ("JOYSTICKS: %u.", count);
#else
- cprintf ("Driver supports %d joystick(s)", count);
+ cprintf ("Driver supports %u joystick%s", count, count == 1 ? "." : "s.");
#endif
while (1) {
for (i = 0; i < count; ++i) {
- gotoxy (0, i+1);
j = joy_read (i);
-#if defined(__ATARI5200__) || defined(__CREATIVISION__)
- cprintf ("%1d:%-3s%-3s%-3s%-3s%-3s %02x",
+#if defined(__NES__) || defined(__CX16__)
+ /* two lines for each device */
+ gotoxy (0, i * 2 +1);
+ cprintf ("%2u:%-6s%-6s%-6s%-6s\r\n"
+ " %-6s%-6s%-6s%-6s $%02X",
i,
- JOY_UP(j)? " U " : " - ",
- JOY_DOWN(j)? " D " : " - ",
- JOY_LEFT(j)? " L " : " - ",
- JOY_RIGHT(j)? " R " : " - ",
- JOY_BTN_1(j)? " 1 " : " - ", j);
+ JOY_UP(j) ? " up " : " ---- ",
+ JOY_DOWN(j) ? " down " : " ---- ",
+ JOY_LEFT(j) ? " left " : " ---- ",
+ JOY_RIGHT(j) ? " right" : " ---- ",
+ JOY_BTN_1(j) ? "btn A " : " ---- ",
+ JOY_BTN_2(j) ? "btn B " : " ---- ",
+ JOY_BTN_3(j) ? "select" : " ---- ",
+ JOY_BTN_4(j) ? " start" : " ---- ",
+ j);
#else
- cprintf ("%2d: %-6s%-6s%-6s%-6s%-6s %02x",
+ /* one line for each device */
+ gotoxy (0, i + 1);
+# if defined(__ATARI5200__) || defined(__CREATIVISION__)
+ cprintf ("%1u:%-3s%-3s%-3s%-3s%-3s %02X",
i,
- JOY_UP(j)? " up " : " ---- ",
- JOY_DOWN(j)? " down " : " ---- ",
- JOY_LEFT(j)? " left " : " ---- ",
- JOY_RIGHT(j)? "right " : " ---- ",
- JOY_BTN_1(j)? "button" : " ---- ", j);
+ JOY_UP(j) ? " U " : " - ",
+ JOY_DOWN(j) ? " D " : " - ",
+ JOY_LEFT(j) ? " L " : " - ",
+ JOY_RIGHT(j) ? " R " : " - ",
+ JOY_BTN_1(j) ? " 1 " : " - ",
+ j);
+# else
+ cprintf ("%2u: %-6s%-6s%-6s%-6s%-6s $%02X",
+ i,
+ JOY_UP(j) ? " up " : " ---- ",
+ JOY_DOWN(j) ? " down " : " ---- ",
+ JOY_LEFT(j) ? " left " : " ---- ",
+ JOY_RIGHT(j) ? "right " : " ---- ",
+ JOY_BTN_1(j) ? "button" : " ---- ",
+ j);
+# endif
#endif
}
- /* show pressed key, so we can verify keyboard is working */
- kb = kbhit ();
- ch = kb ? cgetc () : ' ';
- gotoxy (1, i+2);
- revers (kb);
- cprintf ("kbd: %c", ch);
- revers (0);
+ /* Show any pressed keys; so that we can verify that the keyboard is working. */
+ if (kbhit ()) {
+#if defined(__NES__) || defined(__CX16__)
+ gotoxy (1, i * 2 + 2);
+#else
+ gotoxy (1, i + 2);
+#endif
+ cprintf ("keyboard: $%02X", cgetc ());
+ }
}
- return 0;
+ return EXIT_SUCCESS;
}
--
2.26.0