From 34f3169dda02679c1293adfde51dac27e39f678b Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 4 Apr 2024 00:18:53 +0200 Subject: [PATCH] tweak library routines for multiple return values. cbm: MEMTOP changed (now also returns nr of banks in A) STOP2 removed (just use STOP) RDTIM_safe() added TEST IRQ ENABLE RDTIM16 changed (internally) TEST IRQ ENABLE cx16: screen_mode changed (now also returns width and height in X,Y) kbdbuf_peek2 removed (just use kbdbuf_peek) joystick_get changed (presence now returned as bool in Y) joystick_get2 removed (just use joystick_get) mouse_pos changed (now properly returns x and y position in R0 and R1) set_led_brightness changed into set_led_state, with only a boolean on/off argument. There is no variable brightness. sys.set_leds_brightness() removed. Use cx16.set_led_brightness(). --- .../cpu6502/assignment/AssignmentAsmGen.kt | 61 +++++++- compiler/res/prog8lib/c128/syslib.p8 | 12 -- compiler/res/prog8lib/c64/syslib.p8 | 12 -- compiler/res/prog8lib/cx16/diskio.p8 | 3 +- compiler/res/prog8lib/cx16/syslib.p8 | 139 ++++++++---------- compiler/res/prog8lib/diskio.p8 | 3 +- compiler/res/prog8lib/pet32/syslib.p8 | 12 -- docs/source/syntaxreference.rst | 8 +- docs/source/todo.rst | 7 + examples/cx16/chunkedfile/demo.p8 | 4 +- examples/cx16/spotlight.p8 | 2 +- examples/cx16/tehtriz.p8 | 5 +- examples/cx16/zsound/play-zsound.p8 | 3 +- examples/test.p8 | 25 +--- 14 files changed, 143 insertions(+), 153 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 15164682d..179c9154b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -55,7 +55,7 @@ internal class AssignmentAsmGen(private val program: PtProgram, else true - fun assignCarryResult(target: PtAssignTarget, saveA: Boolean) { + fun assignCarryFlagResult(target: PtAssignTarget, saveA: Boolean) { if(saveA) asmgen.out(" pha") asmgen.out(" lda #0 | rol a") val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) @@ -63,6 +63,45 @@ internal class AssignmentAsmGen(private val program: PtProgram, if(saveA) asmgen.out(" pla") } + fun assignZeroFlagResult(target: PtAssignTarget, saveA: Boolean) { + if(saveA) asmgen.out(" pha") + asmgen.out(""" + beq + + lda #0 + beq ++ ++ lda #1 ++""") + val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) + assignRegisterByte(tgt, CpuRegister.A, false, false) + if(saveA) asmgen.out(" pla") + } + + fun assignNegativeFlagResult(target: PtAssignTarget, saveA: Boolean) { + if(saveA) asmgen.out(" pha") + asmgen.out(""" + bmi + + lda #0 + beq ++ ++ lda #1 ++""") + val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) + assignRegisterByte(tgt, CpuRegister.A, false, false) + if(saveA) asmgen.out(" pla") + } + + fun assignOverflowFlagResult(target: PtAssignTarget, saveA: Boolean) { + if(saveA) asmgen.out(" pha") + asmgen.out(""" + bvs + + lda #0 + beq ++ ++ lda #1 ++""") + val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) + assignRegisterByte(tgt, CpuRegister.A, false, false) + if(saveA) asmgen.out(" pla") + } + fun assignRegisterResults(registersResults: List>) { registersResults.forEach { (returns, target) -> target as PtAssignTarget @@ -94,9 +133,6 @@ internal class AssignmentAsmGen(private val program: PtProgram, if(statusFlagResults.size>1) TODO("handle multiple status flag results") val (returns, target) = statusFlagResults.single() - if(returns.register.statusflag!=Statusflag.Pc) - TODO("other status flag for return value") - target as PtAssignTarget if(target.void) { // forget about the Carry status flag, only assign the normal return values @@ -110,10 +146,21 @@ internal class AssignmentAsmGen(private val program: PtProgram, // all other results are just stored into identifiers directly so first handle those // (simple store instructions that don't modify the carry flag) assignRegisterResults(registersResults) - assignCarryResult(target, false) - return + return when(returns.register.statusflag!!) { + Statusflag.Pc -> assignCarryFlagResult(target, false) + Statusflag.Pz -> assignZeroFlagResult(target, false) + Statusflag.Pv -> assignOverflowFlagResult(target, false) + Statusflag.Pn -> assignNegativeFlagResult(target, false) + } + } + + val saveA = needsToSaveA(registersResults) + when(returns.register.statusflag!!) { + Statusflag.Pc -> assignCarryFlagResult(target, saveA) + Statusflag.Pz -> assignZeroFlagResult(target, saveA) + Statusflag.Pv -> assignOverflowFlagResult(target, saveA) + Statusflag.Pn -> assignNegativeFlagResult(target, saveA) } - assignCarryResult(target, needsToSaveA(registersResults)) } assignRegisterResults(registersResults) } else { diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index c5f5fa171..2c645c274 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -105,18 +105,6 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr ; ---- utilities ----- -asmsub STOP2() clobbers(X) -> bool @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 {{ diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index 8efdfcba8..a33516d90 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -102,18 +102,6 @@ romsub $FFED = SCREEN() -> ubyte @ X, ubyte @ Y ; read number of romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) clobbers(A) -> 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 -asmsub STOP2() clobbers(X) -> bool @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 {{ diff --git a/compiler/res/prog8lib/cx16/diskio.p8 b/compiler/res/prog8lib/cx16/diskio.p8 index afa2639eb..5568c570a 100644 --- a/compiler/res/prog8lib/cx16/diskio.p8 +++ b/compiler/res/prog8lib/cx16/diskio.p8 @@ -81,7 +81,8 @@ diskio { void cbm.CHRIN() ; skip 2 bytes void cbm.CHRIN() status = cbm.READST() - if cbm.STOP2() + void cbm.STOP() + if_z break } status = cbm.READST() diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 9e35f0eeb..351dc35c7 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -19,7 +19,7 @@ romsub $FF8D = VECTOR(uword userptr @ XY, bool dir @ Pc) clobbers(A,Y) ; rea 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. NOTE: as a Cx16 extension, also returns the number of RAM memory banks in register A ! See cx16.numbanks() +romsub $FF99 = MEMTOP(uword address @ XY, bool dir @ Pc) -> uword @ XY, ubyte @A ; read/set top of memory pointer. NOTE: on the Cx16 also returns the number of RAM memory banks in A! Also see cx16.numbanks() 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, also called kbd_scan romsub $FFA2 = SETTMO(ubyte timeout @ A) ; set time-out flag for IEEE bus @@ -32,7 +32,7 @@ romsub $FFB4 = TALK(ubyte device @ A) clobbers(A) ; command serial romsub $FFB7 = READST() -> ubyte @ A ; read I/O status word (use CLEARST to reset it to 0) 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 $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 @@ -42,37 +42,33 @@ romsub $FFD2 = CHROUT(ubyte character @ A) ; (via 806 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) clobbers (X, Y) -> bool @ Pc, ubyte @ A ; (via 818 ($332)) save to a device. See also BSAVE 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 $FFDE = RDTIM() -> ubyte @ A, ubyte @ X, ubyte @ Y ; read the software clock (in little endian order: A=lo,X=mid,Y=high) , however use RDTIM_safe() instead +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) clobbers(A) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Use txt.plot for a 'safe' wrapper that preserves X. +romsub $FFF0 = PLOT(ubyte col @ Y, ubyte row @ X, bool dir @ Pc) clobbers(A) -> ubyte @ X, ubyte @ Y ; read/set position of cursor on screen. Also see txt.plot romsub $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices ; ---- utility -asmsub STOP2() clobbers(X) -> bool @A { - ; -- check if STOP key was pressed, returns true if so. More convenient to use than STOP() because that only sets the zero 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. Also avoids ram bank issue for irqs. +asmsub RDTIM_safe() -> ubyte @ A, ubyte @ X, ubyte @ Y { + ; -- read the software clock (in little endian order: A=lo,X=mid,Y=high) + ; with safeguard for ram bank issue for irqs. %asm {{ php sei jsr cbm.RDTIM plp - cli + rts + }} +} + +asmsub RDTIM16() clobbers(X) -> uword @AY { + ; -- like RDTIM_safe() but only returning the lower 16 bits in AY for convenience. + %asm {{ + jsr RDTIM_safe pha txa tay @@ -295,33 +291,33 @@ cx16 { &ubyte VERA_SPI_CTRL = VERA_BASE + $001F ; Vera FX registers: (accessing depends on particular DCSEL value set in VERA_CTRL!) - &ubyte VERA_FX_CTRL = VERA_BASE + $0009 - &ubyte VERA_FX_TILEBASE = VERA_BASE + $000a - &ubyte VERA_FX_MAPBASE = VERA_BASE + $000b - &ubyte VERA_FX_MULT = VERA_BASE + $000c - &ubyte VERA_FX_X_INCR_L = VERA_BASE + $0009 - &ubyte VERA_FX_X_INCR_H = VERA_BASE + $000a - &uword VERA_FX_X_INCR = VERA_BASE + $0009 - &ubyte VERA_FX_Y_INCR_L = VERA_BASE + $000b - &ubyte VERA_FX_Y_INCR_H = VERA_BASE + $000c - &uword VERA_FX_Y_INCR = VERA_BASE + $000b - &ubyte VERA_FX_X_POS_L = VERA_BASE + $0009 - &ubyte VERA_FX_X_POS_H = VERA_BASE + $000a - &uword VERA_FX_X_POS = VERA_BASE + $0009 - &ubyte VERA_FX_Y_POS_L = VERA_BASE + $000b - &ubyte VERA_FX_Y_POS_H = VERA_BASE + $000c - &uword VERA_FX_Y_POS = VERA_BASE + $000b - &ubyte VERA_FX_X_POS_S = VERA_BASE + $0009 - &ubyte VERA_FX_Y_POS_S = VERA_BASE + $000a - &ubyte VERA_FX_POLY_FILL_L = VERA_BASE + $000b - &ubyte VERA_FX_POLY_FILL_H = VERA_BASE + $000c - &uword VERA_FX_POLY_FILL = VERA_BASE + $000b - &ubyte VERA_FX_CACHE_L = VERA_BASE + $0009 - &ubyte VERA_FX_CACHE_M = VERA_BASE + $000a - &ubyte VERA_FX_CACHE_H = VERA_BASE + $000b - &ubyte VERA_FX_CACHE_U = VERA_BASE + $000c - &ubyte VERA_FX_ACCUM = VERA_BASE + $000a - &ubyte VERA_FX_ACCUM_RESET = VERA_BASE + $0009 + &ubyte VERA_FX_CTRL = VERA_BASE + $0009 + &ubyte VERA_FX_TILEBASE = VERA_BASE + $000a + &ubyte VERA_FX_MAPBASE = VERA_BASE + $000b + &ubyte VERA_FX_MULT = VERA_BASE + $000c + &ubyte VERA_FX_X_INCR_L = VERA_BASE + $0009 + &ubyte VERA_FX_X_INCR_H = VERA_BASE + $000a + &uword VERA_FX_X_INCR = VERA_BASE + $0009 + &ubyte VERA_FX_Y_INCR_L = VERA_BASE + $000b + &ubyte VERA_FX_Y_INCR_H = VERA_BASE + $000c + &uword VERA_FX_Y_INCR = VERA_BASE + $000b + &ubyte VERA_FX_X_POS_L = VERA_BASE + $0009 + &ubyte VERA_FX_X_POS_H = VERA_BASE + $000a + &uword VERA_FX_X_POS = VERA_BASE + $0009 + &ubyte VERA_FX_Y_POS_L = VERA_BASE + $000b + &ubyte VERA_FX_Y_POS_H = VERA_BASE + $000c + &uword VERA_FX_Y_POS = VERA_BASE + $000b + &ubyte VERA_FX_X_POS_S = VERA_BASE + $0009 + &ubyte VERA_FX_Y_POS_S = VERA_BASE + $000a + &ubyte VERA_FX_POLY_FILL_L = VERA_BASE + $000b + &ubyte VERA_FX_POLY_FILL_H = VERA_BASE + $000c + &uword VERA_FX_POLY_FILL = VERA_BASE + $000b + &ubyte VERA_FX_CACHE_L = VERA_BASE + $0009 + &ubyte VERA_FX_CACHE_M = VERA_BASE + $000a + &ubyte VERA_FX_CACHE_H = VERA_BASE + $000b + &ubyte VERA_FX_CACHE_U = VERA_BASE + $000c + &ubyte VERA_FX_ACCUM = VERA_BASE + $000a + &ubyte VERA_FX_ACCUM_RESET = VERA_BASE + $0009 ; VERA_PSG_BASE = $1F9C0 @@ -376,20 +372,16 @@ cx16 { ; ---- Commander X-16 additions on top of C64 kernal routines ---- ; spelling of the names is taken from the Commander X-16 rom sources -; supported C128 additions romsub $ff4a = CLOSE_ALL(ubyte device @A) clobbers(A,X,Y) romsub $ff59 = LKUPLA(ubyte la @A) clobbers(A,X,Y) romsub $ff5c = LKUPSA(ubyte sa @Y) clobbers(A,X,Y) -romsub $ff5f = screen_mode(ubyte mode @A, bool getCurrent @Pc) clobbers(X, Y) -> ubyte @A, bool @Pc ; note: X,Y size result is not supported, use SCREEN or get_screen_mode routine for that -romsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) ; incompatible with C128 dlchr() -; not yet supported: romsub $ff65 = pfkey() clobbers(A,X,Y) +romsub $ff5f = screen_mode(ubyte mode @A, bool getCurrent @Pc) -> ubyte @A, ubyte @X, ubyte @Y, bool @Pc ; also see SCREEN or get_screen_mode() +romsub $ff62 = screen_set_charset(ubyte charset @A, uword charsetptr @XY) clobbers(A,X,Y) romsub $ff6e = JSRFAR() ; following word = address to call, byte after that=rom/ram bank it is in romsub $ff74 = fetch(ubyte bank @X, ubyte index @Y) clobbers(X) -> ubyte @A romsub $ff77 = stash(ubyte data @A, ubyte bank @X, ubyte index @Y) clobbers(X) romsub $ff7d = PRIMM() -; It's not documented what registers are clobbered, so we assume the worst for all following kernal routines...: - ; high level graphics & fonts romsub $ff20 = GRAPH_init(uword vectors @R0) clobbers(A,X,Y) romsub $ff23 = GRAPH_clear() clobbers(A,X,Y) @@ -422,7 +414,6 @@ romsub $ff1a = FB_filter_pixels(uword pointer @ R0, uword count @R1) clobbers(A romsub $ff1d = FB_move_pixels(uword sx @R0, uword sy @R1, uword tx @R2, uword ty @R3, uword count @R4) clobbers(A,X,Y) ; misc -romsub $FEBA = BSAVE(ubyte zp_startaddr @ A, uword endaddr @ XY) clobbers (X, Y) -> bool @ Pc, ubyte @ A ; like cbm.SAVE, but omits the 2-byte prg header romsub $fec6 = i2c_read_byte(ubyte device @X, ubyte offset @Y) clobbers (X,Y) -> ubyte @A, bool @Pc romsub $fec9 = i2c_write_byte(ubyte device @X, ubyte offset @Y, ubyte data @A) clobbers (A,X,Y) -> bool @Pc romsub $feb4 = i2c_batch_read(ubyte device @X, uword buffer @R0, uword length @R1, bool advance @Pc) clobbers(A,Y) -> bool @Pc @@ -446,6 +437,7 @@ romsub $fecc = monitor() clobbers(A,X,Y) romsub $ff44 = MACPTR(ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) clobbers(A) -> bool @Pc, uword @XY romsub $feb1 = MCIOUT(ubyte length @A, uword buffer @XY, bool dontAdvance @Pc) clobbers(A) -> bool @Pc, uword @XY +romsub $FEBA = BSAVE(ubyte zp_startaddr @ A, uword endaddr @ XY) clobbers (X, Y) -> bool @ Pc, ubyte @ A ; like cbm.SAVE, but omits the 2-byte prg header romsub $ff47 = enter_basic(bool cold_or_warm @Pc) clobbers(A,X,Y) romsub $ff4d = clock_set_date_time(uword yearmonth @R0, uword dayhours @R1, uword minsecs @R2, uword jiffiesweekday @R3) clobbers(A, X, Y) romsub $ff50 = clock_get_date_time() clobbers(A, X, Y) -> uword @R0, uword @R1, uword @R2, uword @R3 ; result registers see clock_set_date_time() @@ -453,16 +445,14 @@ romsub $ff50 = clock_get_date_time() clobbers(A, X, Y) -> uword @R0, uword @R1 ; keyboard, mouse, joystick ; note: also see the cbm.kbdbuf_clear() helper routine romsub $febd = kbdbuf_peek() -> ubyte @A, ubyte @X ; key in A, queue length in X -romsub $febd = kbdbuf_peek2() -> uword @AX ; alternative to above to not have the hassle to deal with multiple return values romsub $fec0 = kbdbuf_get_modifiers() -> ubyte @A romsub $fec3 = kbdbuf_put(ubyte key @A) clobbers(X) romsub $fed2 = keymap(uword identifier @XY, bool read @Pc) -> bool @Pc romsub $ff68 = mouse_config(byte shape @A, ubyte resX @X, ubyte resY @Y) clobbers (A, X, Y) -romsub $ff6b = mouse_get(ubyte zpdataptr @X) -> ubyte @A +romsub $ff6b = mouse_get(ubyte zpdataptr @X) -> ubyte @A ; use mouse_pos() instead romsub $ff71 = mouse_scan() clobbers(A, X, Y) romsub $ff53 = joystick_scan() clobbers(A, X, Y) -romsub $ff56 = joystick_get(ubyte joynr @A) -> ubyte @A, ubyte @X, ubyte @Y -romsub $ff56 = joystick_get2(ubyte joynr @A) clobbers(Y) -> uword @AX ; alternative to above to not have the hassle to deal with multiple return values +romsub $ff56 = joystick_get(ubyte joynr @A) -> uword @AX, bool @Y ; note: everything is inverted ; X16Edit (rom bank 13/14 but you ideally should use the routine search_x16edit() to search for the correct bank) romsub $C000 = x16edit_default() clobbers(A,X,Y) @@ -559,7 +549,7 @@ asmsub set_screen_mode(ubyte mode @A) clobbers(A,X,Y) -> bool @Pc { }} } -asmsub get_screen_mode() -> byte @A, byte @X, byte @Y { +asmsub get_screen_mode() -> ubyte @A, ubyte @X, ubyte @Y { ; -- convenience wrapper for screen_mode() to just get the current mode in A, and size in characters in X+Y ; this does need a piece of inlined asm to call it ans store the result values if you call this from prog8 code ; Note: you can also just do the SEC yourself and simply call screen_mode() directly, @@ -581,9 +571,10 @@ asmsub mouse_config2(byte shape @A) clobbers (A, X, Y) { }} } -asmsub mouse_pos() clobbers(X) -> ubyte @A { +asmsub mouse_pos() clobbers(X) -> ubyte @A, word @R0, word @R1 { ; -- short wrapper around mouse_get() kernal routine: ; -- gets the position of the mouse cursor in cx16.r0 and cx16.r1 (x/y coordinate), returns mouse button status in A. + ; Note: mouse pointer needs to be enabled for this to do anything. %asm {{ ldx #cx16.r0 jmp cx16.mouse_get @@ -594,6 +585,7 @@ asmsub mouse_pos() clobbers(X) -> ubyte @A { asmsub mouse_set_pos(uword xpos @R0, uword ypos @R1) clobbers(X) { ; -- sets the mouse sprite position + ; Note: mouse pointer needs to be enabled for this to do anything. %asm {{ ldx #cx16.r0L lda #EXTAPI_mouse_set_position @@ -1230,7 +1222,7 @@ sub search_x16edit() -> ubyte { } asmsub cpu_is_65816() -> bool @A { - ; Returns true when you have a 65816 cpu, false when it's a 6502. + ; -- Returns true when you have a 65816 cpu, false when it's a 6502. %asm {{ php clv @@ -1246,7 +1238,7 @@ sub search_x16edit() -> ubyte { } sub set_program_args(uword args_ptr, ubyte args_size) { - ; Set the inter-program arguments. + ; -- Set the inter-program arguments. ; standardized way to pass arguments between programs is in ram bank 0, address $bf00-$bfff. ; see https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2007%20-%20Memory%20Map.md#bank-0 sys.push(getrambank()) @@ -1258,9 +1250,9 @@ sub search_x16edit() -> ubyte { } asmsub get_program_args(uword buffer @R0, ubyte buf_size @R1, bool binary @Pc) { - ; Retrieve the inter-program arguments. If binary=false, it treats them as a string (stops copying at first zero). + ; -- Retrieve the inter-program arguments. If binary=false, it treats them as a string (stops copying at first zero). ; standardized way to pass arguments between programs is in ram bank 0, address $bf00-$bfff. - ; see https://github.com/X16Community/x16-docs/blob/master/X16%20Reference%20-%2007%20-%20Memory%20Map.md#bank-0 + ; see https://github.com/X16Community/x16-docs/blob/a21a320aebec2c7b93f1bd90b97dcfd73fff4ad0/X16%20Reference%20-%2008%20-%20Memory%20Map.md#bank-0 %asm {{ lda #0 rol a @@ -1287,17 +1279,21 @@ _continue iny } sub reset_system() { - ; Soft-reset the system back to initial power-on Basic prompt. + ; -- Soft-reset the system back to initial power-on Basic prompt. sys.reset_system() } sub poweroff_system() { - ; use the SMC to shutdown the computer + ; -- use the SMC to shutdown the computer void cx16.i2c_write_byte($42, $01, $00) } - sub set_led_brightness(ubyte brightness) { - void cx16.i2c_write_byte($42, $05, brightness) + sub set_led_state(bool on) { + ; -- sets the computer's activity led on/off + cx16.r0L = 0 + if on + cx16.r0 = 255 + void cx16.i2c_write_byte($42, $05, cx16.r0L) } } @@ -1514,11 +1510,6 @@ asmsub set_rasterline(uword line @AY) { void cx16.i2c_write_byte($42, $01, $00) } - sub set_leds_brightness(ubyte activity, ubyte power) { - void cx16.i2c_write_byte($42, $04, power) - void cx16.i2c_write_byte($42, $05, activity) - } - asmsub wait(uword jiffies @AY) clobbers(X) { ; --- 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 diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 59d1dff3a..9485497ca 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -59,7 +59,8 @@ diskio { void cbm.CHRIN() ; skip 2 bytes void cbm.CHRIN() status = cbm.READST() - if cbm.STOP2() + void cbm.STOP() + if_z break } status = cbm.READST() diff --git a/compiler/res/prog8lib/pet32/syslib.p8 b/compiler/res/prog8lib/pet32/syslib.p8 index ff2a497f9..81eef4ead 100644 --- a/compiler/res/prog8lib/pet32/syslib.p8 +++ b/compiler/res/prog8lib/pet32/syslib.p8 @@ -34,18 +34,6 @@ romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; get a characte romsub $FFE7 = CLALL() clobbers(A,X) ; close all files romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock -asmsub STOP2() clobbers(X) -> bool @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 SETTIM(ubyte low @ A, ubyte middle @ X, ubyte high @ Y) { ; PET stub to set the software clock %asm {{ diff --git a/docs/source/syntaxreference.rst b/docs/source/syntaxreference.rst index 328169bb4..53f14b600 100644 --- a/docs/source/syntaxreference.rst +++ b/docs/source/syntaxreference.rst @@ -671,7 +671,7 @@ Multiple return values ^^^^^^^^^^^^^^^^^^^^^^ Normal subroutines can only return zero or one return values. However, the special ``asmsub`` routines (implemented in assembly code) or ``romsub`` routines -(referencing a routine in Kernal ROM) can return more than one return value. +(referencing an external routine in ROM or elsewhere in memory) can return more than one return value. For example a status in the carry bit and a number in A, or a 16-bit value in A/Y registers. In these cases, it is possible to do a "multi assign" where the multiple return values of the subroutine call, are all assigned to individual assignment targets. You simply write them as a comma separated list, @@ -716,15 +716,15 @@ The return type has to be specified if the subroutine returns a value. Assembly / ROM subroutines ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Subroutines implemented in ROM are usually defined by compiler library files, with the following syntax:: +External subroutines implemented in ROM (or elsewhere in memory) are usually defined by compiler library files, with the following syntax:: romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> clobbers() -> bool @Pc, ubyte @ A, ubyte @ X, ubyte @ Y -This defines the ``LOAD`` subroutine at ROM memory address $FFD5, taking arguments in all three registers A, X and Y, +This defines the ``LOAD`` subroutine at memory address $FFD5, taking arguments in all three registers A, X and Y, and returning stuff in several registers as well. The ``clobbers`` clause is used to signify to the compiler what CPU registers are clobbered by the call instead of being unchanged or returning a meaningful result value. -User subroutines in the program source code that are implemented purely in assembly and which have an assembly calling convention (i.e. +User-written subroutines in the program source code itself, implemented purely in assembly and which have an assembly calling convention (i.e. the parameters are strictly passed via cpu registers), are defined with ``asmsub`` like this:: asmsub clear_screenchars (ubyte char @ A) clobbers(Y) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 0c203eb06..8d3b14f5b 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,6 +1,12 @@ TODO ==== +chess fails to compile (crash) + +remove redundant assignments in calls like this where the result registers are the same as the assigment targets: +void, cx16.r0s, cx16.r1s = cx16.mouse_pos() +(6502 + IR) + ... @@ -81,6 +87,7 @@ What if we were to re-introduce Structs in prog8? Some thoughts: Other language/syntax features to think about --------------------------------------------- +- allow returning multiple values from normal (non-asmsub) subroutines as well? Once that is done we can also clean up more of the library routines that now struggle to return multiple values. - add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram. challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)? How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ? diff --git a/examples/cx16/chunkedfile/demo.p8 b/examples/cx16/chunkedfile/demo.p8 index 88deea080..9c9740532 100644 --- a/examples/cx16/chunkedfile/demo.p8 +++ b/examples/cx16/chunkedfile/demo.p8 @@ -10,7 +10,7 @@ main { ubyte[256] bonkbuffer ;; diskio.fastmode(1) - set_screen_mode() + set_screen() cbm.SETTIM(0,0,0) mcf.set_callbacks(mcf_get_buffer, mcf_process_chunk) ; not needed if the stream has no custom chunk types @@ -35,7 +35,7 @@ main { txt.print(" jiffies.\n") } - sub set_screen_mode() { + sub set_screen() { ; 640x400 16 colors cx16.VERA_DC_VIDEO = (cx16.VERA_DC_VIDEO & %11001111) | %00100000 ; enable only layer 1 cx16.VERA_DC_HSCALE = 128 diff --git a/examples/cx16/spotlight.p8 b/examples/cx16/spotlight.p8 index 0fd6fff98..1d6d47174 100644 --- a/examples/cx16/spotlight.p8 +++ b/examples/cx16/spotlight.p8 @@ -37,7 +37,7 @@ main { ; spotlight repeat { - void cx16.mouse_pos() + void, cx16.r0s, cx16.r1s = cx16.mouse_pos() new_direction = math.direction(128, HEIGHT/2, clampx(cx16.r0), cx16.r1L) if new_direction != previous_direction { sys.waitvsync() diff --git a/examples/cx16/tehtriz.p8 b/examples/cx16/tehtriz.p8 index 31b1b8adf..caa90f591 100644 --- a/examples/cx16/tehtriz.p8 +++ b/examples/cx16/tehtriz.p8 @@ -97,7 +97,8 @@ waitkey: ubyte key=cbm.GETIN() keypress(key) - joystick(cx16.joystick_get2(1)) + cx16.r0,void = cx16.joystick_get(1) + joystick(cx16.r0) goto waitkey @@ -334,7 +335,7 @@ waitkey: ubyte key do { ; endless loop until user presses F1 or Start button to restart the game - cx16.r0 = cx16.joystick_get2(1) + cx16.r0, void = cx16.joystick_get(1) if cx16.r0 & %0000000000010000 == 0 break key = cbm.GETIN() diff --git a/examples/cx16/zsound/play-zsound.p8 b/examples/cx16/zsound/play-zsound.p8 index f7b9cbc3e..ea36b5398 100644 --- a/examples/cx16/zsound/play-zsound.p8 +++ b/examples/cx16/zsound/play-zsound.p8 @@ -88,7 +88,8 @@ zsound_lib: txt.print(" hz\nplaying song! hit enter to also play a digi sample!\n") repeat { - if cx16.joystick_get2(0)!=$ffff + cx16.r0, void = cx16.joystick_get(0) + if cx16.r0!=$ffff pcm_trigger_digi(digi_bank, digi_address) sys.waitvsync() diff --git a/examples/test.p8 b/examples/test.p8 index 1acaa823a..aed1ac724 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -4,29 +4,6 @@ main { sub start() { - ubyte @shared bytevar - uword @shared wordvar - bool flag - - wordvar, bytevar, void = test4() - if_cs - txt.print("true! ") - else - txt.print("false! ") - - txt.print_uwhex(wordvar, true) - txt.spc() - txt.print_ub(bytevar) - txt.nl() - } - - asmsub test4() -> uword @AY, ubyte @X, bool @Pc { - %asm {{ - lda #<$11ee - ldy #>$11ee - ldx #42 - clc - rts - }} + void, cx16.r0s, cx16.r1s = cx16.mouse_pos() } }