diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index 96c1c0247..13fd48e8e 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -65,44 +65,77 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // this is called when one or more of the arguments are 'complex' and // cannot be assigned to a register easily or risk clobbering other registers. - // make sure the X register is loaded last so we can "safely" destroy the estack pointer - val argsOrig = stmt.args.zip(sub.asmParameterRegisters) - val args = mutableListOf>() - for(argOrig in argsOrig) { - if(argOrig.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY)) - args.add(argOrig) - else - args.add(0, argOrig) - } + if(sub.parameters.isEmpty()) + return - for (arg in args.reversed()) - asmgen.translateExpression(arg.first) - for (arg in args) { - val regparam = arg.second + // 1. load all arguments reversed onto the stack: first arg goes last (is on top). + for (arg in stmt.args.reversed()) + asmgen.translateExpression(arg) + + var argForCarry: IndexedValue>? = null + var argForXregister: IndexedValue>? = null + var argForAregister: IndexedValue>? = null + + asmgen.out(" inx") // align estack pointer + + for(argi in stmt.args.zip(sub.asmParameterRegisters).withIndex()) { when { - regparam.statusflag==Statusflag.Pc -> { - asmgen.out(""" - inx - pha - lda P8ESTACK_LO,x - beq + - sec - bcs ++ -+ clc -+ pla""") + argi.value.second.stack -> TODO("asmsub @stack parameter") + argi.value.second.statusflag == Statusflag.Pc -> { + require(argForCarry == null) + argForCarry = argi } - regparam.statusflag!=null -> { - throw AssemblyError("can only use Carry as status flag parameter") + argi.value.second.statusflag != null -> throw AssemblyError("can only use Carry as status flag parameter") + argi.value.second.registerOrPair in setOf(RegisterOrPair.X, RegisterOrPair.AX, RegisterOrPair.XY) -> { + require(argForXregister==null) + argForXregister = argi } - regparam.registerOrPair!=null -> { - val tgt = AsmAssignTarget.fromRegisters(regparam.registerOrPair, program, asmgen) - val source = AsmAssignSource(SourceStorageKind.STACK, program, tgt.datatype) - val asgn = AsmAssignment(source, tgt, false, Position.DUMMY) - asmgen.translateNormalAssignment(asgn) + argi.value.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.AY) -> { + require(argForAregister == null) + argForAregister = argi } - else -> {} + argi.value.second.registerOrPair == RegisterOrPair.Y -> { + asmgen.out(" ldy P8ESTACK_LO+${argi.index},x") + } + else -> throw AssemblyError("weird argument") } } + + if(argForCarry!=null) { + asmgen.out(""" + lda P8ESTACK_LO+${argForCarry.index},x + beq + + sec + bcs ++ ++ clc ++ php""") // push the status flags + } + + if(argForAregister!=null) { + when(argForAregister.value.second.registerOrPair) { + RegisterOrPair.A -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x") + RegisterOrPair.AY -> asmgen.out(" lda P8ESTACK_LO+${argForAregister.index},x | ldy P8ESTACK_HI+${argForAregister.index},x") + else -> throw AssemblyError("weird arg") + } + } + + if(argForXregister!=null) { + if(argForAregister!=null) + asmgen.out(" pha") + when(argForXregister.value.second.registerOrPair) { + RegisterOrPair.X -> asmgen.out(" lda P8ESTACK_LO+${argForXregister.index},x | tax") + RegisterOrPair.AX -> asmgen.out(" ldy P8ESTACK_LO+${argForXregister.index},x | lda P8ESTACK_HI+${argForXregister.index},x | tax | tya") + RegisterOrPair.XY -> asmgen.out(" ldy P8ESTACK_HI+${argForXregister.index},x | lda P8ESTACK_LO+${argForXregister.index},x | tax") + else -> throw AssemblyError("weird arg") + } + if(argForAregister!=null) + asmgen.out(" pla") + } else { + repeat(sub.parameters.size - 1) { asmgen.out(" inx") } // unwind stack + } + + if(argForCarry!=null) + asmgen.out(" plp") // set the carry flag back to correct value } private fun argumentViaVariable(sub: Subroutine, parameter: IndexedValue, value: Expression) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index 5905c0b41..e89564279 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -260,16 +260,16 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen DataType.UBYTE, DataType.BYTE -> { when(target.register!!) { RegisterOrPair.A -> asmgen.out(" inx | lda P8ESTACK_LO,x") - RegisterOrPair.X -> asmgen.out(" inx | lda P8ESTACK_LO,x | tax") + RegisterOrPair.X -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}") RegisterOrPair.Y -> asmgen.out(" inx | ldy P8ESTACK_LO,x") else -> throw AssemblyError("can't assign byte to register pair word") } } DataType.UWORD, DataType.WORD, in PassByReferenceDatatypes -> { when(target.register!!) { - RegisterOrPair.AX -> asmgen.out(" inx | lda P8ESTACK_LO,x | pha | lda P8ESTACK_HI,x | tax | pla") + RegisterOrPair.AX -> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}") RegisterOrPair.AY-> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x") - RegisterOrPair.XY-> asmgen.out(" inx | lda P8ESTACK_LO,x | ldy P8ESTACK_HI,x | tax") + RegisterOrPair.XY-> throw AssemblyError("can't load X from stack here - use intermediary var? ${target.origAstTarget?.position}") else -> throw AssemblyError("can't assign word to single byte register") } } @@ -590,7 +590,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen TargetStorageKind.STACK -> { when(register) { CpuRegister.A -> asmgen.out(" sta P8ESTACK_LO,x | dex") - CpuRegister.X -> throw AssemblyError("can't store X itself on eval stack") + CpuRegister.X -> throw AssemblyError("can't use X here") CpuRegister.Y -> asmgen.out(" tya | sta P8ESTACK_LO,x | dex") } }