From cc96ab7a9bf7cf5e66671aea1661843bf991af7d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 6 Feb 2021 13:01:45 +0100 Subject: [PATCH] assignment source now also treats cx16.r[0-15] as registers no longer create useless assignment code for r0=r0 --- compiler/src/prog8/ast/base/Base.kt | 7 ++ .../compiler/target/c64/codegen/AsmGen.kt | 7 +- .../c64/codegen/assignment/AsmAssignment.kt | 12 ++- .../codegen/assignment/AssignmentAsmGen.kt | 99 ++++++++++++++----- docs/source/todo.rst | 1 + examples/test.p8 | 25 ++--- 6 files changed, 108 insertions(+), 43 deletions(-) diff --git a/compiler/src/prog8/ast/base/Base.kt b/compiler/src/prog8/ast/base/Base.kt index 1dcf810bd..1c63700dd 100644 --- a/compiler/src/prog8/ast/base/Base.kt +++ b/compiler/src/prog8/ast/base/Base.kt @@ -91,6 +91,13 @@ enum class RegisterOrPair { val names by lazy { values().map { it.toString()} } } + fun asCpuRegister(): CpuRegister = when(this) { + A -> CpuRegister.A + X -> CpuRegister.X + Y -> CpuRegister.Y + else -> throw IllegalArgumentException("no cpu hardware register for $this") + } + } // only used in parameter and return value specs in asm subroutines enum class Statusflag { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index b68364251..f2f764811 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -506,6 +506,12 @@ internal class AsmGen(private val program: Program, } } + internal fun asmSymbolName(regs: RegisterOrPair): String = + if(regs in Cx16VirtualRegisters) + "cx16." + regs.toString().toLowerCase() + else + throw AssemblyError("no symbol name for register $regs") + internal fun asmVariableName(identifier: IdentifierReference): String { return if(identifier.memberOfStruct(program.namespace)!=null) { val name = identifier.targetVarDecl(program.namespace)!!.name @@ -1442,5 +1448,4 @@ $label nop""") } return 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 26328ecff..75b8d11e7 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -104,7 +104,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, private val variableAsmName: String? = null, val array: ArrayIndexedExpression? = null, val memory: DirectMemoryRead? = null, - val register: CpuRegister? = null, + val register: RegisterOrPair? = null, val number: NumericLiteralValue? = null, val expression: Expression? = null ) @@ -138,7 +138,15 @@ internal class AsmAssignSource(val kind: SourceStorageKind, is ArrayLiteralValue -> throw AssemblyError("array literal value should not occur anymore for asm generation") is IdentifierReference -> { val dt = value.inferType(program).typeOrElse(DataType.STRUCT) - AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = asmgen.asmVariableName(value)) + val varName=asmgen.asmVariableName(value) + // special case: "cx16.r[0-15]" are 16-bits virtual registers of the commander X16 system + if(dt==DataType.UWORD && varName.toLowerCase().startsWith("cx16.r")) { + val regStr = varName.toLowerCase().substring(5) + val reg = RegisterOrPair.valueOf(regStr.toUpperCase()) + AsmAssignSource(SourceStorageKind.REGISTER, program, asmgen, dt, register = reg) + } else { + AsmAssignSource(SourceStorageKind.VARIABLE, program, asmgen, dt, variableAsmName = varName) + } } is DirectMemoryRead -> { AsmAssignSource(SourceStorageKind.MEMORY, program, asmgen, DataType.UBYTE, memory = value) 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 e9a08e28c..dcde69104 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -263,7 +263,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } SourceStorageKind.REGISTER -> { - assignRegisterByte(assign.target, assign.source.register!!) + when(assign.source.datatype) { + DataType.UBYTE -> assignRegisterByte(assign.target, assign.source.register!!.asCpuRegister()) + DataType.UWORD -> assignRegisterpairWord(assign.target, assign.source.register!!) + else -> throw AssemblyError("invalid register dt") + } } SourceStorageKind.STACK -> { assignStackValue(assign.target) @@ -1434,7 +1438,15 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen 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") + in Cx16VirtualRegisters -> { + val srcReg = asmgen.asmSymbolName(regs) + asmgen.out(""" + lda $srcReg + sta ${target.asmVarname} + lda $srcReg+1 + sta ${target.asmVarname}+1""") + } + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } } TargetStorageKind.ARRAY -> { @@ -1444,24 +1456,43 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen RegisterOrPair.AX -> asmgen.out(" sta ${target.asmVarname}+$idx | stx ${target.asmVarname}+$idx+1") RegisterOrPair.AY -> asmgen.out(" sta ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1") RegisterOrPair.XY -> asmgen.out(" stx ${target.asmVarname}+$idx | sty ${target.asmVarname}+$idx+1") - else -> throw AssemblyError("expected reg pair") + in Cx16VirtualRegisters -> { + val srcReg = asmgen.asmSymbolName(regs) + asmgen.out(""" + lda $srcReg + sta ${target.asmVarname}+$idx + lda $srcReg+1 + sta ${target.asmVarname}+$idx+1""") + } + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } } else { - when(regs) { - RegisterOrPair.AX -> asmgen.out(" pha | txa | pha") - RegisterOrPair.AY -> asmgen.out(" pha | tya | pha") - RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha") - else -> throw AssemblyError("expected reg pair") - } - asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true) - asmgen.out(""" - pla - sta ${target.asmVarname},y - dey - pla - sta ${target.asmVarname},y""") + if (regs !in Cx16VirtualRegisters) { + when (regs) { + RegisterOrPair.AX -> asmgen.out(" pha | txa | pha") + RegisterOrPair.AY -> asmgen.out(" pha | tya | pha") + RegisterOrPair.XY -> asmgen.out(" txa | pha | tya | pha") + else -> throw AssemblyError("expected reg pair") + } + asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true) + asmgen.out(""" + pla + sta ${target.asmVarname},y + dey + pla + sta ${target.asmVarname},y""") + } else { + val srcReg = asmgen.asmSymbolName(regs) + asmgen.loadScaledArrayIndexIntoRegister(target.array!!, DataType.UWORD, CpuRegister.Y, true) + asmgen.out(""" + lda $srcReg+1 + sta ${target.asmVarname},y + dey + lda $srcReg + sta ${target.asmVarname},y""") } + } } TargetStorageKind.REGISTER -> { when(regs) { @@ -1475,7 +1506,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen stx cx16.${target.register.toString().toLowerCase()}+1 """) } - else -> throw AssemblyError("expected reg pair") + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } RegisterOrPair.AY -> when(target.register!!) { RegisterOrPair.AY -> { } @@ -1487,7 +1518,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen sty cx16.${target.register.toString().toLowerCase()}+1 """) } - else -> throw AssemblyError("expected reg pair") + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } RegisterOrPair.XY -> when(target.register!!) { RegisterOrPair.AY -> { asmgen.out(" txa") } @@ -1499,16 +1530,40 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen sty cx16.${target.register.toString().toLowerCase()}+1 """) } - else -> throw AssemblyError("expected reg pair") + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } - else -> throw AssemblyError("expected reg pair") + in Cx16VirtualRegisters -> { + val srcReg = asmgen.asmSymbolName(regs) + if(regs!=target.register) { + when(target.register) { + RegisterOrPair.AX -> asmgen.out(" lda $srcReg | ldx $srcReg+1") + RegisterOrPair.AY -> asmgen.out(" lda $srcReg | ldy $srcReg+1") + RegisterOrPair.XY -> asmgen.out(" ldx $srcReg | ldy $srcReg+1") + in Cx16VirtualRegisters -> { + val targetReg = asmgen.asmSymbolName(target.register!!) + asmgen.out(" lda $srcReg | sta $targetReg | lda $srcReg+1 | sta $targetReg+1") + } + else -> throw AssemblyError("invalid reg") + } + } + } + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } } TargetStorageKind.STACK -> { when(regs) { - RegisterOrPair.AY -> asmgen.out(" sta P8ESTACK_LO,x | sty P8ESTACK_HI,x | dex") + 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") + in Cx16VirtualRegisters -> { + val srcReg = asmgen.asmSymbolName(regs) + asmgen.out(""" + lda $srcReg + sta P8ESTACK_LO,x + lda $srcReg+1 + sta P8ESTACK_HI,x + dex""") + } + else -> throw AssemblyError("expected reg pair or cx16 virtual 16-bit register") } } TargetStorageKind.MEMORY -> throw AssemblyError("can't store word into memory byte") diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 547fe2f92..6ac6c8a2a 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,6 +2,7 @@ TODO ==== +- refactor the project module structure: make the static ast stuff a separate module, the optimizers another one, etc. - optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions (like repeat loop) - implement the linked_list millfork benchmark - optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2)) diff --git a/examples/test.p8 b/examples/test.p8 index 779e45156..eb841bdcf 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,27 +5,16 @@ main { - sub start() { - uword screencolorRGB - uword drawcolorRGB - ubyte ll - ubyte hh + ubyte lower2_x_bits=1 + ubyte cbits4 + ubyte operand - cx16.vpoke(1, mkword(hh, ll), lsb(screencolorRGB)) + cbits4 &= operand + cbits4 |= operand - cx16.vpoke(lsb(cx16.r1), cx16.r0, cbits4) ; TODO r0 is alreay in r0, avoid bogus assignment here - cbits4 &= gfx2.plot.mask4c[lower2_x_bits] ; TODO why lda..and instead of and mask,y? - cbits4 |= colorbits[lower2_x_bits] ; TODO why lda..ora instead of ora mask,y? + ;cbits4 &= gfx2.plot.mask4c[lower2_x_bits] ; TODO why lda..and instead of and mask,y? + ;cbits4 |= colorbits[lower2_x_bits] ; TODO why lda..ora instead of ora mask,y? -; ubyte value -; ubyte bb1 -; -; value = cx16.vpeek(lsb(cx16.r0), mkword(value, bb1)) -; value = cx16.vpeek(lsb(cx16.r0), mkword(value, bb1)) -; -; ubyte lx = lsb(cx16.r0) -; value = cx16.vpeek(lx, mkword(value, bb1)) -; value = cx16.vpeek(lx, mkword(value, bb1)) } }