mirror of
https://github.com/irmen/prog8.git
synced 2024-11-29 17:50:35 +00:00
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:
parent
a2db44f80c
commit
7748c261da
@ -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) {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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
|
||||||
----------------
|
----------------
|
||||||
|
@ -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)
|
||||||
|
@ -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?
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<keywords keywords="&;->;@;\$;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="&;->;@;\$;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" />
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<Keywords name="Keywords1">void const
str
byte ubyte
word uword
float
zp shared</Keywords>
|
<Keywords name="Keywords1">void const
str
byte ubyte
word uword
float
zp shared</Keywords>
|
||||||
<Keywords name="Keywords2">%address
%asm
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
<Keywords name="Keywords2">%address
%asm
%asmbinary
%asminclude
%breakpoint
%import
%launcher
%option
%output
%zeropage
%zpreserved</Keywords>
|
||||||
<Keywords name="Keywords3">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</Keywords>
|
<Keywords name="Keywords3">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</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
</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
</Keywords>
|
||||||
<Keywords name="Keywords5">true false
not and or xor
as to downto</Keywords>
|
<Keywords name="Keywords5">true false
not and or xor
as to downto</Keywords>
|
||||||
<Keywords name="Keywords6"></Keywords>
|
<Keywords name="Keywords6"></Keywords>
|
||||||
<Keywords name="Keywords7"></Keywords>
|
<Keywords name="Keywords7"></Keywords>
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user