diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt index 882bf4a6d..221a7220e 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/AsmGen.kt @@ -587,7 +587,10 @@ class AsmGen6502Internal ( is PtInlineAssembly -> translate(stmt) is PtBuiltinFunctionCall -> builtinFunctionsAsmGen.translateFunctioncallStatement(stmt) is PtFunctionCall -> functioncallAsmGen.translateFunctionCallStatement(stmt) - is PtAssignment -> assignmentAsmGen.translate(stmt) + is PtAssignment -> { + if(stmt.multiTarget) assignmentAsmGen.translateMultiAssign(stmt) + else assignmentAsmGen.translate(stmt) + } is PtAugmentedAssign -> assignmentAsmGen.translate(stmt) is PtJump -> { val (asmLabel, indirect) = getJumpTarget(stmt) diff --git a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt index 38e228aa5..ad6f08f2b 100644 --- a/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt +++ b/codeGenCpu6502/src/prog8/codegen/cpu6502/assignment/AssignmentAsmGen.kt @@ -1,6 +1,8 @@ package prog8.codegen.cpu6502.assignment import prog8.code.StMemVar +import prog8.code.StRomSub +import prog8.code.StRomSubParameter import prog8.code.StStaticVariable import prog8.code.ast.* import prog8.code.core.* @@ -32,6 +34,77 @@ internal class AssignmentAsmGen(private val program: PtProgram, augmentableAsmGen.translate(assign, augmentedAssign.definingISub()) } + fun translateMultiAssign(assignment: PtAssignment) { + // TODO("translate multi-value assignment ${assignment.position}") + val values = assignment.value as? PtFunctionCall + ?: throw AssemblyError("only function calls can return multiple values in a multi-assign") + + val sub = asmgen.symbolTable.lookup(values.name) as? StRomSub + ?: throw AssemblyError("only asmsubs can return multiple values") + + require(sub.returns.size>=2) + if(sub.returns.any { it.type==DataType.FLOAT }) + TODO("deal with (multiple?) FP return registers") + + asmgen.translate(values) + + fun needsToSaveA(registersResults: List>): Boolean = + if(registersResults.isEmpty()) + false + else if(registersResults.all { (it.second as PtAssignTarget).identifier!=null}) + false + else + true + + fun assignCarryResult(target: PtAssignTarget, saveA: Boolean) { + if(saveA) asmgen.out(" pha") + asmgen.out(" lda #0 | rol a") + val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) + assignRegisterByte(tgt, CpuRegister.A, false, false) + if(saveA) asmgen.out(" pla") + } + + fun assignRegisterResults(registersResults: List>) { + registersResults.forEach { (returns, target) -> + val targetIdent = (target as PtAssignTarget).identifier + val targetMem = target.memory + if(targetIdent!=null || targetMem!=null) { + val tgt = AsmAssignTarget.fromAstAssignment(target, target.definingISub(), asmgen) + when(returns.type) { + in ByteDatatypesWithBoolean -> { + assignRegisterByte(tgt, returns.register.registerOrPair!!.asCpuRegister(), false, false) + } + in WordDatatypes -> { + assignRegisterpairWord(tgt, returns.register.registerOrPair!!) + } + else -> throw AssemblyError("weird dt") + } + } + else TODO("array target for multi-value assignment") // Not done yet due to result register clobbering complexity + } + } + + // because we can only handle integer results right now we can just zip() it all up + val (statusFlagResult, registersResults) = sub.returns.zip(assignment.children).partition { it.first.register.statusflag!=null } + if(statusFlagResult.isNotEmpty()) { + val (returns, target) = statusFlagResult.single() + if(returns.register.statusflag!=Statusflag.Pc) + TODO("other status flag for return value") + + target as PtAssignTarget + if(registersResults.all { (it.second as PtAssignTarget).identifier!=null}) { + // all other results are just stored into identifiers directly so first handle those + // (simple store instructions that don't modify the carry flag) + assignRegisterResults(registersResults) + assignCarryResult(target, false) + return + } + assignCarryResult(target, needsToSaveA(registersResults)) + } + assignRegisterResults(registersResults) + } + + fun translateNormalAssignment(assign: AsmAssignment, scope: IPtSubroutine?) { when(assign.source.kind) { SourceStorageKind.LITERALBOOLEAN -> { diff --git a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt index 646470a3e..41c964b32 100644 --- a/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt +++ b/codeGenIntermediate/src/prog8/codegen/intermediate/AssignmentGen.kt @@ -31,15 +31,12 @@ internal class AssignmentGen(private val codeGen: IRCodeGen, private val express val target = it.first.second as PtAssignTarget result += assignCpuRegister(returns, regNumber, target) } - result.filterIsInstance().firstOrNull()?.appendSrcPosition(assignment.position) return result } else { if (assignment.target.children.single() is PtIrRegister) throw AssemblyError("assigning to a register should be done by just evaluating the expression into resultregister") - val chunks = translateRegularAssign(assignment) - chunks.filterIsInstance().firstOrNull()?.appendSrcPosition(assignment.position) - return chunks + return translateRegularAssign(assignment) } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 66ee9a95b..dc990dc1e 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -1,8 +1,8 @@ TODO ==== -6502 codegen: make multi return value asmsub calls work. - +add unit tests for vm and 6502 multi-assigns. +add docs for multi-assigns. ... diff --git a/examples/test.p8 b/examples/test.p8 index 5db5a26d5..08dd66683 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,9 +6,9 @@ main { bool @shared flag cx16.r1=9999 - ; flag = test(42) + flag = test(42) cx16.r0L, flag = test2(12345, 5566, flag, -42) - + cx16.r0, flag = test3() } asmsub test(ubyte arg @A) -> bool @Pc { @@ -27,4 +27,12 @@ main { rts }} } + + asmsub test3() -> uword @AY, bool @Pc { + %asm {{ + lda #0 + ldy #0 + rts + }} + } }