mirror of
https://github.com/irmen/prog8.git
synced 2024-11-23 22:33:12 +00:00
08ac459a41
When it returns true it means run the system IRQ handler afterwards. When it returns false, the system handler is NOT ran afterwards.
908 lines
30 KiB
Lua
908 lines
30 KiB
Lua
; Prog8 definitions for the Commodore-128
|
|
; Including memory registers, I/O registers, Basic and Kernal subroutines.
|
|
|
|
cbm {
|
|
; Commodore (CBM) common variables, vectors and kernal routines
|
|
%option no_symbol_prefixing
|
|
|
|
&ubyte TIME_HI = $a0 ; software jiffy clock, hi byte
|
|
&ubyte TIME_MID = $a1 ; .. mid byte
|
|
&ubyte TIME_LO = $a2 ; .. lo byte. Updated by IRQ every 1/60 sec
|
|
&ubyte STATUS = $90 ; kernal status variable for I/O
|
|
&ubyte STKEY = $91 ; various keyboard statuses (updated by IRQ)
|
|
&ubyte SHFLAG = $d3 ; various modifier key status (updated by IRQ)
|
|
&ubyte SFDX = $d4 ; current key pressed (matrix value) (updated by IRQ)
|
|
&ubyte COLOR = $f1 ; cursor color
|
|
|
|
&uword IERROR = $0300
|
|
&uword IMAIN = $0302
|
|
&uword ICRNCH = $0304
|
|
&uword IQPLOP = $0306
|
|
&uword IGONE = $0308
|
|
&uword IEVAL = $030a
|
|
&uword ICRNCH2 = $030c
|
|
&uword IQPLOP2 = $030e
|
|
&uword IGONE2 = $0310
|
|
; $0312 and $0313 are unused.
|
|
&uword CINV = $0314 ; IRQ vector (in ram)
|
|
&uword CBINV = $0316 ; BRK vector (in ram)
|
|
&uword NMINV = $0318 ; NMI vector (in ram)
|
|
&uword IOPEN = $031a
|
|
&uword ICLOSE = $031c
|
|
&uword ICHKIN = $031e
|
|
&uword ICKOUT = $0320
|
|
&uword ICLRCH = $0322
|
|
&uword IBASIN = $0324
|
|
&uword IBSOUT = $0326
|
|
&uword ISTOP = $0328
|
|
&uword IGETIN = $032a
|
|
&uword ICLALL = $032c
|
|
&uword IEXMON = $032e
|
|
&uword ILOAD = $0330
|
|
&uword ISAVE = $0332
|
|
|
|
&uword NMI_VEC = $FFFA ; 6502 nmi vector, determined by the kernal if banked in
|
|
&uword RESET_VEC = $FFFC ; 6502 reset vector, determined by the kernal if banked in
|
|
&uword IRQ_VEC = $FFFE ; 6502 interrupt vector, determined by the kernal if banked in
|
|
|
|
; the default addresses for the character screen chars and colors
|
|
const uword Screen = $0400 ; to have this as an array[40*25] the compiler would have to support array size > 255
|
|
const uword Colors = $d800 ; to have this as an array[40*25] the compiler would have to support array size > 255
|
|
|
|
; ---- kernal routines, these are the same as on the Commodore-64 (hence the same block name) ----
|
|
|
|
; STROUT --> use txt.print
|
|
; CLEARSCR -> use txt.clear_screen
|
|
; HOMECRSR -> use txt.home or txt.plot
|
|
|
|
romsub $FA65 = IRQDFRT() clobbers(A,X,Y) ; default IRQ routine
|
|
romsub $FF33 = IRQDFEND() clobbers(A,X,Y) ; default IRQ end/cleanup
|
|
|
|
; TODO c128 a bunch of kernal routines are missing here that are specific to the c128
|
|
|
|
romsub $FF81 = CINT() clobbers(A,X,Y) ; (alias: SCINIT) initialize screen editor and video chip
|
|
romsub $FF84 = IOINIT() clobbers(A, X) ; initialize I/O devices (CIA, SID, IRQ)
|
|
romsub $FF87 = RAMTAS() clobbers(A,X,Y) ; initialize RAM, tape buffer, screen
|
|
romsub $FF8A = RESTOR() clobbers(A,X,Y) ; restore default I/O vectors
|
|
romsub $FF8D = VECTOR(uword userptr @ XY, bool dir @ Pc) clobbers(A,Y) ; read/set I/O vector table
|
|
romsub $FF90 = SETMSG(ubyte value @ A) ; set Kernal message control flag
|
|
romsub $FF93 = SECOND(ubyte address @ A) clobbers(A) ; (alias: LSTNSA) send secondary address after LISTEN
|
|
romsub $FF96 = TKSA(ubyte address @ A) clobbers(A) ; (alias: TALKSA) send secondary address after TALK
|
|
romsub $FF99 = MEMTOP(uword address @ XY, bool dir @ Pc) -> uword @ XY ; read/set top of memory pointer
|
|
romsub $FF9C = MEMBOT(uword address @ XY, bool dir @ Pc) -> uword @ XY ; read/set bottom of memory pointer
|
|
romsub $FF9F = SCNKEY() clobbers(A,X,Y) ; scan the keyboard
|
|
romsub $FFA2 = SETTMO(ubyte timeout @ A) ; set time-out flag for IEEE bus
|
|
romsub $FFA5 = ACPTR() -> ubyte @ A ; (alias: IECIN) input byte from serial bus
|
|
romsub $FFA8 = CIOUT(ubyte databyte @ A) ; (alias: IECOUT) output byte to serial bus
|
|
romsub $FFAB = UNTLK() clobbers(A) ; command serial bus device to UNTALK
|
|
romsub $FFAE = UNLSN() clobbers(A) ; command serial bus device to UNLISTEN
|
|
romsub $FFB1 = LISTEN(ubyte device @ A) clobbers(A) ; command serial bus device to LISTEN
|
|
romsub $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial bus device to TALK
|
|
romsub $FFB7 = READST() -> ubyte @ A ; read I/O status word
|
|
romsub $FFBA = SETLFS(ubyte logical @ A, ubyte device @ X, ubyte secondary @ Y) ; set logical file parameters
|
|
romsub $FFBD = SETNAM(ubyte namelen @ A, str filename @ XY) ; set filename parameters
|
|
romsub $FFC0 = OPEN() clobbers(X,Y) -> bool @Pc, ubyte @A ; (via 794 ($31A)) open a logical file
|
|
romsub $FFC3 = CLOSE(ubyte logical @ A) clobbers(A,X,Y) ; (via 796 ($31C)) close a logical file
|
|
romsub $FFC6 = CHKIN(ubyte logical @ X) clobbers(A,X) -> bool @Pc ; (via 798 ($31E)) define an input channel
|
|
romsub $FFC9 = CHKOUT(ubyte logical @ X) clobbers(A,X) ; (via 800 ($320)) define an output channel
|
|
romsub $FFCC = CLRCHN() clobbers(A,X) ; (via 802 ($322)) restore default devices
|
|
romsub $FFCF = CHRIN() clobbers(X, Y) -> ubyte @ A ; (via 804 ($324)) input a character (for keyboard, read a whole line from the screen) A=byte read.
|
|
romsub $FFD2 = CHROUT(ubyte character @ A) ; (via 806 ($326)) output a character
|
|
romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> bool @Pc, ubyte @ A, uword @ XY ; (via 816 ($330)) load from device
|
|
romsub $FFD8 = SAVE(ubyte zp_startaddr @ A, uword endaddr @ XY) -> bool @ Pc, ubyte @ A ; (via 818 ($332)) save to a device
|
|
romsub $FFDB = SETTIM(ubyte low @ A, ubyte middle @ X, ubyte high @ Y) ; set the software clock
|
|
romsub $FFDE = RDTIM() -> ubyte @ A, ubyte @ X, ubyte @ Y ; read the software clock (A=lo,X=mid,Y=high)
|
|
romsub $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; (via 808 ($328)) check the STOP key (and some others in A)
|
|
romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; (via 810 ($32A)) get a character
|
|
romsub $FFE7 = CLALL() clobbers(A,X) ; (via 812 ($32C)) close all files
|
|
romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock
|
|
romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of screen rows and columns
|
|
romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use txt.plot for a 'safe' wrapper that preserves X.
|
|
romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices
|
|
|
|
; ---- end of C64 compatible ROM kernal routines ----
|
|
|
|
; ---- utilities -----
|
|
|
|
asmsub STOP2() clobbers(X) -> ubyte @A {
|
|
; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the carry status flag.
|
|
%asm {{
|
|
jsr cbm.STOP
|
|
beq +
|
|
lda #0
|
|
rts
|
|
+ lda #1
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub RDTIM16() clobbers(X) -> uword @AY {
|
|
; -- like RDTIM() but only returning the lower 16 bits in AY for convenience
|
|
%asm {{
|
|
jsr cbm.RDTIM
|
|
pha
|
|
txa
|
|
tay
|
|
pla
|
|
rts
|
|
}}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
c64 {
|
|
; C64 I/O registers (VIC, SID, CIA)
|
|
%option no_symbol_prefixing
|
|
|
|
; the default locations of the 8 sprite pointers (store address of sprite / 64)
|
|
&ubyte SPRPTR0 = 2040
|
|
&ubyte SPRPTR1 = 2041
|
|
&ubyte SPRPTR2 = 2042
|
|
&ubyte SPRPTR3 = 2043
|
|
&ubyte SPRPTR4 = 2044
|
|
&ubyte SPRPTR5 = 2045
|
|
&ubyte SPRPTR6 = 2046
|
|
&ubyte SPRPTR7 = 2047
|
|
&ubyte[8] SPRPTR = 2040 ; the 8 sprite pointers as an array.
|
|
|
|
|
|
; ---- VIC-II 6567/6569/856x registers ----
|
|
|
|
&ubyte SP0X = $d000
|
|
&ubyte SP0Y = $d001
|
|
&ubyte SP1X = $d002
|
|
&ubyte SP1Y = $d003
|
|
&ubyte SP2X = $d004
|
|
&ubyte SP2Y = $d005
|
|
&ubyte SP3X = $d006
|
|
&ubyte SP3Y = $d007
|
|
&ubyte SP4X = $d008
|
|
&ubyte SP4Y = $d009
|
|
&ubyte SP5X = $d00a
|
|
&ubyte SP5Y = $d00b
|
|
&ubyte SP6X = $d00c
|
|
&ubyte SP6Y = $d00d
|
|
&ubyte SP7X = $d00e
|
|
&ubyte SP7Y = $d00f
|
|
&ubyte[16] SPXY = $d000 ; the 8 sprite X and Y registers as an array.
|
|
&uword[8] SPXYW = $d000 ; the 8 sprite X and Y registers as a combined xy word array.
|
|
|
|
&ubyte MSIGX = $d010
|
|
&ubyte SCROLY = $d011
|
|
&ubyte RASTER = $d012
|
|
&ubyte LPENX = $d013
|
|
&ubyte LPENY = $d014
|
|
&ubyte SPENA = $d015
|
|
&ubyte SCROLX = $d016
|
|
&ubyte YXPAND = $d017
|
|
&ubyte VMCSB = $d018
|
|
&ubyte VICIRQ = $d019
|
|
&ubyte IREQMASK = $d01a
|
|
&ubyte SPBGPR = $d01b
|
|
&ubyte SPMC = $d01c
|
|
&ubyte XXPAND = $d01d
|
|
&ubyte SPSPCL = $d01e
|
|
&ubyte SPBGCL = $d01f
|
|
|
|
&ubyte EXTCOL = $d020 ; border color
|
|
&ubyte BGCOL0 = $d021 ; screen color
|
|
&ubyte BGCOL1 = $d022
|
|
&ubyte BGCOL2 = $d023
|
|
&ubyte BGCOL4 = $d024
|
|
&ubyte SPMC0 = $d025
|
|
&ubyte SPMC1 = $d026
|
|
&ubyte SP0COL = $d027
|
|
&ubyte SP1COL = $d028
|
|
&ubyte SP2COL = $d029
|
|
&ubyte SP3COL = $d02a
|
|
&ubyte SP4COL = $d02b
|
|
&ubyte SP5COL = $d02c
|
|
&ubyte SP6COL = $d02d
|
|
&ubyte SP7COL = $d02e
|
|
&ubyte[8] SPCOL = $d027
|
|
|
|
|
|
; ---- end of VIC-II registers ----
|
|
|
|
; ---- CIA 6526 1 & 2 registers ----
|
|
|
|
&ubyte CIA1PRA = $DC00 ; CIA 1 DRA, keyboard column drive (and joystick control port #2)
|
|
&ubyte CIA1PRB = $DC01 ; CIA 1 DRB, keyboard row port (and joystick control port #1)
|
|
&ubyte CIA1DDRA = $DC02 ; CIA 1 DDRA, keyboard column
|
|
&ubyte CIA1DDRB = $DC03 ; CIA 1 DDRB, keyboard row
|
|
&ubyte CIA1TAL = $DC04 ; CIA 1 timer A low byte
|
|
&ubyte CIA1TAH = $DC05 ; CIA 1 timer A high byte
|
|
&ubyte CIA1TBL = $DC06 ; CIA 1 timer B low byte
|
|
&ubyte CIA1TBH = $DC07 ; CIA 1 timer B high byte
|
|
&ubyte CIA1TOD10 = $DC08 ; time of day, 1/10 sec.
|
|
&ubyte CIA1TODSEC = $DC09 ; time of day, seconds
|
|
&ubyte CIA1TODMMIN = $DC0A ; time of day, minutes
|
|
&ubyte CIA1TODHR = $DC0B ; time of day, hours
|
|
&ubyte CIA1SDR = $DC0C ; Serial Data Register
|
|
&ubyte CIA1ICR = $DC0D
|
|
&ubyte CIA1CRA = $DC0E
|
|
&ubyte CIA1CRB = $DC0F
|
|
|
|
&ubyte CIA2PRA = $DD00 ; CIA 2 DRA, serial port and video address
|
|
&ubyte CIA2PRB = $DD01 ; CIA 2 DRB, RS232 port / USERPORT
|
|
&ubyte CIA2DDRA = $DD02 ; CIA 2 DDRA, serial port and video address
|
|
&ubyte CIA2DDRB = $DD03 ; CIA 2 DDRB, RS232 port / USERPORT
|
|
&ubyte CIA2TAL = $DD04 ; CIA 2 timer A low byte
|
|
&ubyte CIA2TAH = $DD05 ; CIA 2 timer A high byte
|
|
&ubyte CIA2TBL = $DD06 ; CIA 2 timer B low byte
|
|
&ubyte CIA2TBH = $DD07 ; CIA 2 timer B high byte
|
|
&ubyte CIA2TOD10 = $DD08 ; time of day, 1/10 sec.
|
|
&ubyte CIA2TODSEC = $DD09 ; time of day, seconds
|
|
&ubyte CIA2TODMIN = $DD0A ; time of day, minutes
|
|
&ubyte CIA2TODHR = $DD0B ; time of day, hours
|
|
&ubyte CIA2SDR = $DD0C ; Serial Data Register
|
|
&ubyte CIA2ICR = $DD0D
|
|
&ubyte CIA2CRA = $DD0E
|
|
&ubyte CIA2CRB = $DD0F
|
|
|
|
; ---- end of CIA registers ----
|
|
|
|
; ---- SID 6581/8580 registers ----
|
|
|
|
&ubyte FREQLO1 = $D400 ; channel 1 freq lo
|
|
&ubyte FREQHI1 = $D401 ; channel 1 freq hi
|
|
&uword FREQ1 = $D400 ; channel 1 freq (word)
|
|
&ubyte PWLO1 = $D402 ; channel 1 pulse width lo (7-0)
|
|
&ubyte PWHI1 = $D403 ; channel 1 pulse width hi (11-8)
|
|
&uword PW1 = $D402 ; channel 1 pulse width (word)
|
|
&ubyte CR1 = $D404 ; channel 1 voice control register
|
|
&ubyte AD1 = $D405 ; channel 1 attack & decay
|
|
&ubyte SR1 = $D406 ; channel 1 sustain & release
|
|
&ubyte FREQLO2 = $D407 ; channel 2 freq lo
|
|
&ubyte FREQHI2 = $D408 ; channel 2 freq hi
|
|
&uword FREQ2 = $D407 ; channel 2 freq (word)
|
|
&ubyte PWLO2 = $D409 ; channel 2 pulse width lo (7-0)
|
|
&ubyte PWHI2 = $D40A ; channel 2 pulse width hi (11-8)
|
|
&uword PW2 = $D409 ; channel 2 pulse width (word)
|
|
&ubyte CR2 = $D40B ; channel 2 voice control register
|
|
&ubyte AD2 = $D40C ; channel 2 attack & decay
|
|
&ubyte SR2 = $D40D ; channel 2 sustain & release
|
|
&ubyte FREQLO3 = $D40E ; channel 3 freq lo
|
|
&ubyte FREQHI3 = $D40F ; channel 3 freq hi
|
|
&uword FREQ3 = $D40E ; channel 3 freq (word)
|
|
&ubyte PWLO3 = $D410 ; channel 3 pulse width lo (7-0)
|
|
&ubyte PWHI3 = $D411 ; channel 3 pulse width hi (11-8)
|
|
&uword PW3 = $D410 ; channel 3 pulse width (word)
|
|
&ubyte CR3 = $D412 ; channel 3 voice control register
|
|
&ubyte AD3 = $D413 ; channel 3 attack & decay
|
|
&ubyte SR3 = $D414 ; channel 3 sustain & release
|
|
&ubyte FCLO = $D415 ; filter cutoff lo (2-0)
|
|
&ubyte FCHI = $D416 ; filter cutoff hi (10-3)
|
|
&uword FC = $D415 ; filter cutoff (word)
|
|
&ubyte RESFILT = $D417 ; filter resonance and routing
|
|
&ubyte MVOL = $D418 ; filter mode and main volume control
|
|
&ubyte POTX = $D419 ; potentiometer X
|
|
&ubyte POTY = $D41A ; potentiometer Y
|
|
&ubyte OSC3 = $D41B ; channel 3 oscillator value read
|
|
&ubyte ENV3 = $D41C ; channel 3 envelope value read
|
|
|
|
; ---- end of SID registers ----
|
|
|
|
}
|
|
|
|
c128 {
|
|
; ---- C128 specific registers ----
|
|
%option no_symbol_prefixing
|
|
|
|
&ubyte VM1 = $0A2C ; shadow for VUC $d018 in text mode
|
|
&ubyte VM2 = $0A2D ; shadow for VIC $d018 in bitmap screen mode
|
|
&ubyte VM3 = $0A2E ; starting page for VDC screen mem
|
|
&ubyte VM4 = $0A2F ; starting page for VDC attribute mem
|
|
|
|
|
|
; ---- C128 specific system utility routines: ----
|
|
|
|
asmsub disable_basic() clobbers(A) {
|
|
%asm {{
|
|
lda $0a04 ; disable BASIC shadow registers
|
|
and #$fe
|
|
sta $0a04
|
|
|
|
lda #$01 ; disable BASIC IRQ service routine
|
|
sta $12fd
|
|
|
|
lda #$ff ; disable screen editor IRQ setup
|
|
sta $d8
|
|
|
|
lda #$b7 ; skip programmable function key check
|
|
sta $033c
|
|
|
|
lda #$0e ; bank out BASIC ROM
|
|
sta $ff00
|
|
rts
|
|
}}
|
|
}
|
|
|
|
; ---- end of C128 specific system utility routines ----
|
|
|
|
}
|
|
|
|
sys {
|
|
; ------- lowlevel system routines --------
|
|
%option no_symbol_prefixing
|
|
|
|
const ubyte target = 128 ; compilation target specifier. 64 = C64, 128 = C128, 16 = CommanderX16.
|
|
|
|
asmsub init_system() {
|
|
; Initializes the machine to a sane starting state.
|
|
; Called automatically by the loader program logic.
|
|
; This means that the BASIC, KERNAL and CHARGEN ROMs are banked in,
|
|
; the VIC, SID and CIA chips are reset, screen is cleared, and the default IRQ is set.
|
|
; Also a different color scheme is chosen to identify ourselves a little.
|
|
; Uppercase charset is activated.
|
|
%asm {{
|
|
sei
|
|
cld
|
|
lda #0
|
|
sta $ff00 ; select default bank 15
|
|
jsr cbm.IOINIT
|
|
jsr cbm.RESTOR
|
|
jsr cbm.CINT
|
|
lda #6
|
|
sta c64.EXTCOL
|
|
lda #7
|
|
sta cbm.COLOR
|
|
lda #0
|
|
sta c64.BGCOL0
|
|
jsr disable_runstop_and_charsetswitch
|
|
clc
|
|
clv
|
|
cli
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub init_system_phase2() {
|
|
%asm {{
|
|
rts ; no phase 2 steps on the C128
|
|
}}
|
|
}
|
|
|
|
asmsub cleanup_at_exit() {
|
|
; executed when the main subroutine does rts
|
|
%asm {{
|
|
jmp sys.enable_runstop_and_charsetswitch
|
|
}}
|
|
}
|
|
|
|
asmsub disable_runstop_and_charsetswitch() clobbers(A) {
|
|
%asm {{
|
|
lda #$80
|
|
sta 247 ; disable charset switching
|
|
lda #112
|
|
sta 808 ; disable run/stop key
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub enable_runstop_and_charsetswitch() clobbers(A) {
|
|
%asm {{
|
|
lda #0
|
|
sta 247 ; enable charset switching
|
|
lda #110
|
|
sta 808 ; enable run/stop key
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub save_prog8_internals() {
|
|
%asm {{
|
|
lda P8ZP_SCRATCH_B1
|
|
sta save_SCRATCH_ZPB1
|
|
lda P8ZP_SCRATCH_REG
|
|
sta save_SCRATCH_ZPREG
|
|
lda P8ZP_SCRATCH_W1
|
|
sta save_SCRATCH_ZPWORD1
|
|
lda P8ZP_SCRATCH_W1+1
|
|
sta save_SCRATCH_ZPWORD1+1
|
|
lda P8ZP_SCRATCH_W2
|
|
sta save_SCRATCH_ZPWORD2
|
|
lda P8ZP_SCRATCH_W2+1
|
|
sta save_SCRATCH_ZPWORD2+1
|
|
rts
|
|
save_SCRATCH_ZPB1 .byte 0
|
|
save_SCRATCH_ZPREG .byte 0
|
|
save_SCRATCH_ZPWORD1 .word 0
|
|
save_SCRATCH_ZPWORD2 .word 0
|
|
}}
|
|
}
|
|
|
|
asmsub restore_prog8_internals() {
|
|
%asm {{
|
|
lda save_prog8_internals.save_SCRATCH_ZPB1
|
|
sta P8ZP_SCRATCH_B1
|
|
lda save_prog8_internals.save_SCRATCH_ZPREG
|
|
sta P8ZP_SCRATCH_REG
|
|
lda save_prog8_internals.save_SCRATCH_ZPWORD1
|
|
sta P8ZP_SCRATCH_W1
|
|
lda save_prog8_internals.save_SCRATCH_ZPWORD1+1
|
|
sta P8ZP_SCRATCH_W1+1
|
|
lda save_prog8_internals.save_SCRATCH_ZPWORD2
|
|
sta P8ZP_SCRATCH_W2
|
|
lda save_prog8_internals.save_SCRATCH_ZPWORD2+1
|
|
sta P8ZP_SCRATCH_W2+1
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub set_irq(uword handler @AY) clobbers(A) {
|
|
%asm {{
|
|
sta _modified+1
|
|
sty _modified+2
|
|
sei
|
|
lda #<_irq_handler
|
|
sta cbm.CINV
|
|
lda #>_irq_handler
|
|
sta cbm.CINV+1
|
|
cli
|
|
rts
|
|
_irq_handler
|
|
jsr sys.save_prog8_internals
|
|
cld
|
|
_modified
|
|
jsr $ffff ; modified
|
|
pha
|
|
jsr sys.restore_prog8_internals
|
|
pla
|
|
beq +
|
|
jmp cbm.IRQDFRT ; continue with normal kernal irq routine
|
|
+ lda #$ff
|
|
sta c64.VICIRQ ; acknowledge raster irq
|
|
lda c64.CIA1ICR ; acknowledge CIA1 interrupt
|
|
pla
|
|
tay
|
|
pla
|
|
tax
|
|
pla
|
|
rti
|
|
|
|
_use_kernal .byte 0
|
|
}}
|
|
}
|
|
|
|
asmsub restore_irq() clobbers(A) {
|
|
%asm {{
|
|
sei
|
|
lda #<cbm.IRQDFRT
|
|
sta cbm.CINV
|
|
lda #>cbm.IRQDFRT
|
|
sta cbm.CINV+1
|
|
lda #0
|
|
sta c64.IREQMASK ; disable raster irq
|
|
lda #%10000001
|
|
sta c64.CIA1ICR ; restore CIA1 irq
|
|
cli
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub set_rasterirq(uword handler @AY, uword rasterpos @R0) clobbers(A) {
|
|
%asm {{
|
|
sta _modified+1
|
|
sty _modified+2
|
|
lda cx16.r0
|
|
ldy cx16.r0+1
|
|
sei
|
|
jsr _setup_raster_irq
|
|
lda #<_raster_irq_handler
|
|
sta cbm.CINV
|
|
lda #>_raster_irq_handler
|
|
sta cbm.CINV+1
|
|
cli
|
|
rts
|
|
|
|
_raster_irq_handler
|
|
jsr sys.save_prog8_internals
|
|
cld
|
|
_modified
|
|
jsr $ffff ; modified
|
|
pha
|
|
jsr sys.restore_prog8_internals
|
|
lda #$ff
|
|
sta c64.VICIRQ ; acknowledge raster irq
|
|
pla
|
|
beq +
|
|
jmp cbm.IRQDFRT ; continue with kernal irq routine
|
|
+ pla
|
|
tay
|
|
pla
|
|
tax
|
|
pla
|
|
rti
|
|
|
|
_setup_raster_irq
|
|
pha
|
|
lda #%01111111
|
|
sta c64.CIA1ICR ; "switch off" interrupts signals from cia-1
|
|
sta c64.CIA2ICR ; "switch off" interrupts signals from cia-2
|
|
and c64.SCROLY
|
|
sta c64.SCROLY ; clear most significant bit of raster position
|
|
lda c64.CIA1ICR ; ack previous irq
|
|
lda c64.CIA2ICR ; ack previous irq
|
|
pla
|
|
sta c64.RASTER ; set the raster line number where interrupt should occur
|
|
cpy #0
|
|
beq +
|
|
lda c64.SCROLY
|
|
ora #%10000000
|
|
sta c64.SCROLY ; set most significant bit of raster position
|
|
+ lda #%00000001
|
|
sta c64.IREQMASK ;enable raster interrupt signals from vic
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub reset_system() {
|
|
; Soft-reset the system back to initial power-on Basic prompt.
|
|
%asm {{
|
|
sei
|
|
lda #0
|
|
sta $ff00 ; default bank 15
|
|
jmp (cbm.RESET_VEC)
|
|
}}
|
|
}
|
|
|
|
asmsub wait(uword jiffies @AY) {
|
|
; --- wait approximately the given number of jiffies (1/60th seconds) (N or N+1)
|
|
; note: the system irq handler has to be active for this to work as it depends on the system jiffy clock
|
|
%asm {{
|
|
stx P8ZP_SCRATCH_B1
|
|
sta P8ZP_SCRATCH_W1
|
|
sty P8ZP_SCRATCH_W1+1
|
|
|
|
_loop lda P8ZP_SCRATCH_W1
|
|
ora P8ZP_SCRATCH_W1+1
|
|
bne +
|
|
ldx P8ZP_SCRATCH_B1
|
|
rts
|
|
|
|
+ lda cbm.TIME_LO
|
|
sta P8ZP_SCRATCH_B1
|
|
- lda cbm.TIME_LO
|
|
cmp P8ZP_SCRATCH_B1
|
|
beq -
|
|
|
|
lda P8ZP_SCRATCH_W1
|
|
bne +
|
|
dec P8ZP_SCRATCH_W1+1
|
|
+ dec P8ZP_SCRATCH_W1
|
|
jmp _loop
|
|
}}
|
|
}
|
|
|
|
asmsub waitvsync() clobbers(A) {
|
|
; --- busy wait till the next vsync has occurred (approximately), without depending on custom irq handling.
|
|
; note: a more accurate way to wait for vsync is to set up a vsync irq handler instead.
|
|
%asm {{
|
|
- bit c64.SCROLY
|
|
bpl -
|
|
- bit c64.SCROLY
|
|
bmi -
|
|
rts
|
|
}}
|
|
}
|
|
|
|
inline asmsub waitrastborder() {
|
|
; --- busy wait till the raster position has reached the bottom screen border (approximately)
|
|
; note: a more accurate way to do this is by using a raster irq handler instead.
|
|
%asm {{
|
|
- bit c64.SCROLY
|
|
bpl -
|
|
}}
|
|
}
|
|
|
|
asmsub internal_stringcopy(uword source @R0, uword target @AY) clobbers (A,Y) {
|
|
; Called when the compiler wants to assign a string value to another string.
|
|
%asm {{
|
|
sta P8ZP_SCRATCH_W1
|
|
sty P8ZP_SCRATCH_W1+1
|
|
lda cx16.r0
|
|
ldy cx16.r0+1
|
|
jmp prog8_lib.strcpy
|
|
}}
|
|
}
|
|
|
|
asmsub memcopy(uword source @R0, uword target @R1, uword count @AY) clobbers(A,X,Y) {
|
|
; note: only works for NON-OVERLAPPING memory regions!
|
|
; note: can't be inlined because is called from asm as well
|
|
%asm {{
|
|
ldx cx16.r0
|
|
stx P8ZP_SCRATCH_W1 ; source in ZP
|
|
ldx cx16.r0+1
|
|
stx P8ZP_SCRATCH_W1+1
|
|
ldx cx16.r1
|
|
stx P8ZP_SCRATCH_W2 ; target in ZP
|
|
ldx cx16.r1+1
|
|
stx P8ZP_SCRATCH_W2+1
|
|
cpy #0
|
|
bne _longcopy
|
|
|
|
; copy <= 255 bytes
|
|
tay
|
|
bne _copyshort
|
|
rts ; nothing to copy
|
|
|
|
_copyshort
|
|
; decrease source and target pointers so we can simply index by Y
|
|
lda P8ZP_SCRATCH_W1
|
|
bne +
|
|
dec P8ZP_SCRATCH_W1+1
|
|
+ dec P8ZP_SCRATCH_W1
|
|
lda P8ZP_SCRATCH_W2
|
|
bne +
|
|
dec P8ZP_SCRATCH_W2+1
|
|
+ dec P8ZP_SCRATCH_W2
|
|
|
|
- lda (P8ZP_SCRATCH_W1),y
|
|
sta (P8ZP_SCRATCH_W2),y
|
|
dey
|
|
bne -
|
|
rts
|
|
|
|
_longcopy
|
|
sta P8ZP_SCRATCH_B1 ; lsb(count) = remainder in last page
|
|
tya
|
|
tax ; x = num pages (1+)
|
|
ldy #0
|
|
- lda (P8ZP_SCRATCH_W1),y
|
|
sta (P8ZP_SCRATCH_W2),y
|
|
iny
|
|
bne -
|
|
inc P8ZP_SCRATCH_W1+1
|
|
inc P8ZP_SCRATCH_W2+1
|
|
dex
|
|
bne -
|
|
ldy P8ZP_SCRATCH_B1
|
|
bne _copyshort
|
|
rts
|
|
}}
|
|
}
|
|
|
|
asmsub memset(uword mem @R0, uword numbytes @R1, ubyte value @A) clobbers(A,X,Y) {
|
|
%asm {{
|
|
ldy cx16.r0
|
|
sty P8ZP_SCRATCH_W1
|
|
ldy cx16.r0+1
|
|
sty P8ZP_SCRATCH_W1+1
|
|
ldx cx16.r1
|
|
ldy cx16.r1+1
|
|
jmp prog8_lib.memset
|
|
}}
|
|
}
|
|
|
|
asmsub memsetw(uword mem @R0, uword numwords @R1, uword value @AY) clobbers(A,X,Y) {
|
|
%asm {{
|
|
ldx cx16.r0
|
|
stx P8ZP_SCRATCH_W1
|
|
ldx cx16.r0+1
|
|
stx P8ZP_SCRATCH_W1+1
|
|
ldx cx16.r1
|
|
stx P8ZP_SCRATCH_W2
|
|
ldx cx16.r1+1
|
|
stx P8ZP_SCRATCH_W2+1
|
|
jmp prog8_lib.memsetw
|
|
}}
|
|
}
|
|
|
|
inline asmsub read_flags() -> ubyte @A {
|
|
%asm {{
|
|
php
|
|
pla
|
|
}}
|
|
}
|
|
|
|
inline asmsub clear_carry() {
|
|
%asm {{
|
|
clc
|
|
}}
|
|
}
|
|
|
|
inline asmsub set_carry() {
|
|
%asm {{
|
|
sec
|
|
}}
|
|
}
|
|
|
|
inline asmsub clear_irqd() {
|
|
%asm {{
|
|
cli
|
|
}}
|
|
}
|
|
|
|
inline asmsub set_irqd() {
|
|
%asm {{
|
|
sei
|
|
}}
|
|
}
|
|
|
|
inline asmsub irqsafe_set_irqd() {
|
|
%asm {{
|
|
php
|
|
sei
|
|
}}
|
|
}
|
|
|
|
inline asmsub irqsafe_clear_irqd() {
|
|
%asm {{
|
|
plp
|
|
}}
|
|
}
|
|
|
|
inline asmsub disable_caseswitch() {
|
|
%asm {{
|
|
lda #$80
|
|
sta 247
|
|
}}
|
|
}
|
|
|
|
inline asmsub enable_caseswitch() {
|
|
%asm {{
|
|
lda #0
|
|
sta 247
|
|
}}
|
|
}
|
|
|
|
inline asmsub exit(ubyte returnvalue @A) {
|
|
; -- immediately exit the program with a return code in the A register
|
|
%asm {{
|
|
lda #0
|
|
sta $ff00 ; default bank 15
|
|
jsr cbm.CLRCHN ; reset i/o channels
|
|
jsr sys.enable_runstop_and_charsetswitch
|
|
ldx prog8_lib.orig_stackpointer
|
|
txs
|
|
rts ; return to original caller
|
|
}}
|
|
}
|
|
|
|
inline asmsub progend() -> uword @AY {
|
|
%asm {{
|
|
lda #<prog8_program_end
|
|
ldy #>prog8_program_end
|
|
}}
|
|
}
|
|
|
|
}
|
|
|
|
cx16 {
|
|
%option no_symbol_prefixing
|
|
|
|
; the sixteen virtual 16-bit registers that the CX16 has defined in the zeropage
|
|
; they are simulated on the C128 as well but their location in memory is different
|
|
; (because there's no room for them in the zeropage)
|
|
; $1300-$1bff is unused RAM on C128.
|
|
&uword r0 = $1be0
|
|
&uword r1 = $1be2
|
|
&uword r2 = $1be4
|
|
&uword r3 = $1be6
|
|
&uword r4 = $1be8
|
|
&uword r5 = $1bea
|
|
&uword r6 = $1bec
|
|
&uword r7 = $1bee
|
|
&uword r8 = $1bf0
|
|
&uword r9 = $1bf2
|
|
&uword r10 = $1bf4
|
|
&uword r11 = $1bf6
|
|
&uword r12 = $1bf8
|
|
&uword r13 = $1bfa
|
|
&uword r14 = $1bfc
|
|
&uword r15 = $1bfe
|
|
|
|
&word r0s = $1be0
|
|
&word r1s = $1be2
|
|
&word r2s = $1be4
|
|
&word r3s = $1be6
|
|
&word r4s = $1be8
|
|
&word r5s = $1bea
|
|
&word r6s = $1bec
|
|
&word r7s = $1bee
|
|
&word r8s = $1bf0
|
|
&word r9s = $1bf2
|
|
&word r10s = $1bf4
|
|
&word r11s = $1bf6
|
|
&word r12s = $1bf8
|
|
&word r13s = $1bfa
|
|
&word r14s = $1bfc
|
|
&word r15s = $1bfe
|
|
|
|
&ubyte r0L = $1be0
|
|
&ubyte r1L = $1be2
|
|
&ubyte r2L = $1be4
|
|
&ubyte r3L = $1be6
|
|
&ubyte r4L = $1be8
|
|
&ubyte r5L = $1bea
|
|
&ubyte r6L = $1bec
|
|
&ubyte r7L = $1bee
|
|
&ubyte r8L = $1bf0
|
|
&ubyte r9L = $1bf2
|
|
&ubyte r10L = $1bf4
|
|
&ubyte r11L = $1bf6
|
|
&ubyte r12L = $1bf8
|
|
&ubyte r13L = $1bfa
|
|
&ubyte r14L = $1bfc
|
|
&ubyte r15L = $1bfe
|
|
|
|
&ubyte r0H = $1be1
|
|
&ubyte r1H = $1be3
|
|
&ubyte r2H = $1be5
|
|
&ubyte r3H = $1be7
|
|
&ubyte r4H = $1be9
|
|
&ubyte r5H = $1beb
|
|
&ubyte r6H = $1bed
|
|
&ubyte r7H = $1bef
|
|
&ubyte r8H = $1bf1
|
|
&ubyte r9H = $1bf3
|
|
&ubyte r10H = $1bf5
|
|
&ubyte r11H = $1bf7
|
|
&ubyte r12H = $1bf9
|
|
&ubyte r13H = $1bfb
|
|
&ubyte r14H = $1bfd
|
|
&ubyte r15H = $1bff
|
|
|
|
&byte r0sL = $1be0
|
|
&byte r1sL = $1be2
|
|
&byte r2sL = $1be4
|
|
&byte r3sL = $1be6
|
|
&byte r4sL = $1be8
|
|
&byte r5sL = $1bea
|
|
&byte r6sL = $1bec
|
|
&byte r7sL = $1bee
|
|
&byte r8sL = $1bf0
|
|
&byte r9sL = $1bf2
|
|
&byte r10sL = $1bf4
|
|
&byte r11sL = $1bf6
|
|
&byte r12sL = $1bf8
|
|
&byte r13sL = $1bfa
|
|
&byte r14sL = $1bfc
|
|
&byte r15sL = $1bfe
|
|
|
|
&byte r0sH = $1be1
|
|
&byte r1sH = $1be3
|
|
&byte r2sH = $1be5
|
|
&byte r3sH = $1be7
|
|
&byte r4sH = $1be9
|
|
&byte r5sH = $1beb
|
|
&byte r6sH = $1bed
|
|
&byte r7sH = $1bef
|
|
&byte r8sH = $1bf1
|
|
&byte r9sH = $1bf3
|
|
&byte r10sH = $1bf5
|
|
&byte r11sH = $1bf7
|
|
&byte r12sH = $1bf9
|
|
&byte r13sH = $1bfb
|
|
&byte r14sH = $1bfd
|
|
&byte r15sH = $1bff
|
|
|
|
asmsub save_virtual_registers() clobbers(A,Y) {
|
|
%asm {{
|
|
ldy #31
|
|
- lda cx16.r0,y
|
|
sta _cx16_vreg_storage,y
|
|
dey
|
|
bpl -
|
|
rts
|
|
|
|
_cx16_vreg_storage
|
|
.word 0,0,0,0,0,0,0,0
|
|
.word 0,0,0,0,0,0,0,0
|
|
}}
|
|
}
|
|
|
|
asmsub restore_virtual_registers() clobbers(A,Y) {
|
|
%asm {{
|
|
ldy #31
|
|
- lda save_virtual_registers._cx16_vreg_storage,y
|
|
sta cx16.r0,y
|
|
dey
|
|
bpl -
|
|
rts
|
|
}}
|
|
}
|
|
}
|