diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmsubHelpers.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmsubHelpers.kt index 3480282fb..a5a1eff8f 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmsubHelpers.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/AsmsubHelpers.kt @@ -11,22 +11,25 @@ internal fun asmsub6502ArgsEvalOrder(sub: Subroutine): List { // order is: // 1) cx16 virtual word registers, // 2) paired CPU registers, - // 3) single CPU registers (X last), + // 3) single CPU registers (X last), except A, // 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 (cx16regs, args2) = args.partition { it.value.second.registerOrPair in Cx16VirtualRegisters } val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY) 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 } pairedRegs.forEach { order += it.index } - regs.forEach { + regsWithoutA.forEach { if(it.value.second.registerOrPair != RegisterOrPair.X) 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 } + regA.forEach { order += it.index } require(order.size==sub.parameters.size) return order } diff --git a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt index e47a7b9e7..7baf66a0e 100644 --- a/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt +++ b/codeGeneration/src/prog8/compiler/target/cpu6502/codegen/BuiltinFunctionsAsmGen.kt @@ -77,6 +77,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } 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) { "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) { "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)] if(reg.statusflag!=null) { + if(shouldKeepA) + asmgen.out(" sta P8ZP_SCRATCH_REG") asmgen.out(""" - sta P8ZP_SCRATCH_REG clc pla beq + sec -+ lda P8ZP_SCRATCH_REG""") ++""") + if(shouldKeepA) + asmgen.out(" lda P8ZP_SCRATCH_REG") } else { if (func.name == "pop") { @@ -109,15 +114,25 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val } } else { 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.X -> asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tax | lda P8ZP_SCRATCH_REG") - RegisterOrPair.Y -> asmgen.out(" sta P8ZP_SCRATCH_REG | pla | tay | lda P8ZP_SCRATCH_REG") + RegisterOrPair.X -> { + 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()}") else -> throw AssemblyError("invalid target register ${reg.registerOrPair}") } } } else { + // word pop if (asmgen.isTargetCpu(CpuType.CPU65c02)) when (reg.registerOrPair) { RegisterOrPair.AX -> asmgen.out(" plx | pla") diff --git a/examples/test.p8 b/examples/test.p8 index af0675272..e807fae03 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -58,19 +58,17 @@ main { 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 {{ - pha + sta routine.num + sty routine.num+1 lda #0 adc #0 sta routine.switch - pla - sta routine.num - sty routine.num+1 + lda cx16.r0 + sta routine.a2 lda cx16.r1 sta routine.a1 - lda cx16.r2 - sta routine.a2 stx routine.a3 jmp routine }}