diff --git a/asminc/cbm_kernal.inc b/asminc/cbm_kernal.inc index 29a6e5ddf..79edce06b 100644 --- a/asminc/cbm_kernal.inc +++ b/asminc/cbm_kernal.inc @@ -1,30 +1,45 @@ ; ; Olli Savia ; -; 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 000000000..6f3f1c731 --- /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 000000000..53f6da176 --- /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 000000000..52438fbac --- /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 000000000..f912e0f83 --- /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 8a5e307d8..ad72189c0 100644 --- a/doc/ca65.sgml +++ b/doc/ca65.sgml @@ -4653,9 +4653,10 @@ compiler, depending on the target system selected: + __CX16__ + + This macro is defined if the target is the Commander X16 (-t cx16). + __DATE__ 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 000000000..077458bf6 --- /dev/null +++ b/doc/cx16.sgml @@ -0,0 +1,311 @@ + + +
+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 aecfb7de9..01325529d 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 994d30bc0..b2b141d10 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 0a2d64694..d9b31543f 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 000000000..db32d8460 --- /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 0ebec46b1..d9ddb3ccd 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 000000000..8059f04d9 --- /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 000000000..53d96e916 --- /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 000000000..6691e2ec5 --- /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 000000000..ec569b9a7 --- /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 000000000..14cad5f5a --- /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 000000000..51fae6bf2 --- /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 000000000..1be01c473 --- /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 000000000..e760af21c --- /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 000000000..2f02623bf --- /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 000000000..4e3a39a2c --- /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 000000000..d67dd2956 --- /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 000000000..e69de29bb diff --git a/libsrc/cx16/cputc.s b/libsrc/cx16/cputc.s new file mode 100644 index 000000000..cf0a5fa22 --- /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 000000000..181e63081 --- /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 000000000..6a59d6ecd --- /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 000000000..a778b6eae --- /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 000000000..79a577dff --- /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 000000000..0d9d54c60 --- /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 000000000..8c7ddd2f2 --- /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 000000000..0e1a3e94d --- /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 000000000..4edf9afc0 --- /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 000000000..8ceba64be --- /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 000000000..faf91385a --- /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 000000000..54ebb91d2 --- /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 000000000..fe4a071c7 --- /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 000000000..300237ee8 --- /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 000000000..0cf49aff7 --- /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 000000000..6292dc274 --- /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 000000000..f8500936b --- /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 000000000..4582ec1bd --- /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 000000000..3fb6354f0 --- /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 33e0a74b5..ab19d0b4d 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 871e21ebc..a4f794fb5 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 56ea0a2ff..a21ef2125 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 5b086e40c..50c400e2e 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 3d584bf9d..53d63c5ce 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; }