From 66a6659a6e81c979062a907c8ffcd2abe3c9ba5f Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 6 Apr 2024 02:16:21 +0200 Subject: [PATCH] cbm.STOP2() and cbm.GETIN2() convenience routines --- .../src/prog8/codegen/cpu6502/AsmGen.kt | 2 +- compiler/res/prog8lib/c128/syslib.p8 | 21 ++++++- compiler/res/prog8lib/c64/syslib.p8 | 22 ++++++- compiler/res/prog8lib/cx16/syslib.p8 | 21 ++++++- compiler/res/prog8lib/pet32/syslib.p8 | 22 ++++++- compiler/test/TestOptimization.kt | 58 +++++++++++++++++++ docs/source/todo.rst | 5 +- 7 files changed, 141 insertions(+), 10 deletions(-) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 221a7220e..bd16a7446 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -66,7 +66,7 @@ class AsmGen6502(val prefixSymbols: Boolean): ICodeGeneratorBackend { if(node.type in SplitWordArrayTypes && (lookupName.endsWith("_lsb") || lookupName.endsWith("_msb"))) { lookupName = lookupName.dropLast(4) } - val stNode = st.lookup(lookupName)!! + val stNode = st.lookup(lookupName) ?: throw AssemblyError("unknown identifier $node") if(stNode.astNode.definingBlock()?.options?.noSymbolPrefixing!=true) { val index = node.parent.children.indexOf(node) nodesToPrefix += node.parent to index diff --git a/compiler/res/prog8lib/c128/syslib.p8 b/compiler/res/prog8lib/c128/syslib.p8 index 2c645c274..7d8816ef1 100644 --- a/compiler/res/prog8lib/c128/syslib.p8 +++ b/compiler/res/prog8lib/c128/syslib.p8 @@ -93,8 +93,8 @@ romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> bool @Pc, ubyte @ A 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 $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; (via 808 ($328)) check the STOP key (and some others in A) also see STOP2 +romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; (via 810 ($32A)) get a character also see GETIN2 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 @@ -105,6 +105,23 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr ; ---- utilities ----- +inline asmsub STOP2() clobbers(X,A) -> bool @Pz { + ; -- just like STOP, but omits the special keys result value in A. + ; just for convenience because most of the times you're only interested in the stop pressed or not status. + %asm {{ + jsr cbm.STOP + }} +} + +inline asmsub GETIN2() clobbers(X,Y) -> ubyte @A { + ; -- just like GETIN, but omits the carry flag result value. + ; just for convenience because GETIN is so often used to just read keyboard input, + ; where you don't have to deal with a potential error status + %asm {{ + jsr cbm.GETIN + }} +} + 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 a33516d90..40342f2c9 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -94,14 +94,32 @@ romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> bool @Pc, ubyte @ A 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 $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; (via 808 ($328)) check the STOP key (and some others in A) also see STOP2 +romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; (via 810 ($32A)) get a character also see GETIN2 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 $FFF3 = IOBASE() -> uword @ XY ; read base address of I/O devices + +inline asmsub STOP2() clobbers(X,A) -> bool @Pz { + ; -- just like STOP, but omits the special keys result value in A. + ; just for convenience because most of the times you're only interested in the stop pressed or not status. + %asm {{ + jsr cbm.STOP + }} +} + +inline asmsub GETIN2() clobbers(X,Y) -> ubyte @A { + ; -- just like GETIN, but omits the carry flag result value. + ; just for convenience because GETIN is so often used to just read keyboard input, + ; where you don't have to deal with a potential error status + %asm {{ + jsr cbm.GETIN + }} +} + 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/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 351dc35c7..6fc23c235 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -43,8 +43,8 @@ romsub $FFD5 = LOAD(ubyte verify @ A, uword address @ XY) -> bool @Pc, ubyte @ A 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 (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 $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; (via 808 ($328)) check the STOP key (and some others in A) also see STOP2 +romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; (via 810 ($32A)) get a character also see GETIN2 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 @@ -53,6 +53,23 @@ romsub $FFF3 = IOBASE() -> uword @ XY ; read base addr ; ---- utility +inline asmsub STOP2() clobbers(X,A) -> bool @Pz { + ; -- just like STOP, but omits the special keys result value in A. + ; just for convenience because most of the times you're only interested in the stop pressed or not status. + %asm {{ + jsr cbm.STOP + }} +} + +inline asmsub GETIN2() clobbers(X,Y) -> ubyte @A { + ; -- just like GETIN, but omits the carry flag result value. + ; just for convenience because GETIN is so often used to just read keyboard input, + ; where you don't have to deal with a potential error status + %asm {{ + jsr cbm.GETIN + }} +} + 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. diff --git a/compiler/res/prog8lib/pet32/syslib.p8 b/compiler/res/prog8lib/pet32/syslib.p8 index 81eef4ead..0ed056552 100644 --- a/compiler/res/prog8lib/pet32/syslib.p8 +++ b/compiler/res/prog8lib/pet32/syslib.p8 @@ -29,11 +29,29 @@ romsub $FFC9 = CHKOUT(ubyte logical @ X) clobbers(A,X) ; define an outp romsub $FFCC = CLRCHN() clobbers(A,X) ; restore default devices romsub $FFCF = CHRIN() clobbers(X, Y) -> ubyte @ A ; input a character (for keyboard, read a whole line from the screen) A=byte read. romsub $FFD2 = CHROUT(ubyte character @ A) ; output a character -romsub $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; check the STOP key (and some others in A) -romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; get a character +romsub $FFE1 = STOP() clobbers(X) -> bool @ Pz, ubyte @ A ; check the STOP key (and some others in A) also see STOP2 +romsub $FFE4 = GETIN() clobbers(X,Y) -> bool @Pc, ubyte @ A ; get a character also see GETIN2 romsub $FFE7 = CLALL() clobbers(A,X) ; close all files romsub $FFEA = UDTIM() clobbers(A,X) ; update the software clock + +inline asmsub STOP2() clobbers(X,A) -> bool @Pz { + ; -- just like STOP, but omits the special keys result value in A. + ; just for convenience because most of the times you're only interested in the stop pressed or not status. + %asm {{ + jsr cbm.STOP + }} +} + +inline asmsub GETIN2() clobbers(X,Y) -> ubyte @A { + ; -- just like GETIN, but omits the carry flag result value. + ; just for convenience because GETIN is so often used to just read keyboard input, + ; where you don't have to deal with a potential error status + %asm {{ + jsr cbm.GETIN + }} +} + asmsub SETTIM(ubyte low @ A, ubyte middle @ X, ubyte high @ Y) { ; PET stub to set the software clock %asm {{ diff --git a/compiler/test/TestOptimization.kt b/compiler/test/TestOptimization.kt index 7c984dd1d..0af8d15dd 100644 --- a/compiler/test/TestOptimization.kt +++ b/compiler/test/TestOptimization.kt @@ -12,6 +12,9 @@ import prog8.ast.ParentSentinel import prog8.ast.Program import prog8.ast.expressions.* import prog8.ast.statements.* +import prog8.code.ast.PtAssignTarget +import prog8.code.ast.PtAssignment +import prog8.code.ast.PtFunctionCall import prog8.code.core.DataType import prog8.code.core.Position import prog8.code.target.C64Target @@ -972,4 +975,59 @@ main { (right2.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read") (right3.left as FunctionCallExpression).target.nameInSource shouldBe listOf("diskio", "f_read") } + + test("eliminate same target register assignments") { + val src=""" +%zeropage basicsafe +%option no_sysinit + +main { + romsub ${'$'}2000 = func1() clobbers(X) -> ubyte @A, word @R0, byte @R1 + romsub ${'$'}3000 = func2() clobbers(X) -> ubyte @A, uword @R0, uword @R1 + romsub ${'$'}4000 = func3() clobbers(X) -> ubyte @R0 + + sub start() { + bool flag + void cbm.GETIN() + flag, cx16.r1L = cbm.GETIN() + void, cx16.r0s, cx16.r1sL = func1() + void, cx16.r2, cx16.r1 = func2() + cx16.r0L = func3() + cx16.r0H = func3() + } +}""" + val result = compileText(C64Target(), true, src, writeAssembly = true)!! + val st = result.codegenAst!!.entrypoint()!!.children + st.size shouldBe 9 + (st[2] as PtFunctionCall).name shouldBe "cbm.GETIN" + (st[2] as PtFunctionCall).void shouldBe true + val a1 = st[3] as PtAssignment + (a1.value as PtFunctionCall).name shouldBe "cbm.GETIN" + a1.multiTarget shouldBe true + a1.children.size shouldBe 3 + (a1.children[0] as PtAssignTarget).void shouldBe false + (a1.children[0] as PtAssignTarget).identifier!!.name shouldBe "p8b_main.p8s_start.p8v_flag" + (a1.children[1] as PtAssignTarget).void shouldBe false + (a1.children[1] as PtAssignTarget).identifier!!.name shouldBe "cx16.r1L" + + (st[4] as PtFunctionCall).name shouldBe "p8b_main.p8s_func1" + (st[4] as PtFunctionCall).void shouldBe true + val a2 = st[5] as PtAssignment + (a2.value as PtFunctionCall).name shouldBe "p8b_main.p8s_func2" + a2.multiTarget shouldBe true + a2.children.size shouldBe 4 + (a2.children[0] as PtAssignTarget).void shouldBe true + (a2.children[1] as PtAssignTarget).void shouldBe false + (a2.children[1] as PtAssignTarget).identifier!!.name shouldBe "cx16.r2" + (a2.children[2] as PtAssignTarget).void shouldBe true + + (st[6] as PtFunctionCall).name shouldBe "p8b_main.p8s_func3" + (st[6] as PtFunctionCall).void shouldBe true + val a3 = st[7] as PtAssignment + (a3.value as PtFunctionCall).name shouldBe "p8b_main.p8s_func3" + a3.multiTarget shouldBe false + a3.children.size shouldBe 2 + (a3.children[0] as PtAssignTarget).void shouldBe false + (a3.children[0] as PtAssignTarget).identifier!!.name shouldBe "cx16.r0H" + } }) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 37bc1e701..0d7dbd1c6 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,7 +1,10 @@ TODO ==== -add unit test for what's now in test.p8 (multi assign stuff) +imageviewer is a lot larger now? + +fix compiler crash for assembler: unknown identifier [PtIdentifier:parser.proces_directive_str.prog8_subexprvar_1 UBYTE [src/assembler.p8: line 875 col 29-29]] +fix similar crash for petaxian check docs on assign about status register in assignment (can no longer be ignored, use void to not assign it)