diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index de6cd981d..6a22c1786 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -543,30 +543,48 @@ internal class AsmGen(private val program: Program, private val saveRegisterLabels = Stack(); - internal fun saveRegister(register: CpuRegister) { - when(register) { - CpuRegister.A -> out(" pha") - CpuRegister.X -> { - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx") - else out(" stx _prog8_regsave${register.name}") + internal fun saveRegister(register: CpuRegister, dontUseStack: Boolean) { + if(dontUseStack) { + when (register) { + CpuRegister.A -> out(" sta _prog8_regsaveA") + CpuRegister.X -> out(" stx _prog8_regsaveX") + CpuRegister.Y -> out(" sty _prog8_regsaveY") } - CpuRegister.Y -> { - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy") - else out(" sty _prog8_regsave${register.name}") + + } else { + when (register) { + CpuRegister.A -> out(" pha") + CpuRegister.X -> { + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phx") + else out(" stx _prog8_regsaveX") + } + CpuRegister.Y -> { + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" phy") + else out(" sty _prog8_regsaveY") + } } } } - internal fun restoreRegister(register: CpuRegister) { - when(register) { - CpuRegister.A -> out(" pla") - CpuRegister.X -> { - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx") - else out(" ldx _prog8_regsave${register.name}") + internal fun restoreRegister(register: CpuRegister, dontUseStack: Boolean) { + if(dontUseStack) { + when (register) { + CpuRegister.A -> out(" sta _prog8_regsaveA") + CpuRegister.X -> out(" ldx _prog8_regsaveX") + CpuRegister.Y -> out(" ldy _prog8_regsaveY") } - CpuRegister.Y -> { - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" ply") - else out(" ldy _prog8_regsave${register.name}") + + } else { + when (register) { + CpuRegister.A -> out(" pla") + CpuRegister.X -> { + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" plx") + else out(" ldx _prog8_regsaveX") + } + CpuRegister.Y -> { + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) out(" ply") + else out(" ldy _prog8_regsaveY") + } } } } @@ -811,6 +829,7 @@ internal class AsmGen(private val program: Program, out("; variables") out(""" ; register saves +_prog8_regsaveA .byte 0 _prog8_regsaveX .byte 0 _prog8_regsaveY .byte 0""") // TODO only generate these bytes if they're actually used by saveRegister() vardecls2asm(sub.statements) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index af0fb3335..16cc278fa 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -19,7 +19,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") val saveX = CpuRegister.X in sub.asmClobbers || sub.regXasResult() || sub.regXasParam() if(saveX) - asmgen.saveRegister(CpuRegister.X) + asmgen.saveRegister(CpuRegister.X, preserveStatusRegisterAfterCall) val subName = asmgen.asmSymbolName(stmt.target) if(stmt.args.isNotEmpty()) { @@ -64,7 +64,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } if(saveX) - asmgen.restoreRegister(CpuRegister.X) + asmgen.restoreRegister(CpuRegister.X, preserveStatusRegisterAfterCall) } private fun registerArgsViaStackEvaluation(stmt: IFunctionCall, sub: Subroutine) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt index 27c0cf71d..ad15e6e52 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/PostIncrDecrAsmGen.kt @@ -97,7 +97,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } else -> { asmgen.loadScaledArrayIndexIntoRegister(targetArrayIdx, elementDt, CpuRegister.A) - asmgen.saveRegister(CpuRegister.X) + asmgen.saveRegister(CpuRegister.X, false) asmgen.out(" tax") when(elementDt) { in ByteDatatypes -> { @@ -125,7 +125,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg } else -> throw AssemblyError("weird array elt dt") } - asmgen.restoreRegister(CpuRegister.X) + asmgen.restoreRegister(CpuRegister.X, false) } } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt index 6e6ad88ab..5ff782ff4 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -127,7 +127,16 @@ internal class AsmAssignSource(val kind: SourceStorageKind, 0 -> throw AssemblyError("can't translate zero return values in assignment") 1 -> { // assignment generation itself must make sure the status register is correct after the subroutine call, if status register is involved! - return AsmAssignSource(SourceStorageKind.EXPRESSION, program, DataType.UBYTE, expression = value) + val reg = asmSub.asmReturnvaluesRegisters.single { rr->rr.registerOrPair!=null }.registerOrPair!! + val dt = when(reg) { + RegisterOrPair.A, + RegisterOrPair.X, + RegisterOrPair.Y -> DataType.UBYTE + RegisterOrPair.AX, + RegisterOrPair.AY, + RegisterOrPair.XY -> DataType.UWORD + } + return AsmAssignSource(SourceStorageKind.EXPRESSION, program, dt, expression = value) } else -> throw AssemblyError("can't translate multiple return values in assignment") } @@ -177,6 +186,8 @@ internal class AsmAssignment(val source: AsmAssignSource, init { if(target.register !in setOf(RegisterOrPair.XY, RegisterOrPair.AX, RegisterOrPair.AY)) require(source.datatype != DataType.STRUCT) { "must not be placeholder datatype" } - require(source.datatype.memorySize() == target.datatype.memorySize()) { "source and target datatype must be same storage class" } + require(source.datatype.memorySize() <= target.datatype.memorySize()) { + "source storage size must be less or equal to target datatype storage size" + } } } 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 88c381efc..73712c9a9 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -133,6 +133,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.A -> assignRegisterByte(assign.target, CpuRegister.A) RegisterOrPair.X -> assignRegisterByte(assign.target, CpuRegister.X) RegisterOrPair.Y -> assignRegisterByte(assign.target, CpuRegister.Y) + RegisterOrPair.AX -> assignRegisterpairWord(assign.target, RegisterOrPair.AX) + RegisterOrPair.AY -> assignRegisterpairWord(assign.target, RegisterOrPair.AY) + RegisterOrPair.XY -> assignRegisterpairWord(assign.target, RegisterOrPair.XY) else -> throw AssemblyError("should be just one register byte result value") } if(preserveStatusRegisterAfterCall) @@ -685,9 +688,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" ldy ${asmgen.asmVariableName(index)} | sta ${target.asmVarname},y") } else -> { - asmgen.saveRegister(register) + asmgen.saveRegister(register, false) asmgen.translateExpression(index) - asmgen.restoreRegister(register) + asmgen.restoreRegister(register, false) when (register) { CpuRegister.A -> asmgen.out(" sta P8ZP_SCRATCH_B1") CpuRegister.X -> asmgen.out(" stx P8ZP_SCRATCH_B1") @@ -741,6 +744,54 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } + private fun assignRegisterpairWord(target: AsmAssignTarget, regs: RegisterOrPair) { + require(target.datatype in WordDatatypes) + when(target.kind) { + TargetStorageKind.VARIABLE -> { + when(regs) { + RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname} | stx ${target.asmVarname}+1") + RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname} | sty ${target.asmVarname}+1") + RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname} | sty ${target.asmVarname}+1") + else -> throw AssemblyError("expected reg pair") + } + } + TargetStorageKind.ARRAY -> { + TODO("store register pair $regs into word-array ${target.array}") + } + TargetStorageKind.REGISTER -> { + when(regs) { + RegisterOrPair.AX -> when(target.register!!) { + RegisterOrPair.AY -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG") } + RegisterOrPair.AX -> { } + RegisterOrPair.XY -> { asmgen.out(" stx P8ZP_SCRATCH_REG | ldy P8ZP_SCRATCH_REG | tax") } + else -> throw AssemblyError("expected reg pair") + } + RegisterOrPair.AY -> when(target.register!!) { + RegisterOrPair.AY -> { } + RegisterOrPair.AX -> { asmgen.out(" sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") } + RegisterOrPair.XY -> { asmgen.out(" tax") } + else -> throw AssemblyError("expected reg pair") + } + RegisterOrPair.XY -> when(target.register!!) { + RegisterOrPair.AY -> { asmgen.out(" txa") } + RegisterOrPair.AX -> { asmgen.out(" txa | sty P8ZP_SCRATCH_REG | ldx P8ZP_SCRATCH_REG") } + RegisterOrPair.XY -> { } + else -> throw AssemblyError("expected reg pair") + } + else -> throw AssemblyError("expected reg pair") + } + } + TargetStorageKind.STACK -> { + when(regs) { + RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex") + RegisterOrPair.AX, RegisterOrPair.XY -> throw AssemblyError("can't use X here") + else -> throw AssemblyError("expected reg pair") + } + } + TargetStorageKind.MEMORY -> throw AssemblyError("can't store word into memory byte") + } + } + private fun assignConstantWord(target: AsmAssignTarget, word: Int) { when(target.kind) { TargetStorageKind.VARIABLE -> { @@ -1136,9 +1187,9 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.storeByteIntoPointer(addressExpr, null) } else -> { - asmgen.saveRegister(register) + asmgen.saveRegister(register, false) asmgen.translateExpression(addressExpr) - asmgen.restoreRegister(CpuRegister.A) + asmgen.restoreRegister(CpuRegister.A, false) asmgen.out(""" inx ldy P8ESTACK_LO,x diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index d543056ff..9f224c7c1 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -1258,7 +1258,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, println("warning: slow stack evaluation used (2): $name $operator= ${value::class.simpleName} at ${value.position}") // TODO asmgen.translateExpression(value) asmgen.out(" jsr floats.pop_float_fac1") - asmgen.saveRegister(CpuRegister.X) + asmgen.saveRegister(CpuRegister.X, false) when (operator) { "**" -> { asmgen.out(""" @@ -1303,7 +1303,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegister(CpuRegister.X) + asmgen.restoreRegister(CpuRegister.X, false) } private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference) { @@ -1312,7 +1312,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, throw AssemblyError("float variable expected") val otherName = asmgen.asmVariableName(ident) - asmgen.saveRegister(CpuRegister.X) + asmgen.saveRegister(CpuRegister.X, false) when (operator) { "**" -> { asmgen.out(""" @@ -1372,12 +1372,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegister(CpuRegister.X) + asmgen.restoreRegister(CpuRegister.X, false) } private fun inplaceModification_float_litval_to_variable(name: String, operator: String, value: Double) { val constValueName = asmgen.getFloatAsmConst(value) - asmgen.saveRegister(CpuRegister.X) + asmgen.saveRegister(CpuRegister.X, false) when (operator) { "**" -> { asmgen.out(""" @@ -1444,7 +1444,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, ldy #>$name jsr floats.MOVMF """) - asmgen.restoreRegister(CpuRegister.X) + asmgen.restoreRegister(CpuRegister.X, false) } private fun inplaceCast(target: AsmAssignTarget, cast: TypecastExpression, position: Position) { diff --git a/examples/cx16/cobramk3-gfx.p8 b/examples/cx16/cobramk3-gfx.p8 index 9cd43474b..c8ffc3bd7 100644 --- a/examples/cx16/cobramk3-gfx.p8 +++ b/examples/cx16/cobramk3-gfx.p8 @@ -4,8 +4,6 @@ ; TODO add all other Elite's ships, show their name, advance to next ship on keypress -; TODO fix crash - main { ; storage for rotated coordinates diff --git a/examples/cx16/mandelbrot-gfx-colors.p8 b/examples/cx16/mandelbrot-gfx-colors.p8 index 3f97e6a42..c2d1d48f5 100644 --- a/examples/cx16/mandelbrot-gfx-colors.p8 +++ b/examples/cx16/mandelbrot-gfx-colors.p8 @@ -3,8 +3,6 @@ %import floats %zeropage basicsafe -; TODO fix crash - main { const uword width = 256 const uword height = 200 diff --git a/examples/cx16/simplegraphics.p8 b/examples/cx16/simplegraphics.p8 index 595745f98..861fefd5e 100644 --- a/examples/cx16/simplegraphics.p8 +++ b/examples/cx16/simplegraphics.p8 @@ -3,8 +3,6 @@ %target cx16 %zeropage basicsafe -; TODO fix crash - main { diff --git a/examples/diskdir.p8 b/examples/diskdir.p8 index 5a42e87ed..05a4630a3 100644 --- a/examples/diskdir.p8 +++ b/examples/diskdir.p8 @@ -4,7 +4,7 @@ %zeropage basicsafe ; This example shows the directory contents of disk drive 8. -; Note: this program is compatible with C64 and CX16. TODO not yet on cx16, fix the crash +; Note: this program is compatible with C64 and CX16. main { sub start() { @@ -37,11 +37,9 @@ main { txt.chrout(char) } until char==0 txt.chrout('\n') - repeat 2 { - void c64.CHRIN() ; skip 2 bytes - } + void c64.CHRIN() ; skip 2 bytes + void c64.CHRIN() status = c64.READST() - c64.STOP() if_nz break diff --git a/examples/mandelbrot-gfx.p8 b/examples/mandelbrot-gfx.p8 index 85239ff54..b83f07f7b 100644 --- a/examples/mandelbrot-gfx.p8 +++ b/examples/mandelbrot-gfx.p8 @@ -8,9 +8,6 @@ ; Note: this program is compatible with C64 and CX16. -; TODO fix compiler crash - - main { const ubyte width = 255 const ubyte height = 200 diff --git a/examples/textelite.p8 b/examples/textelite.p8 index 0fb270a48..654c40d6a 100644 --- a/examples/textelite.p8 +++ b/examples/textelite.p8 @@ -2,8 +2,6 @@ %zeropage basicsafe %option no_sysinit -; TODO fix compiler crash - main { sub start() { txt.lowercase()