rsave/rrestore moved from sys to builtin function to solve the stack related problem when calling it as a regular subroutine

This commit is contained in:
Irmen de Jong 2021-11-29 23:13:04 +01:00
parent a2db44f80c
commit 7748c261da
12 changed files with 76 additions and 109 deletions

View File

@ -69,6 +69,10 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
"poke" -> throw AssemblyError("poke() should have been replaced by @()") "poke" -> throw AssemblyError("poke() should have been replaced by @()")
"push", "pushw" -> funcPush(fcall, func) "push", "pushw" -> funcPush(fcall, func)
"pop", "popw" -> funcPop(fcall, func) "pop", "popw" -> funcPop(fcall, func)
"rsave" -> funcRsave()
"rsavex" -> funcRsaveX()
"rrestore" -> funcRrestore()
"rrestorex" -> funcRrestoreX()
"cmp" -> funcCmp(fcall) "cmp" -> funcCmp(fcall)
"callfar" -> funcCallFar(fcall) "callfar" -> funcCallFar(fcall)
"callrom" -> funcCallRom(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) { private fun funcPop(fcall: IFunctionCall, func: FSignature) {
// note: because A is pushed first so popped last, saving A is often not required here. // note: because A is pushed first so popped last, saving A is often not required here.
require(fcall.args[0] is IdentifierReference) { require(fcall.args[0] is IdentifierReference) {

View File

@ -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 { inline asmsub read_flags() -> ubyte @A {
%asm {{ %asm {{
php php

View File

@ -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 { inline asmsub read_flags() -> ubyte @A {
%asm {{ %asm {{
php php

View File

@ -404,11 +404,11 @@ internal class StatementReorderer(val program: Program,
// 0 params -> just GoSub // 0 params -> just GoSub
val scope = AnonymousScope(mutableListOf(), call.position) val scope = AnonymousScope(mutableListOf(), call.position)
if(function.shouldSaveX()) { 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) scope.statements += GoSub(null, call.target, null, call.position)
if(function.shouldSaveX()) { 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)) return listOf(IAstModification.ReplaceNode(call, scope, parent))
} else if(!options.compTarget.asmsubArgsHaveRegisterClobberRisk(call.args, function.asmParameterRegisters)) { } 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 argOrder = options.compTarget.asmsubArgsEvalOrder(function)
val scope = AnonymousScope(mutableListOf(), call.position) val scope = AnonymousScope(mutableListOf(), call.position)
if(function.shouldSaveX()) { 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 { argOrder.reversed().forEach {
val arg = call.args[it] val arg = call.args[it]
@ -438,7 +438,7 @@ internal class StatementReorderer(val program: Program,
} }
scope.statements += GoSub(null, call.target, null, call.position) scope.statements += GoSub(null, call.target, null, call.position)
if(function.shouldSaveX()) { 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)) return listOf(IAstModification.ReplaceNode(call, scope, parent))
} }

View File

@ -146,6 +146,10 @@ private val functionSignatures: List<FSignature> = listOf(
FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null), FSignature("popw" , false, listOf(FParam("target", WordDatatypes)), null),
FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null), FSignature("push" , false, listOf(FParam("value", ByteDatatypes)), null),
FSignature("pushw" , false, listOf(FParam("value", WordDatatypes)), 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("rnd" , false, emptyList(), DataType.UBYTE),
FSignature("rndw" , false, emptyList(), DataType.UWORD), FSignature("rndw" , false, emptyList(), DataType.UWORD),
FSignature("rndf" , false, emptyList(), DataType.FLOAT), FSignature("rndf" , false, emptyList(), DataType.FLOAT),

View File

@ -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 and you'll have to set up a call in assembly code yourself that handles the banking and
argument/returnvalues. 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 Library routines
---------------- ----------------

View File

@ -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: 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 - 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)

View File

@ -4,12 +4,7 @@ TODO
For next compiler release (7.4) For next compiler release (7.4)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
BUG: sys.rsave/sys.rrestore can never work as subroutine because stack is used -> builtin funcs BUG: line-circle-text doesn't compile anymore due to missing symbol!
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??
Add unit test to avoid this in the future? Add unit test to avoid this in the future?

View File

@ -1,6 +1,4 @@
%import textio %import textio
%import test_stack
%zeropage basicsafe %zeropage basicsafe
; Note: this program is compatible with C64 and CX16. ; Note: this program is compatible with C64 and CX16.
@ -31,12 +29,8 @@ main {
DY[lp] = rnd() & 1 DY[lp] = rnd() & 1
} }
; start clock
c64.SETTIM(0,0,0)
; display balls ; display balls
uword frame repeat {
for frame in 0 to 999 {
; Loop though all balls clearing current spot and setting new spot ; Loop though all balls clearing current spot and setting new spot
for lp in 0 to ballCount-1 { for lp in 0 to ballCount-1 {
@ -74,17 +68,7 @@ main {
txt.setclr(BX[lp], BY[lp], BC[lp]) txt.setclr(BX[lp], BY[lp], BC[lp])
} }
;txt.plot(0,0)
;txt.print_uw(frame)
sys.waitvsync() sys.waitvsync()
} }
uword jiffies = c64.RDTIM16()
txt.print("\nbenchmark: ")
txt.print_uw(jiffies)
txt.print(" jiffies for 1000 frames.\n")
; test_stack.test()
} }
} }

View File

@ -14,7 +14,7 @@
<keywords keywords="&amp;;-&gt;;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" /> <keywords keywords="&amp;;-&gt;;@;\$;and;as;asmsub;break;clobbers;do;downto;else;false;for;goto;if;if_cc;if_cs;if_eq;if_mi;if_ne;if_neg;if_nz;if_pl;if_pos;if_vc;if_vs;if_z;in;inline;not;or;repeat;return;romsub;step;sub;to;true;until;when;while;xor;~" ignore_case="false" />
<keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved" /> <keywords2 keywords="%address;%asm;%asmbinary;%asminclude;%breakpoint;%import;%launcher;%option;%output;%zeropage;%zpreserved" />
<keywords3 keywords="byte;const;float;shared;str;ubyte;uword;void;word;zp" /> <keywords3 keywords="byte;const;float;shared;str;ubyte;uword;void;word;zp" />
<keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;cosr16;cosr16u;cosr8;cosr8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;sgn;sin;sin16;sin16u;sin8;sin8u;sinr16;sinr16u;sinr8;sinr8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" /> <keywords4 keywords="abs;acos;all;any;asin;atan;avg;callfar;callrom;ceil;cmp;cos;cos16;cos16u;cos8;cos8u;cosr16;cosr16u;cosr8;cosr8u;deg;floor;len;ln;log2;lsb;lsl;lsr;max;memory;min;mkword;msb;peek;peekw;poke;pokew;pop;popw;push;pushw;rad;reverse;rnd;rndf;rndw;rol;rol2;ror;ror2;round;rrestore;rrestorex;rsave;rsavex;sgn;sin;sin16;sin16u;sin8;sin8u;sinr16;sinr16u;sinr8;sinr8u;sizeof;sort;sqrt;sqrt16;sum;swap;tan" />
</highlighting> </highlighting>
<extensionMap> <extensionMap>
<mapping ext="p8" /> <mapping ext="p8" />

View File

@ -27,7 +27,7 @@
<Keywords name="Keywords1">void const&#x000D;&#x000A;str&#x000D;&#x000A;byte ubyte&#x000D;&#x000A;word uword&#x000D;&#x000A;float&#x000D;&#x000A;zp shared</Keywords> <Keywords name="Keywords1">void const&#x000D;&#x000A;str&#x000D;&#x000A;byte ubyte&#x000D;&#x000A;word uword&#x000D;&#x000A;float&#x000D;&#x000A;zp shared</Keywords>
<Keywords name="Keywords2">%address&#x000D;&#x000A;%asm&#x000D;&#x000A;%asmbinary&#x000D;&#x000A;%asminclude&#x000D;&#x000A;%breakpoint&#x000D;&#x000A;%import&#x000D;&#x000A;%launcher&#x000D;&#x000A;%option&#x000D;&#x000A;%output&#x000D;&#x000A;%zeropage&#x000D;&#x000A;%zpreserved</Keywords> <Keywords name="Keywords2">%address&#x000D;&#x000A;%asm&#x000D;&#x000A;%asmbinary&#x000D;&#x000A;%asminclude&#x000D;&#x000A;%breakpoint&#x000D;&#x000A;%import&#x000D;&#x000A;%launcher&#x000D;&#x000A;%option&#x000D;&#x000A;%output&#x000D;&#x000A;%zeropage&#x000D;&#x000A;%zpreserved</Keywords>
<Keywords name="Keywords3">inline sub asmsub romsub&#x000D;&#x000A;clobbers&#x000D;&#x000A;asm&#x000D;&#x000A;if&#x000D;&#x000A;when else&#x000D;&#x000A;if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z&#x000D;&#x000A;for in step do while repeat&#x000D;&#x000A;break return goto</Keywords> <Keywords name="Keywords3">inline sub asmsub romsub&#x000D;&#x000A;clobbers&#x000D;&#x000A;asm&#x000D;&#x000A;if&#x000D;&#x000A;when else&#x000D;&#x000A;if_cc if_cs if_eq if_mi if_neg if_nz if_pl if_pos if_vc if_vs if_z&#x000D;&#x000A;for in step do while repeat&#x000D;&#x000A;break return goto</Keywords>
<Keywords name="Keywords4">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&#x000D;&#x000A;</Keywords> <Keywords name="Keywords4">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&#x000D;&#x000A;</Keywords>
<Keywords name="Keywords5">true false&#x000D;&#x000A;not and or xor&#x000D;&#x000A;as to downto</Keywords> <Keywords name="Keywords5">true false&#x000D;&#x000A;not and or xor&#x000D;&#x000A;as to downto</Keywords>
<Keywords name="Keywords6"></Keywords> <Keywords name="Keywords6"></Keywords>
<Keywords name="Keywords7"></Keywords> <Keywords name="Keywords7"></Keywords>

View File

@ -15,7 +15,7 @@ syn keyword prog8BuiltInFunc sqrt16 sqrt tan
syn keyword prog8BuiltInFunc any all len max min reverse sum sort syn keyword prog8BuiltInFunc any all len max min reverse sum sort
" Miscellaneous functions " 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 rndf rol rol2 ror ror2 sizeof
syn keyword prog8BuiltInFunc swap memory callfar callrom syn keyword prog8BuiltInFunc swap memory callfar callrom