From 7748c261da17e834ef130ee20c6b9b94ba0bf8c1 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Mon, 29 Nov 2021 23:13:04 +0100 Subject: [PATCH] rsave/rrestore moved from sys to builtin function to solve the stack related problem when calling it as a regular subroutine --- .../cpu6502/codegen/BuiltinFunctionsAsmGen.kt | 55 +++++++++++++++++++ compiler/res/prog8lib/c64/syslib.p8 | 44 --------------- compiler/res/prog8lib/cx16/syslib.p8 | 33 ----------- .../astprocessing/StatementReorderer.kt | 8 +-- .../compilerinterface/BuiltinFunctions.kt | 4 ++ docs/source/programming.rst | 6 ++ docs/source/technical.rst | 4 +- docs/source/todo.rst | 7 +-- examples/balls.p8 | 18 +----- syntax-files/IDEA/Prog8.xml | 2 +- syntax-files/NotepadPlusPlus/Prog8.xml | 2 +- syntax-files/Vim/prog8_builtins.vim | 2 +- 12 files changed, 76 insertions(+), 109 deletions(-) diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index 3e40b79e1..42b8a8a76 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -69,6 +69,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val "poke" -> throw AssemblyError("poke() should have been replaced by @()") "push", "pushw" -> funcPush(fcall, func) "pop", "popw" -> funcPop(fcall, func) + "rsave" -> funcRsave() + "rsavex" -> funcRsaveX() + "rrestore" -> funcRrestore() + "rrestorex" -> funcRrestoreX() "cmp" -> funcCmp(fcall) "callfar" -> funcCallFar(fcall) "callrom" -> funcCallRom(fcall) @@ -76,6 +80,57 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } + private fun funcRsave() { + if (asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(""" + php + pha + phy + phx""") + else + // see http://6502.org/tutorials/register_preservation.html + asmgen.out(""" + php + sta P8ZP_SCRATCH_REG + pha + txa + pha + tya + pha + lda P8ZP_SCRATCH_REG""") + } + + private fun funcRsaveX() { + if (asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" phx") + else + asmgen.out(" txa | pha") + } + + private fun funcRrestore() { + if (asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(""" + plx + ply + pla + plp""") + else + asmgen.out(""" + pla + tay + pla + tax + pla + plp""") + } + + private fun funcRrestoreX() { + if (asmgen.isTargetCpu(CpuType.CPU65c02)) + asmgen.out(" plx") + else + asmgen.out(" sta P8ZP_SCRATCH_B1 | pla | tax | lda P8ZP_SCRATCH_B1") + } + private fun funcPop(fcall: IFunctionCall, func: FSignature) { // note: because A is pushed first so popped last, saving A is often not required here. require(fcall.args[0] is IdentifierReference) { diff --git a/compiler/res/prog8lib/c64/syslib.p8 b/compiler/res/prog8lib/c64/syslib.p8 index 130f3a2cd..92d82c661 100644 --- a/compiler/res/prog8lib/c64/syslib.p8 +++ b/compiler/res/prog8lib/c64/syslib.p8 @@ -597,50 +597,6 @@ _longcopy }} } - - inline asmsub rsave() { - ; save cpu status flag and all registers A, X, Y. - ; see http://6502.org/tutorials/register_preservation.html - %asm {{ - php - sta P8ZP_SCRATCH_REG - pha - txa - pha - tya - pha - lda P8ZP_SCRATCH_REG - }} - } - - inline asmsub rrestore() { - ; restore all registers and cpu status flag - %asm {{ - pla - tay - pla - tax - pla - plp - }} - } - - inline asmsub rsavex() { - %asm {{ - txa - pha - }} - } - - inline asmsub rrestorex() { - %asm {{ - sta P8ZP_SCRATCH_REG - pla - tax - lda P8ZP_SCRATCH_REG - }} - } - inline asmsub read_flags() -> ubyte @A { %asm {{ php diff --git a/compiler/res/prog8lib/cx16/syslib.p8 b/compiler/res/prog8lib/cx16/syslib.p8 index 09cd6a92d..49efbe478 100644 --- a/compiler/res/prog8lib/cx16/syslib.p8 +++ b/compiler/res/prog8lib/cx16/syslib.p8 @@ -859,39 +859,6 @@ sys { }} } - inline asmsub rsave() { - ; save cpu status flag and all registers A, X, Y. - ; see http://6502.org/tutorials/register_preservation.html - %asm {{ - php - pha - phy - phx - }} - } - - inline asmsub rrestore() { - ; restore all registers and cpu status flag - %asm {{ - plx - ply - pla - plp - }} - } - - inline asmsub rsavex() { - %asm {{ - phx - }} - } - - inline asmsub rrestorex() { - %asm {{ - plx - }} - } - inline asmsub read_flags() -> ubyte @A { %asm {{ php diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index 7d519df5b..ac72f73cc 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -404,11 +404,11 @@ internal class StatementReorderer(val program: Program, // 0 params -> just GoSub val scope = AnonymousScope(mutableListOf(), call.position) if(function.shouldSaveX()) { - scope.statements += FunctionCallStatement(IdentifierReference(listOf("sys", "rsavex"), call.position), mutableListOf(), true, call.position) + scope.statements += FunctionCallStatement(IdentifierReference(listOf("rsavex"), call.position), mutableListOf(), true, call.position) } scope.statements += GoSub(null, call.target, null, call.position) if(function.shouldSaveX()) { - scope.statements += FunctionCallStatement(IdentifierReference(listOf("sys", "rrestorex"), call.position), mutableListOf(), true, call.position) + scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), call.position), mutableListOf(), true, call.position) } return listOf(IAstModification.ReplaceNode(call, scope, parent)) } else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args, function.asmParameterRegisters)) { @@ -423,7 +423,7 @@ internal class StatementReorderer(val program: Program, val argOrder = options.compTarget.asmsubArgsEvalOrder(function) val scope = AnonymousScope(mutableListOf(), call.position) if(function.shouldSaveX()) { - scope.statements += FunctionCallStatement(IdentifierReference(listOf("sys", "rsavex"), call.position), mutableListOf(), true, call.position) + scope.statements += FunctionCallStatement(IdentifierReference(listOf("rsavex"), call.position), mutableListOf(), true, call.position) } argOrder.reversed().forEach { val arg = call.args[it] @@ -438,7 +438,7 @@ internal class StatementReorderer(val program: Program, } scope.statements += GoSub(null, call.target, null, call.position) if(function.shouldSaveX()) { - scope.statements += FunctionCallStatement(IdentifierReference(listOf("sys", "rrestorex"), call.position), mutableListOf(), true, call.position) + scope.statements += FunctionCallStatement(IdentifierReference(listOf("rrestorex"), call.position), mutableListOf(), true, call.position) } return listOf(IAstModification.ReplaceNode(call, scope, parent)) } diff --git a/compilerInterfaces/src/prog8/compilerinterface/BuiltinFunctions.kt b/compilerInterfaces/src/prog8/compilerinterface/BuiltinFunctions.kt index c6650ca68..a69ab1f94 100644 --- a/compilerInterfaces/src/prog8/compilerinterface/BuiltinFunctions.kt +++ b/compilerInterfaces/src/prog8/compilerinterface/BuiltinFunctions.kt @@ -146,6 +146,10 @@ private val functionSignatures: List = listOf( FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null), FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null), FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), null), + FSignature("rsave" , false, emptyList(), null), + FSignature("rsavex" , false, emptyList(), null), + FSignature("rrestore" , false, emptyList(), null), + FSignature("rrestorex" , false, emptyList(), null), FSignature("rnd" , false, emptyList(), DataType.UBYTE), FSignature("rndw" , false, emptyList(), DataType.UWORD), FSignature("rndf" , false, emptyList(), DataType.FLOAT), diff --git a/docs/source/programming.rst b/docs/source/programming.rst index ea83ddd10..4698ce30f 100644 --- a/docs/source/programming.rst +++ b/docs/source/programming.rst @@ -951,6 +951,12 @@ callrom(bank, address, argumentaddress) ; NOTE: specific to cx16 compiler t and you'll have to set up a call in assembly code yourself that handles the banking and argument/returnvalues. +rsave, rsavex + Saves all registers including status (or only X) on the stack + +rrestore, rrestorex + Restore all registers including status (or only X) back from the cpu hardware stack + Library routines ---------------- diff --git a/docs/source/technical.rst b/docs/source/technical.rst index d0ce3691e..bc2973e9e 100644 --- a/docs/source/technical.rst +++ b/docs/source/technical.rst @@ -115,5 +115,5 @@ inaccessible unless you write a short piece of inline assembly code to deal with Prog8 also provides some help to deal with this: - you should use a ``clobbers(X)`` specification for asmsub routines that modify the X register; the compiler will preserve it for you automatically when such a routine is called -- the ``sys.rsave()`` and ``sys.rrestore()`` routines can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X) - +- the ``rsavex()`` and ``rrestorex()`` builtin functions can preserve and restore the X register +- the ``rsave()`` and ``rrestore()`` builtin functions can preserve and restore *all* registers (but this is very slow and overkill if you only need to save X) diff --git a/docs/source/todo.rst b/docs/source/todo.rst index e183318c6..51b580f53 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,12 +4,7 @@ TODO For next compiler release (7.4) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -BUG: sys.rsave/sys.rrestore can never work as subroutine because stack is used -> builtin funcs - -BUG: balls example crashes / animates wrong! - caused by c83882161521378f20dc0076c01e18e8556e363e 'refactor function arguments codegen a bit' - on the lines that call txt.setclr(BX[lp], BY[lp], BC[lp]) - they work with regular vars as args - so, something wrong with clobber/arg order when passing array lookups?? +BUG: line-circle-text doesn't compile anymore due to missing symbol! Add unit test to avoid this in the future? diff --git a/examples/balls.p8 b/examples/balls.p8 index 505f6c3cf..b0c276613 100644 --- a/examples/balls.p8 +++ b/examples/balls.p8 @@ -1,6 +1,4 @@ %import textio -%import test_stack - %zeropage basicsafe ; Note: this program is compatible with C64 and CX16. @@ -31,12 +29,8 @@ main { DY[lp] = rnd() & 1 } - ; start clock - c64.SETTIM(0,0,0) - ; display balls - uword frame - for frame in 0 to 999 { + repeat { ; Loop though all balls clearing current spot and setting new spot for lp in 0 to ballCount-1 { @@ -74,17 +68,7 @@ main { txt.setclr(BX[lp], BY[lp], BC[lp]) } - ;txt.plot(0,0) - ;txt.print_uw(frame) - sys.waitvsync() } - - uword jiffies = c64.RDTIM16() - txt.print("\nbenchmark: ") - txt.print_uw(jiffies) - txt.print(" jiffies for 1000 frames.\n") - - ; test_stack.test() } } diff --git a/syntax-files/IDEA/Prog8.xml b/syntax-files/IDEA/Prog8.xml index 44e92201c..c47bc3ee1 100644 --- a/syntax-files/IDEA/Prog8.xml +++ b/syntax-files/IDEA/Prog8.xml @@ -14,7 +14,7 @@ - + diff --git a/syntax-files/NotepadPlusPlus/Prog8.xml b/syntax-files/NotepadPlusPlus/Prog8.xml index 8be5a8bcf..c39aa7d40 100644 --- a/syntax-files/NotepadPlusPlus/Prog8.xml +++ b/syntax-files/NotepadPlusPlus/Prog8.xml @@ -27,7 +27,7 @@ void const str byte ubyte word uword float zp shared %address %asm %asmbinary %asminclude %breakpoint %import %launcher %option %output %zeropage %zpreserved inline sub asmsub romsub clobbers asm if when else if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z for in step do while repeat break return goto - abs acos all any asin atan avg callfar callrom ceil cmp cos cos16 cos16u cos8 cos8u cosr8 cosr8u cosr16 cosr16u deg floor len ln log2 lsb lsl lsr max memory min mkword msb peek peekw poke pokew push pushw pop popw rad reverse rnd rndf rndw rol rol2 ror ror2 round sgn sin sin16 sin16u sin8 sin8u sinr8 sinr8u sinr16 sinr16u sizeof sort sqrt sqrt16 sum swap tan + abs acos all any asin atan avg callfar callrom ceil cmp cos cos16 cos16u cos8 cos8u cosr8 cosr8u cosr16 cosr16u deg floor len ln log2 lsb lsl lsr max memory min mkword msb peek peekw poke pokew push pushw pop popw rsave rsavex rrestore rrestorex rad reverse rnd rndf rndw rol rol2 ror ror2 round sgn sin sin16 sin16u sin8 sin8u sinr8 sinr8u sinr16 sinr16u sizeof sort sqrt sqrt16 sum swap tan true false not and or xor as to downto diff --git a/syntax-files/Vim/prog8_builtins.vim b/syntax-files/Vim/prog8_builtins.vim index 21470a480..617806cac 100644 --- a/syntax-files/Vim/prog8_builtins.vim +++ b/syntax-files/Vim/prog8_builtins.vim @@ -15,7 +15,7 @@ syn keyword prog8BuiltInFunc sqrt16 sqrt tan syn keyword prog8BuiltInFunc any all len max min reverse sum sort " Miscellaneous functions -syn keyword prog8BuiltInFunc cmp lsb msb mkword peek peekw poke pokew rnd rndw push pushw pop popw +syn keyword prog8BuiltInFunc cmp lsb msb mkword peek peekw poke pokew rnd rndw push pushw pop popw rsave rsavex rrestore rrestorex syn keyword prog8BuiltInFunc rndf rol rol2 ror ror2 sizeof syn keyword prog8BuiltInFunc swap memory callfar callrom