mirror of
https://github.com/irmen/prog8.git
synced 2026-10-22 20:02:27 +00:00
fix builtins rejecting a cx16 virtual register as their result register
This commit is contained in:
1 parent
2b156ec652
commit
e74c34a5ab
2 files changed
+92
-8
No files matched your search
@@ -20,6 +20,25 @@ import prog8.codegen.cpu6502.assignment.*
|
||||
translateFunctioncall(fcall, null, discardResult = true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Several builtins can only produce their result in a CPU register, and which one that is
|
||||
* depends on the width of the result: the byte-returning ones (lsb/msb) take a single register,
|
||||
* the word-returning ones (lsw/msw) and popw take a register pair, and the builtin picks the
|
||||
* specific register. [hardwareReg] is the register to fall back on when the caller has no
|
||||
* preference, or when it asked for something the builtin cannot deliver to directly.
|
||||
*
|
||||
* The caller's requested register is honoured when it is a real CPU register. A CX16 virtual
|
||||
* register (for example an asmsub parameter declared as @R0) is not: those are memory locations,
|
||||
* so the builtin produces its result in [hardwareReg] and the caller's assignment then stores it
|
||||
* into the virtual register. Passing the virtual register through would make the builtin reject
|
||||
* it as an invalid result register.
|
||||
*
|
||||
* (funcPeekW and funcMkword already handle virtual registers themselves.)
|
||||
*/
|
||||
private fun withResultRegister(requested: RegisterOrPair?, hardwareReg: RegisterOrPair, compute: (RegisterOrPair) -> Array<RegisterOrPair>): Array<RegisterOrPair> =
|
||||
if (requested != null && requested !in Cx16VirtualRegisters) compute(requested)
|
||||
else compute(hardwareReg)
|
||||
|
||||
private fun translateFunctioncall(fcall: PtFunctionCall, firstReturnRegister: RegisterOrPair?, discardResult: Boolean): Array<RegisterOrPair> {
|
||||
|
||||
// Note: returns the actual register(s) that the return value is in, so the caller should still make sure to place it into the actual correct destination.
|
||||
@@ -31,12 +50,12 @@ import prog8.codegen.cpu6502.assignment.*
|
||||
val sscope = fcall.definingISub()
|
||||
|
||||
return when (fcall.name) {
|
||||
"msw" -> funcMsw(fcall, firstReturnRegister ?: RegisterOrPair.AY)
|
||||
"lsw" -> funcLsw(fcall, firstReturnRegister ?: RegisterOrPair.AY)
|
||||
"msb" -> funcMsb(fcall, false, firstReturnRegister ?: RegisterOrPair.A)
|
||||
"msb__long" -> funcMsb(fcall, true, firstReturnRegister ?: RegisterOrPair.A)
|
||||
"lsb" -> funcLsb(fcall, false, firstReturnRegister ?: RegisterOrPair.A)
|
||||
"lsb__long" -> funcLsb(fcall,true, firstReturnRegister ?: RegisterOrPair.A)
|
||||
"msw" -> withResultRegister(firstReturnRegister, RegisterOrPair.AY) { funcMsw(fcall, it) }
|
||||
"lsw" -> withResultRegister(firstReturnRegister, RegisterOrPair.AY) { funcLsw(fcall, it) }
|
||||
"msb" -> withResultRegister(firstReturnRegister, RegisterOrPair.A) { funcMsb(fcall, false, it) }
|
||||
"msb__long" -> withResultRegister(firstReturnRegister, RegisterOrPair.A) { funcMsb(fcall, true, it) }
|
||||
"lsb" -> withResultRegister(firstReturnRegister, RegisterOrPair.A) { funcLsb(fcall, false, it) }
|
||||
"lsb__long" -> withResultRegister(firstReturnRegister, RegisterOrPair.A) { funcLsb(fcall, true, it) }
|
||||
"mkword" -> funcMkword(fcall, firstReturnRegister ?: RegisterOrPair.AY)
|
||||
"mklong", "mklong2" -> funcMklong(fcall, firstReturnRegister ?: RegisterOrPair.R14R15)
|
||||
"clamp__byte", "clamp__ubyte" -> funcClamp(fcall)
|
||||
@@ -98,8 +117,8 @@ import prog8.codegen.cpu6502.assignment.*
|
||||
"pushw" -> funcPushW(fcall)
|
||||
"pushl" -> funcPushL(fcall)
|
||||
"pushf" -> funcPushF(fcall)
|
||||
"pop" -> funcPop(firstReturnRegister ?: RegisterOrPair.A)
|
||||
"popw" -> funcPopW(firstReturnRegister ?: RegisterOrPair.AY)
|
||||
"pop" -> withResultRegister(firstReturnRegister, RegisterOrPair.A) { funcPop(it) }
|
||||
"popw" -> withResultRegister(firstReturnRegister, RegisterOrPair.AY) { funcPopW(it) }
|
||||
"popl" -> funcPopL()
|
||||
"popf" -> funcPopF()
|
||||
else -> throw AssemblyError("sizeof must have been replaced with a constant ${fcall.position}")
|
||||
|
||||
@@ -990,4 +990,69 @@ class TestExecution6502 : FunSpec({
|
||||
machine.assertMemory(0x04, 0x77)
|
||||
machine.assertMemory(0x05, 0x00)
|
||||
}
|
||||
|
||||
test("lsb/msb/lsw/msw result delivered to a cx16 virtual register parameter") {
|
||||
val src = $$"""
|
||||
%option no_sysinit
|
||||
%launcher none
|
||||
%address $1000
|
||||
|
||||
main {
|
||||
&ubyte poweroff = $f203
|
||||
|
||||
; each routine copies the value it received in the @R0 virtual register to a probe address
|
||||
asmsub recordLsb(ubyte c @R0) {
|
||||
%asm {{
|
||||
lda cx16.r0L
|
||||
sta $3000
|
||||
rts
|
||||
}}
|
||||
}
|
||||
asmsub recordMsb(ubyte c @R0) {
|
||||
%asm {{
|
||||
lda cx16.r0L
|
||||
sta $3001
|
||||
rts
|
||||
}}
|
||||
}
|
||||
asmsub recordLsw(uword c @R0) {
|
||||
%asm {{
|
||||
lda cx16.r0
|
||||
sta $3002
|
||||
lda cx16.r0+1
|
||||
sta $3003
|
||||
rts
|
||||
}}
|
||||
}
|
||||
asmsub recordMsw(uword c @R0) {
|
||||
%asm {{
|
||||
lda cx16.r0
|
||||
sta $3004
|
||||
lda cx16.r0+1
|
||||
sta $3005
|
||||
rts
|
||||
}}
|
||||
}
|
||||
|
||||
sub start() {
|
||||
uword @shared l
|
||||
l = $1234
|
||||
recordLsb(lsb(l))
|
||||
recordMsb(msb(l))
|
||||
recordLsw(lsw(l))
|
||||
recordMsw(msw(l))
|
||||
poweroff = 1
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val compileResult = compileText(Cx16Target(), false, src, outputDir)
|
||||
val machine = compileResult!!.simulate()
|
||||
machine.assertMemory(0x3000, 0x34) // lsb($1234)
|
||||
machine.assertMemory(0x3001, 0x12) // msb($1234)
|
||||
machine.assertMemory(0x3002, 0x34) // lsw($1234) low
|
||||
machine.assertMemory(0x3003, 0x12) // lsw($1234) high
|
||||
machine.assertMemory(0x3004, 0x00) // msw($1234) low
|
||||
machine.assertMemory(0x3005, 0x00) // msw($1234) high
|
||||
}
|
||||
})
|
||||
Reference in new issue
Block a user