Updated cx16 to match the Commander X16 ROMs and emulator, release 34.

This commit is contained in:
Greg King
2019-11-16 13:11:40 -05:00
parent 4dda5d2173
commit d78133e1f0
37 changed files with 607 additions and 182 deletions

View File

@@ -1,6 +1,6 @@
;
; 1998-09-27, Ullrich von Bassewitz
; 2019-09-08, Greg King
; 2019-11-06, Greg King
;
; void __fastcall__ set_brk (unsigned Addr);
; void reset_brk (void);
@@ -30,6 +30,7 @@ uservec: jmp $FFFF ; Patched at runtime
.code
; Set the break vector
.proc _set_brk
sta uservec+1
@@ -40,9 +41,9 @@ uservec: jmp $FFFF ; Patched at runtime
bne L1 ; Jump if we installed the handler already
lda BRKVec
ldx BRKVec+1
sta oldvec
lda BRKVec+1
sta oldvec+1 ; Save the old vector
stx oldvec+1 ; Save the old vector
L1: lda #<brk_handler ; Set the break vector to our routine
ldx #>brk_handler
@@ -54,6 +55,7 @@ L1: lda #<brk_handler ; Set the break vector to our routine
; Reset the break vector
.proc _reset_brk
lda oldvec
@@ -61,15 +63,15 @@ L1: lda #<brk_handler ; Set the break vector to our routine
beq @L9 ; Jump if vector not installed
sta BRKVec
stx BRKVec+1
lda #$00
sta oldvec ; Clear the old vector
stx oldvec+1
sta oldvec+1
@L9: rts
.endproc
; Break handler, called if a break occurs
.proc brk_handler
@@ -81,14 +83,13 @@ L1: lda #<brk_handler ; Set the break vector to our routine
pla
sta _brk_a
pla
and #$EF ; Clear break bit
sta _brk_sr
pla ; PC low
sec
sbc #2 ; Point to start of brk
sbc #<$0002 ; Point to start of BRK
sta _brk_pc
pla ; PC high
sbc #0
sbc #>$0002
sta _brk_pc+1
jsr uservec ; Call the user's routine
@@ -99,11 +100,9 @@ L1: lda #<brk_handler ; Set the break vector to our routine
pha
lda _brk_sr
pha
ldx _brk_x
ldy _brk_y
ldx _brk_x
lda _brk_a
rti ; Jump back...
.endproc

View File

@@ -1,9 +0,0 @@
;
; 2019-09-23, Greg King
;
; Low-level stuff for screen output/console input
;
.exportzp CURS_X, CURS_Y
.include "cx16.inc"

View File

@@ -19,7 +19,7 @@ _cpeekc:
sta VERA::ADDR+1 ; set row number
stz VERA::ADDR+2
lda CURS_X ; get character column
asl a
asl a ; each character has two bytes
sta VERA::ADDR
lda VERA::DATA0 ; get screen code
plp

View File

@@ -21,7 +21,7 @@ _cpeekrevers:
sta VERA::ADDR+1 ; set row number
stz VERA::ADDR+2
lda CURS_X ; get character column
asl a
asl a ; each character has two bytes
sta VERA::ADDR
lda VERA::DATA0 ; get screen code
plp

View File

@@ -78,7 +78,7 @@ plot: ldy CURS_X
; Write one screen-code and color to the video RAM without doing anything else.
; Return the x position in Y.
; Return the x position in .Y .
putchar:
ora RVS ; Set revers bit
@@ -90,7 +90,7 @@ putchar:
sta VERA::ADDR+2
ldy CURS_X ; Get character column
tya
asl a
asl a ; Each character has two bytes
sta VERA::ADDR
stx VERA::DATA0
lda CHARCOLOR

View File

@@ -9,7 +9,6 @@
.import zerobss, callmain
.import CHROUT
.import __MAIN_START__, __MAIN_SIZE__ ; Linker-generated
.importzp ST
.include "zeropage.inc"
.include "cx16.inc"
@@ -36,11 +35,18 @@ Start: tsx
jsr callmain
; Back from main() [this is also the exit() entry]. Run the module destructors.
; Back from main() [this is also the exit() entry].
_exit:
; Put the program return code into BASIC's status variable.
sta STATUS
; Run the module destructors.
_exit: pha ; Save the return code on stack
jsr donelib
.if 0 ; We no longer need to preserve zero-page space for cc65's variables.
; Copy back the zero-page stuff.
ldx #zpspace-1
@@ -48,11 +54,7 @@ L2: lda zpsave,x
sta sp,x
dex
bpl L2
; Place the program return code into BASIC's status variable.
pla
sta ST
.endif
; Restore the system stuff.
@@ -88,6 +90,7 @@ init:
lda #$00 ; Choose RAM bank zero
sta VIA1::PRA2
.if 0 ; We no longer need to preserve zero-page space for cc65's variables.
; Save the zero-page locations that we need.
ldx #zpspace-1
@@ -95,6 +98,7 @@ L1: lda sp,x
sta zpsave,x
dex
bpl L1
.endif
; Set up the stack.
@@ -121,4 +125,6 @@ L1: lda sp,x
ramsave:
.res 1
spsave: .res 1
.if 0
zpsave: .res zpspace
.endif

View File

@@ -1,8 +0,0 @@
;
; 2010-02-14, Oliver Schmidt
; 2019-09-08, Greg King
;
.include "cx16.inc"
.exportzp devnum := DEVNUM

122
libsrc/cx16/exec.c Normal file
View File

@@ -0,0 +1,122 @@
/*
** Program-chaining function for Commodore platforms.
**
** 2019-11-08, Greg King
**
** This function exploits the program-chaining feature in Commander X16 BASIC's ROM.
**
** CC65's CBM programs have a BASIC program stub. We start those programs by
** RUNning that stub; it SYSes to the Machine Language code. Normally, after
** the ML code exits, the BASIC ROM continues running the stub. But, it has
** no more statements; so, the program stops.
**
** This function puts the desired program's name and device number into a LOAD
** statement. Then, it points BASIC to that statement, so that the ROM will run
** that statement after this program quits. The ROM will load the next program,
** and will execute it (because the LOAD will be seen in a running program).
*/
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <device.h>
/* The struct below is a line of BASIC code. It sits in the LOWCODE segment
** to make sure that it won't be hidden by a ROM when BASIC is re-enabled.
** The line is:
** 0 CLR:LOAD""+"" ,01
** After this function has written into the line, it might look like this:
** 0 CLR:LOAD""+"program name" ,08
**
** When BASIC's LOAD command asks the Kernal to load a file, it gives the
** Kernal a pointer to a file-name string. CC65's CBM programs use that
** pointer to give a copy of the program's name to main()'s argv[0] parameter.
** But, when BASIC uses a string literal that is in a program, it points
** directly to that literal -- in the models that don't use banked RAM
** (Pet/CBM, VIC-20, and 64). The literal is overwritten by the next program
** that is loaded. So, argv[0] would point to machine code. String operations
** create a new result string -- even when that operation changes nothing. The
** result is put in the string space at the top of BASIC's memory. So, the ""+
** in this BASIC line guarantees that argv[0] will get a name from a safe place.
*/
#pragma data-name(push, "LOWCODE")
static struct line {
const char end_of_line; /* fake previous line */
const struct line* const next;
const unsigned line_num;
const char CLR_token, colon, LOAD_token, quotes[2], add_token, quote;
char name[21];
const char comma;
char unit[3];
} basic = {
'\0', &basic + 1, /* high byte of link must be non-zero */
0, 0x9C, ':', 0x93, "\"\"", 0xAA, '\"',
"\" ", /* format: "123:1234567890123456\"" */
',', "01"
};
#pragma data-name(pop)
/* These values are platform-specific. */
extern const void* vartab; /* points to BASIC program variables */
extern const void* memsize; /* points to top of BASIC RAM */
extern const struct line* txtptr; /* points to BASIC code */
#pragma zpsym("txtptr")
extern char basbuf[]; /* BASIC's input buffer */
extern void basbuf_len[];
#pragma zpsym("basbuf_len")
int __fastcall__ exec (const char* progname, const char* cmdline)
{
static int fd;
static unsigned char dv, n;
/* Exclude devices that can't load files. */
/* (Use hand optimization, to make smaller code.) */
dv = getcurrentdevice ();
if (dv < 8 && __AX__ != 1 || __AX__ > 30) {
return _mappederrno (9); /* illegal device number */
}
utoa (dv, basic.unit, 10);
/* Don't try to run a program that doesn't exist. */
fd = open (progname, O_RDONLY);
if (fd < 0) {
return _mappederrno (4); /* file not found */
}
close (fd);
n = 0;
do {
if ((basic.name[n] = progname[n]) == '\0') {
break;
}
} while (++n < 20); /* truncate long names */
basic.name[n] = '\"';
/* cc65 program loads might extend beyond the end of the RAM that is allowed
** for BASIC. Then, the LOAD statement would complain that it is "out of
** memory". Some pointers that say where to put BASIC program variables
** must be changed, so that we do not get that error. One pointer is
** changed here; a BASIC CLR statement changes the others.
*/
vartab = (char*)memsize - 256;
/* Build the next program's argument list. */
basbuf[0] = 0x8F; /* REM token */
basbuf[1] = '\0';
if (cmdline != NULL) {
strncat (basbuf, cmdline, (size_t)basbuf_len - 2);
}
/* Tell the ROM where to find that BASIC program. */
txtptr = &basic;
/* (The return code, in STATUS, will be destroyed by LOAD.
** So, don't bother to set it here.)
*/
exit (__AX__);
}

16
libsrc/cx16/execvars.s Normal file
View File

@@ -0,0 +1,16 @@
;
; Platform-specific variables for the exec program-chaining function
;
.include "cx16.inc"
; exec() is written in C.
; Provide the spellings that the C compiler wants to use.
.export _vartab := VARTAB
.export _memsize := MEMSIZE
.exportzp _txtptr := TXTPTR
.export _basbuf := BASIC_BUF
.exportzp _basbuf_len = BASIC_BUF_LEN

39
libsrc/cx16/filevars.s Normal file
View File

@@ -0,0 +1,39 @@
;
; 2002-11-15, Ullrich von Bassewitz
; 2019-11-08, Greg King
;
; Variables used for CBM file I/O
;
.export curunit
.constructor initcurunit, 30
.destructor updatedevnum, 30
.include "cx16.inc"
.segment "INIT"
curunit:
.res 1
.segment "ONCE"
.proc initcurunit
lda DEVNUM
bne L0
lda #8 ; Default is SD card
sta DEVNUM
L0: sta curunit
rts
.endproc
.code
.proc updatedevnum
lda curunit
sta DEVNUM
rts
.endproc

67
libsrc/cx16/getdevice.s Normal file
View File

@@ -0,0 +1,67 @@
;
; 2012-09-04, Oliver Schmidt
; 2019-11-08, Greg King
;
; unsigned char getfirstdevice (void);
; unsigned char __fastcall__ getnextdevice (unsigned char device);
;
.export _getfirstdevice
.export _getnextdevice
.import isdisk
.import opencmdchannel
.import closecmdchannel
.importzp tmp2
.include "cx16.inc"
;------------------------------------------------------------------------------
; getfirstdevice()
_getfirstdevice:
lda #$FF
; Fall through
;------------------------------------------------------------------------------
; getnextdevice()
_getnextdevice:
tax
next: inx
cpx #$FF
beq done
; [open|close]cmdchannel already call isdisk internally; but, they
; interpret a non-disk as a no-op, while we need to interpret it
; as an error here.
jsr isdisk
bcs next
; [open|close]cmdchannel don't call into the Kernal, at all, if they
; only [in|de]crement the reference count of the shared cmdchannel.
; Therefore, we need to initiate STATUS explicitly here.
lda #$00
sta STATUS
stx tmp2
jsr opencmdchannel
ldx tmp2
jsr closecmdchannel
ldx tmp2
; As we had to reference ST above anyway, we can do so, as well,
; here too (instead of calling READST).
lda STATUS
; Either the Kernal calls above were successfull, or there was
; already a cmdchannel to the device open -- which is a pretty
; good indication of its existence. ;-)
bmi next
done: txa
ldx #$00
rts

13
libsrc/cx16/gotox.s Normal file
View File

@@ -0,0 +1,13 @@
;
; 2019-11-06, Greg King
;
; void fastcall gotox (unsigned char x);
;
.export _gotox
.import plot
.include "cx16.inc"
_gotox: sta CURS_X ; Set new position
jmp plot ; And activate it

18
libsrc/cx16/gotoxy.s Normal file
View File

@@ -0,0 +1,18 @@
;
; 2019-11-06, Greg King
;
; void fastcall gotoxy (unsigned char x, unsigned char y);
;
.export gotoxy, _gotoxy
.import popa, plot
.include "cx16.inc"
gotoxy: jsr popa ; Get Y
_gotoxy:
sta CURS_Y ; Set Y
jsr popa ; Get X
sta CURS_X ; Set X
jmp plot ; Set the cursor position

13
libsrc/cx16/gotoy.s Normal file
View File

@@ -0,0 +1,13 @@
;
; 2019-11-06, Greg King
;
; void gotoy (unsigned char y);
;
.export _gotoy
.import plot
.include "cx16.inc"
_gotoy: sta CURS_Y ; Set the new position
jmp plot ; And activate it

View File

@@ -1,8 +1,8 @@
;
; Standard joystick driver for the CX16.
; May be used multiple times when statically linked to the application.
; May be installed multiple times when statically linked to the application.
;
; 2019-09-23, Greg King
; 2019-11-15 Greg King
;
.include "joy-kernel.inc"
@@ -18,7 +18,7 @@
; ------------------------------------------------------------------------
; Header. Includes jump table
module_header _cx16_stdjoy_joy
module_header _cx16_std_joy
; Driver signature
@@ -48,11 +48,10 @@ JOY_COUNT = 2 ; Number of joysticks we support
.code
; ------------------------------------------------------------------------
; INSTALL routine. Is called after the driver is loaded into memory.
; 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.
;
; Must return a JOY_ERR_xx code in .XA .
INSTALL:
lda #<JOY_ERR_OK
@@ -60,60 +59,67 @@ INSTALL:
; 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 routine -- is called before the driver is removed from memory.
; Can do clean-up or whatever. Shouldn't return anything.
UNINSTALL:
rts
; ------------------------------------------------------------------------
; COUNT: Return the total number of possible joysticks in a/x.
;
; COUNT: Return the total number of possible joysticks, in .XA .
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: Read a particular joystick passed in .A .
READ: pha
jsr GETJOY
pla
bne pad2
READ: php
bit #JOY_COUNT - $01
sei
bnz pad2
; Read game pad 1
pad1: lda JOY1 + 1
pad1: ldy JOY1 ; Allow JOY1 to be reread between interrupts
sty JOY1 + 2
lda JOY1 + 1
bit #%00001110
beq nes1
asl JOY1 ; Get SNES's B button
bze nes1
asl JOY1 + 2 ; 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 JOY1 + 2 ; Drop SNES's Y button
asl a ; Get back the B button
ror JOY1 + 2
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
ror JOY1 + 2 ; Make byte look like NES pad
nes1: lda JOY1 + 2
plp
eor #%11111111 ; (The controllers use negative logic)
rts
; Read game pad 2
pad2: lda JOY2 + 1
pad2: ldy JOY2
sty JOY2 + 2
lda JOY2 + 1
bit #%00001110
beq nes2
asl JOY2
bze nes2
asl JOY2 + 2
ror a
asl JOY2
asl JOY2 + 2
asl a
ror JOY2
ror JOY2 + 2
asl a
ror JOY2
nes2: lda JOY2
ror JOY2 + 2
nes2: lda JOY2 + 2
plp
eor #%11111111
rts

View File

@@ -1,10 +1,11 @@
;
; Address of the static standard joystick driver
;
; 2019-09-19, Greg King
; 2019-11-10, Greg King
;
; const void joy_static_stddrv[];
;
.import _cx16_stdjoy_joy
.export _joy_static_stddrv := _cx16_stdjoy_joy
.import _cx16_std_joy
.export _joy_static_stddrv := _cx16_std_joy

View File

@@ -1,7 +1,7 @@
;
; Name of the standard joystick driver
;
; 2019-09-19, Greg King
; 2019-11-10, Greg King
;
; const char joy_stddrv[];
;
@@ -10,4 +10,4 @@
.rodata
_joy_stddrv: .asciiz "cx16-stdjoy.joy"
_joy_stddrv: .asciiz "cx16-std.joy"

20
libsrc/cx16/joyref.s Normal file
View File

@@ -0,0 +1,20 @@
;
; 2019-11-14, Greg King
;
; Link an interrupt handler if joysticks are used by a program.
;
.interruptor joy_libref, 9
.include "cbm_kernal.inc"
.include "cx16.inc"
joy_libref:
lda VERA::IRQ_FLAGS
lsr a
bcc not_vsync
jsr GETJOY ; Bit-bang game controllers
clc ; Let other Jiffy handlers run
not_vsync:
rts

View File

@@ -1,5 +1,5 @@
;
; 2019-09-20, Greg King
; 2019-11-06, Greg King
;
; unsigned char kbhit (void);
; /* Returns non-zero (true) if a typed character is waiting. */
@@ -11,7 +11,7 @@
.proc _kbhit
ldx #>$0000 ; High byte of return
lda KEY_COUNT ; Get number of characters
rts
tax ; High byte of return (only its zero/nonzero ...
rts ; ... state matters)
.endproc

View File

@@ -1,5 +1,5 @@
;
; 2019-09-22, Greg King
; 2019-11-05, Greg King
;
; CX16 Kernal functions
;
@@ -7,9 +7,10 @@
.include "cbm_kernal.inc"
.export GETJOY
.export MOUSE
.export SCRMOD
.export CLSALL
.export SWAPPER
.export JSRFAR
.export INDFET
.export INDSTA

View File

@@ -1,10 +1,9 @@
;
; 2013-05-31, Oliver Schmidt
; 2019-09-22, Greg King
; 2019-11-14, Greg King
;
.export em_libref
.export joy_libref
.export mouse_libref
.export ser_libref
.export tgi_libref
@@ -12,7 +11,6 @@
.import _exit
em_libref := _exit
joy_libref := _exit
mouse_libref := _exit
ser_libref := _exit
tgi_libref := _exit

View File

@@ -33,7 +33,7 @@ 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
; which may be reused after the startup code is run.
.segment "ONCE"
@@ -64,7 +64,7 @@ L2: lda BASIC_BUF,x
bne L2
ldy #1 * 2
; Find the next argument
; Find the next argument.
next: lda BASIC_BUF,x
beq done ; End of line reached
@@ -74,7 +74,7 @@ next: lda BASIC_BUF,x
; 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
; will check now for a quoted argument, in which case, we will have to skip this
; first character.
found: cmp #'"' ; Is the argument quoted?
@@ -95,7 +95,7 @@ setterm:sta term ; Set end of argument marker
iny
inc __argc ; Found another arg
; Search for the end of the argument
; Search for the end of the argument.
argloop:lda BASIC_BUF,x
beq done

View File

@@ -1,5 +1,5 @@
;
; 2019-09-20, Greg King
; 2019-11-06, Greg King
;
; void __fastcall__ set_tv (unsigned char);
; /* Set the video mode the machine will use. */
@@ -12,20 +12,18 @@
.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
ldx #<VERA::COMPOSER::VIDEO
ldy #>VERA::COMPOSER::VIDEO
stx VERA::ADDR
sty VERA::ADDR+1
ldx #^VERA::COMPOSER::VIDEO
stx VERA::ADDR+2
pla
sta VERA::DATA0
plp ; Re-enable interrupts
rts

View File

@@ -1,6 +1,16 @@
;
; 2012-09-30, Oliver Schmidt
; 2019-09-08, Greg King
; 2019-11-05, Greg King
;
.exportzp ST := $90 ; IEC status byte
.export ST: zp
.segment "EXTZP": zp
; This is a temporary hack.
; A zero-page copy of the IEC status byte.
; This is needed because the Commander X16's Kernal's status
; variable was moved out of the zero page. But, the common
; CBM file function modules import this as a zero-page variable.
ST: .res 1

View File

@@ -0,0 +1,11 @@
;
; Address of the static standard TGI driver
;
; 2019-11-06, Greg King
;
; const void tgi_static_stddrv[];
;
.import _cx16_640x4c_tgi
.export _tgi_static_stddrv := _cx16_640x4c_tgi

13
libsrc/cx16/tgi_stddrv.s Normal file
View File

@@ -0,0 +1,13 @@
;
; Name of the standard TGI driver
;
; 2019-11-06, Greg King
;
; const char tgi_stddrv[];
;
.export _tgi_stddrv
.rodata
_tgi_stddrv: .asciiz "cx16-640x4c.tgi"

View File

@@ -1,30 +1,44 @@
;
; 2009-09-07, Ullrich von Bassewitz
; 2019-09-23, Greg King
; 2019-11-06, Greg King
;
; unsigned __fastcall__ videomode (unsigned Mode);
; /* Set the video mode, return the old mode. */
; /* Video mode defines */
; #define VIDEOMODE_40x30 0x00
; #define VIDEOMODE_80x60 0x02
; #define VIDEOMODE_320x240 0x80
; #define VIDEOMODE_SWAP (-1)
;
; signed char __fastcall__ videomode (signed char Mode);
; /* Set the video mode, return the old mode.
; ** Return -1 if Mode isn't valid.
; ** Call with one of the VIDEOMODE_xx constants.
; */
;
.export _videomode
.import SWAPPER
.include "cx16.inc"
.import SCRMOD
.proc _videomode
cmp LLEN ; Do we have this mode already?
beq @L9
tax
clc ; (Get old mode)
jsr SCRMOD
pha
txa
lda LLEN ; Get current mode ...
pha ; ... and save it
sec ; (Set new mode)
jsr SCRMOD
jsr SWAPPER ; Toggle the mode
pla ; Get back old mode
bcs @L1
ldx #>$0000 ; Clear high byte
rts
pla ; Get old mode into A
; The new mode is invalid. Go back to the old mode. Return -1.
; Done, old mode is in .A
@L9: ldx #>$0000 ; Clear high byte
@L1: sec
jsr SCRMOD
lda #<-1
tax
rts
.endproc

View File

@@ -3,7 +3,7 @@
;
; void waitvsync (void);
;
; VERA's vertical sync. causes IRQs which increment the jiffy clock.
; VERA's vertical sync causes IRQs which increment the jiffy clock.
;
.export _waitvsync

15
libsrc/cx16/wherex.s Normal file
View File

@@ -0,0 +1,15 @@
;
; 2019-11-06, Greg King
;
; unsigned char wherex (void);
;
.export _wherex
.include "cx16.inc"
.proc _wherex
lda CURS_X
ldx #>$0000
rts
.endproc

15
libsrc/cx16/wherey.s Normal file
View File

@@ -0,0 +1,15 @@
;
; 2019-11-06, Greg King
;
; unsigned char wherey (void);
;
.export _wherey
.include "cx16.inc"
.proc _wherey
lda CURS_Y
ldx #>$0000
rts
.endproc