moved A to the end of the param list to avoid having to store its value

This commit is contained in:
Irmen de Jong 2021-11-28 03:55:13 +01:00
parent f3a4048ebf
commit 3d23b39f4c
3 changed files with 32 additions and 16 deletions

View File

@ -11,22 +11,25 @@ internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List<Int> {
// order is: // order is:
// 1) cx16 virtual word registers, // 1) cx16 virtual word registers,
// 2) paired CPU registers, // 2) paired CPU registers,
// 3) single CPU registers (X last), // 3) single CPU registers (X last), except A,
// 4) CPU Carry status flag // 4) CPU Carry status flag
// 5) the A register itself last (so everything before it can use the accumulator without having to save its value)
val args = sub.parameters.zip(sub.asmParameterRegisters).withIndex() val args = sub.parameters.zip(sub.asmParameterRegisters).withIndex()
val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters } val (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters }
val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY) val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)
val (pairedRegs , args3) = args2.partition { it.value.second.registerOrPair in pairedRegisters } val (pairedRegs , args3) = args2.partition { it.value.second.registerOrPair in pairedRegisters }
val (regs, rest) = args3.partition { it.value.second.registerOrPair != null } val (regsWithoutA, args4) = args3.partition { it.value.second.registerOrPair != RegisterOrPair.A }
val (regA, rest) = args4.partition { it.value.second.registerOrPair != null }
cx16regs.forEach { order += it.index } cx16regs.forEach { order += it.index }
pairedRegs.forEach { order += it.index } pairedRegs.forEach { order += it.index }
regs.forEach { regsWithoutA.forEach {
if(it.value.second.registerOrPair != RegisterOrPair.X) if(it.value.second.registerOrPair != RegisterOrPair.X)
order += it.index order += it.index
} }
regs.firstOrNull { it.value.second.registerOrPair==RegisterOrPair.X } ?.let { order += it.index} regsWithoutA.firstOrNull { it.value.second.registerOrPair==RegisterOrPair.X } ?.let { order += it.index}
rest.forEach { order += it.index } rest.forEach { order += it.index }
regA.forEach { order += it.index }
require(order.size==sub.parameters.size) require(order.size==sub.parameters.size)
return order return order
} }

View File

@ -77,6 +77,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
} }
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.
require(fcall.args[0] is IdentifierReference) { require(fcall.args[0] is IdentifierReference) {
"attempt to pop a value into a differently typed variable, or in something else that isn't supported ${(fcall as Node).position}" "attempt to pop a value into a differently typed variable, or in something else that isn't supported ${(fcall as Node).position}"
} }
@ -87,15 +88,19 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
require(sub.isAsmSubroutine) { require(sub.isAsmSubroutine) {
"push/pop arg passing only supported on asmsubs ${(fcall as Node).position}" "push/pop arg passing only supported on asmsubs ${(fcall as Node).position}"
} }
val shouldKeepA = sub.asmParameterRegisters.any { it.registerOrPair==RegisterOrPair.AX || it.registerOrPair==RegisterOrPair.AY }
val reg = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)] val reg = sub.asmParameterRegisters[sub.parameters.indexOf(parameter)]
if(reg.statusflag!=null) { if(reg.statusflag!=null) {
if(shouldKeepA)
asmgen.out(" sta P8ZP_SCRATCH_REG")
asmgen.out(""" asmgen.out("""
sta P8ZP_SCRATCH_REG
clc clc
pla pla
beq + beq +
sec sec
+ lda P8ZP_SCRATCH_REG""") +""")
if(shouldKeepA)
asmgen.out(" lda P8ZP_SCRATCH_REG")
} }
else { else {
if (func.name == "pop") { if (func.name == "pop") {
@ -109,15 +114,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
} }
} else { } else {
when (reg.registerOrPair) { when (reg.registerOrPair) {
// TODO make sure that A is pushed first so popped last, so that those store/load to save A are no longer needed (c64)
RegisterOrPair.A -> asmgen.out(" pla") RegisterOrPair.A -> asmgen.out(" pla")
RegisterOrPair.X -> asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG") RegisterOrPair.X -> {
RegisterOrPair.Y -> asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG") if(shouldKeepA)
asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG")
else
asmgen.out(" pla | tax")
}
RegisterOrPair.Y -> {
if(shouldKeepA)
asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG")
else
asmgen.out(" pla | tay")
}
in Cx16VirtualRegisters -> asmgen.out(" pla | sta cx16.${reg.registerOrPair!!.name.lowercase()}") in Cx16VirtualRegisters -> asmgen.out(" pla | sta cx16.${reg.registerOrPair!!.name.lowercase()}")
else -> throw AssemblyError("invalid target register ${reg.registerOrPair}") else -> throw AssemblyError("invalid target register ${reg.registerOrPair}")
} }
} }
} else { } else {
// word pop
if (asmgen.isTargetCpu(CpuType.CPU65c02)) if (asmgen.isTargetCpu(CpuType.CPU65c02))
when (reg.registerOrPair) { when (reg.registerOrPair) {
RegisterOrPair.AX -> asmgen.out(" plx | pla") RegisterOrPair.AX -> asmgen.out(" plx | pla")

View File

@ -58,19 +58,17 @@ main {
txt.nl() txt.nl()
} }
asmsub routine2(uword num @AY, ubyte a1 @R1, ubyte a2 @R2, ubyte switch @Pc, ubyte a3 @X) { asmsub routine2(uword num @AY, ubyte a1 @R1, ubyte a2 @R0, ubyte switch @Pc, ubyte a3 @X) {
%asm {{ %asm {{
pha sta routine.num
sty routine.num+1
lda #0 lda #0
adc #0 adc #0
sta routine.switch sta routine.switch
pla lda cx16.r0
sta routine.num sta routine.a2
sty routine.num+1
lda cx16.r1 lda cx16.r1
sta routine.a1 sta routine.a1
lda cx16.r2
sta routine.a2
stx routine.a3 stx routine.a3
jmp routine jmp routine
}} }}