diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index e0363cc98..7550640ca 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -558,44 +558,6 @@ internal class AsmGen(private val program: Program, } } - fun storeByteIntoPointer(pointervar: IdentifierReference, ldaInstructionArg: String?) { - val sourceName = asmVariableName(pointervar) - val vardecl = pointervar.targetVarDecl(program.namespace)!! - val scopedName = vardecl.makeScopedName(vardecl.name) - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { - if (isZpVar(scopedName)) { - // pointervar is already in the zero page, no need to copy - if (ldaInstructionArg != null) - out(" lda $ldaInstructionArg") - out(" sta ($sourceName)") - } else { - out(""" - ldy $sourceName - sty P8ZP_SCRATCH_W2 - ldy $sourceName+1 - sty P8ZP_SCRATCH_W2+1 - ${if (ldaInstructionArg == null) "" else "lda $ldaInstructionArg"} - sta (P8ZP_SCRATCH_W2)""") - } - } else { - if (isZpVar(scopedName)) { - // pointervar is already in the zero page, no need to copy - if (ldaInstructionArg != null) - out(" lda $ldaInstructionArg") - out(" ldy #0 | sta ($sourceName),y") - } else { - out(""" - ldy $sourceName - sty P8ZP_SCRATCH_W2 - ldy $sourceName+1 - sty P8ZP_SCRATCH_W2+1 - ${if (ldaInstructionArg == null) "" else "lda $ldaInstructionArg"} - ldy #0 - sta (P8ZP_SCRATCH_W2),y""") - } - } - } - private fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names internal fun saveRegisterLocal(register: CpuRegister, scope: Subroutine) { @@ -1369,4 +1331,85 @@ $label nop""") val vardecl = variable.targetVarDecl(program.namespace)!! return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables } + + internal fun pointerViaIndexRegisterPossible(pointerOffsetExpr: Expression): Pair? { + if(pointerOffsetExpr is BinaryExpression && pointerOffsetExpr.operator=="+") { + val leftDt = pointerOffsetExpr.left.inferType(program) + val rightDt = pointerOffsetExpr.left.inferType(program) + if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UBYTE)) + return Pair(pointerOffsetExpr.left, pointerOffsetExpr.right) + if(leftDt.istype(DataType.UBYTE) && rightDt.istype(DataType.UWORD)) + return Pair(pointerOffsetExpr.right, pointerOffsetExpr.left) + if(leftDt.istype(DataType.UWORD) && rightDt.istype(DataType.UWORD)) { + // could be that the index was a constant numeric byte but converted to word, check that + val constIdx = pointerOffsetExpr.right.constValue(program) + if(constIdx!=null && constIdx.number.toInt()>=0 && constIdx.number.toInt()<=255) { + return Pair(pointerOffsetExpr.left, NumericLiteralValue(DataType.UBYTE, constIdx.number, constIdx.position)) + } + // could be that the index was type casted into uword, check that + val rightTc = pointerOffsetExpr.right as? TypecastExpression + if(rightTc!=null && rightTc.expression.inferType(program).istype(DataType.UBYTE)) + return Pair(pointerOffsetExpr.left, rightTc.expression) + val leftTc = pointerOffsetExpr.left as? TypecastExpression + if(leftTc!=null && leftTc.expression.inferType(program).istype(DataType.UBYTE)) + return Pair(pointerOffsetExpr.right, leftTc.expression) + } + + } + return null + } + + internal fun tryOptimizedPointerAccessWithA(expr: BinaryExpression, write: Boolean): Boolean { + // optimize pointer,indexregister if possible + if(expr.operator=="+") { + val ptrAndIndex = pointerViaIndexRegisterPossible(expr) + if(ptrAndIndex!=null) { + val pointervar = ptrAndIndex.first as? IdentifierReference + if(write) { + when(ptrAndIndex.second) { + is NumericLiteralValue, is IdentifierReference -> { + if(pointervar!=null && isZpVar(pointervar)) { + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" sta (${asmSymbolName(pointervar)}),y") + } else { + // copy the pointer var to zp first + assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" sta (P8ZP_SCRATCH_W2),y") + } + } + else -> { + // same as above but we need to save the A register + if(pointervar!=null && isZpVar(pointervar)) { + out(" pha") + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" pla") + out(" sta (${asmSymbolName(pointervar)}),y") + } else { + // copy the pointer var to zp first + assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + out(" pha") + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" pla") + out(" sta (P8ZP_SCRATCH_W2),y") + } + } + } + } else { + if(pointervar!=null && isZpVar(pointervar)) { + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" lda (${asmSymbolName(pointervar)}),y") + } else { + // copy the pointer var to zp first + assignExpressionToVariable(ptrAndIndex.first, asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.Y) + out(" lda (P8ZP_SCRATCH_W2),y") + } + } + return true + } + } + return false + } + } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 4e2ac2e98..18eafcc8c 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -240,11 +240,23 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val val number = (what.addressExpression as NumericLiteralValue).number asmgen.out(" ror ${number.toHex()}") } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) - asmgen.out(""" - sta (+) + 1 - sty (+) + 2 -+ ror ${'$'}ffff ; modified""") + val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression) + if(ptrAndIndex!=null) { + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) + asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) + asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(""" + sta (+) + 1 + sty (+) + 2 ++ ror ${'$'}ffff,x ; modified""") + } else { + asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.out(""" + sta (+) + 1 + sty (+) + 2 ++ ror ${'$'}ffff ; modified""") + } } } is IdentifierReference -> { @@ -329,11 +341,23 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val val number = (what.addressExpression as NumericLiteralValue).number asmgen.out(" rol ${number.toHex()}") } else { - asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) - asmgen.out(""" - sta (+) + 1 - sty (+) + 2 -+ rol ${'$'}ffff ; modified""") + val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression) + if(ptrAndIndex!=null) { + asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X) + asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine()!!) + asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY) + asmgen.restoreRegisterLocal(CpuRegister.X) + asmgen.out(""" + sta (+) + 1 + sty (+) + 2 ++ rol ${'$'}ffff,x ; modified""") + } else { + asmgen.assignExpressionToRegister(what.addressExpression, RegisterOrPair.AY) + asmgen.out(""" + sta (+) + 1 + sty (+) + 2 ++ rol ${'$'}ffff ; modified""") + } } } is IdentifierReference -> { @@ -510,6 +534,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val // optimized simple case: swap two memory locations if(first is DirectMemoryRead && second is DirectMemoryRead) { + // TODO optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2)) val addr1 = (first.addressExpression as? NumericLiteralValue)?.number?.toHex() val addr2 = (second.addressExpression as? NumericLiteralValue)?.number?.toHex() val name1 = if(first.addressExpression is IdentifierReference) asmgen.asmVariableName(first.addressExpression as IdentifierReference) else null diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 224f4fa52..ca8fe0965 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -1462,51 +1462,19 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { if (pushResultOnEstack) { - asmgen.out(" dex | lda (P8ZP_SCRATCH_W2) | sta P8ESTACK_LO+1,x") + asmgen.out(" lda (P8ZP_SCRATCH_W2) | dex | sta P8ESTACK_LO+1,x") } else { asmgen.out(" lda (P8ZP_SCRATCH_W2)") } } else { if (pushResultOnEstack) { - asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x") + asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y | dex | sta P8ESTACK_LO+1,x") } else { asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") } } } - fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean { - // try to optimize simple cases like assignment from ptr+1, ptr+2... - if(expr.operator=="+") { - // we can assume const operand has been moved to the right. - val constOperand = expr.right.constValue(program) - if(constOperand!=null) { - val intIndex = constOperand.number.toInt() - if(intIndex in 1..255) { - val idref = expr.left as? IdentifierReference - if(idref!=null && asmgen.isZpVar(idref)) { - // pointer var is already in zp, we can indirect index immediately - if (pushResultOnEstack) { - asmgen.out(" dex | ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y | sta P8ESTACK_LO+1,x") - } else { - asmgen.out(" ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y") - } - } else { - // copy the pointer var to zp first - asmgen.assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - if (pushResultOnEstack) { - asmgen.out(" dex | ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x") - } else { - asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y") - } - } - return true - } - } - } - return false - } - when(expr.addressExpression) { is NumericLiteralValue -> { val address = (expr.addressExpression as NumericLiteralValue).number.toInt() @@ -1521,8 +1489,12 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge asmgen.out(" sta P8ESTACK_LO,x | dex") } is BinaryExpression -> { - if(!tryOptimizedPointerAccess(expr.addressExpression as BinaryExpression)) + if(asmgen.tryOptimizedPointerAccessWithA(expr.addressExpression as BinaryExpression, false)) { + if(pushResultOnEstack) + asmgen.out(" sta P8ESTACK_LO,x | dex") + } else { assignViaExprEval() + } } else -> assignViaExprEval() } 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 59a2b322f..65a145c03 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -121,31 +121,6 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen assignRegisterByte(assign.target, CpuRegister.A) } - fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean { - // try to optimize simple cases like assignment from ptr+1, ptr+2... - if(expr.operator=="+") { - // we can assume const operand has been moved to the right. - val constOperand = expr.right.constValue(program) - if(constOperand!=null) { - val intIndex = constOperand.number.toInt() - if(intIndex in 1..255) { - val idref = expr.left as? IdentifierReference - if(idref!=null && asmgen.isZpVar(idref)) { - // pointer var is already in zp, we can indirect index immediately - asmgen.out(" ldy #${intIndex} | lda (${asmgen.asmSymbolName(idref)}),y") - } else { - // copy the pointer var to zp first - assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope) - asmgen.out(" ldy #${intIndex} | lda (P8ZP_SCRATCH_W2),y") - } - assignRegisterByte(assign.target, CpuRegister.A) - return true - } - } - } - return false - } - val value = assign.source.memory!! when (value.addressExpression) { is NumericLiteralValue -> { @@ -156,8 +131,11 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen assignMemoryByte(assign.target, null, value.addressExpression as IdentifierReference) } is BinaryExpression -> { - if(!tryOptimizedPointerAccess(value.addressExpression as BinaryExpression)) + if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) { + assignRegisterByte(assign.target, CpuRegister.A) + } else { assignViaExprEval(value.addressExpression) + } } else -> assignViaExprEval(value.addressExpression) } @@ -331,14 +309,37 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } is DirectMemoryRead -> { if(targetDt in WordDatatypes) { - if (value.addressExpression is NumericLiteralValue) { - val address = (value.addressExpression as NumericLiteralValue).number.toInt() - assignMemoryByteIntoWord(target, address, null) - return + + fun assignViaExprEval(addressExpression: Expression) { + asmgen.assignExpressionToVariable(addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) + asmgen.out(" lda (P8ZP_SCRATCH_W2)") + else + asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") + assignRegisterByte(target, CpuRegister.A) } - else if (value.addressExpression is IdentifierReference) { - assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference) - return + + when (value.addressExpression) { + is NumericLiteralValue -> { + val address = (value.addressExpression as NumericLiteralValue).number.toInt() + assignMemoryByteIntoWord(target, address, null) + return + } + is IdentifierReference -> { + assignMemoryByteIntoWord(target, null, value.addressExpression as IdentifierReference) + return + } + is BinaryExpression -> { + if(asmgen.tryOptimizedPointerAccessWithA(value.addressExpression as BinaryExpression, false)) { + asmgen.out(" ldy #0") + assignRegisterpairWord(target, RegisterOrPair.AY) + } else { + assignViaExprEval(value.addressExpression) + } + } + else -> { + assignViaExprEval(value.addressExpression) + } } } } @@ -749,8 +750,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } TargetStorageKind.MEMORY -> { - asmgen.out(" inx") - storeByteViaRegisterAInMemoryAddress("P8ESTACK_LO,x", target.memory!!) + asmgen.out(" inx | lda P8ESTACK_LO,x") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { if(target.constArrayIndexValue!=null) { @@ -1178,7 +1179,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen """) } TargetStorageKind.MEMORY -> { - storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!) + asmgen.out(" lda $sourceName") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { if (target.constArrayIndexValue!=null) { @@ -1338,7 +1340,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" st${register.name.toLowerCase()} ${target.asmVarname}") } TargetStorageKind.MEMORY -> { - storeRegisterInMemoryAddress(register, target.memory!!) + when(register) { + CpuRegister.A -> {} + CpuRegister.X -> asmgen.out(" txa") + CpuRegister.Y -> asmgen.out(" tya") + } + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { if (target.constArrayIndexValue!=null) { @@ -1608,7 +1615,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" stz ${target.asmVarname} ") } TargetStorageKind.MEMORY -> { - storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", target.memory!!) + asmgen.out(" lda #${byte.toHex()}") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { if (target.constArrayIndexValue!=null) { @@ -1647,7 +1655,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" lda #${byte.toHex()} | sta ${target.asmVarname} ") } TargetStorageKind.MEMORY -> { - storeByteViaRegisterAInMemoryAddress("#${byte.toHex()}", target.memory!!) + asmgen.out(" lda #${byte.toHex()}") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { if (target.constArrayIndexValue!=null) { @@ -1831,7 +1840,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen """) } TargetStorageKind.MEMORY -> { - storeByteViaRegisterAInMemoryAddress(address.toHex(), target.memory!!) + asmgen.out(" lda ${address.toHex()}") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { throw AssemblyError("no asm gen for assign memory byte at $address to array ${target.asmVarname}") @@ -1869,7 +1879,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } TargetStorageKind.MEMORY -> { val sourceName = asmgen.asmVariableName(identifier) - storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!) + asmgen.out(" lda $sourceName") + storeRegisterAInMemoryAddress(target.memory!!) } TargetStorageKind.ARRAY -> { throw AssemblyError("no asm gen for assign memory byte $identifier to array ${target.asmVarname} ") @@ -1965,117 +1976,73 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } } - private fun storeByteViaRegisterAInMemoryAddress(ldaInstructionArg: String, memoryAddress: DirectMemoryWrite) { + private fun storeRegisterAInMemoryAddress(memoryAddress: DirectMemoryWrite) { val addressExpr = memoryAddress.addressExpression val addressLv = addressExpr as? NumericLiteralValue fun storeViaExprEval() { - assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) - asmgen.out(" lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2)") - else - asmgen.out(" lda $ldaInstructionArg | ldy #0 | sta (P8ZP_SCRATCH_W2),y") - } - - fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean { - // try to optimize simple cases like storing value to ptr+1, ptr+2... - if(expr.operator=="+") { - // we can assume const operand has been moved to the right. - val constOperand = expr.right.constValue(program) - if(constOperand!=null) { - val intIndex = constOperand.number.toInt() - if(intIndex in 1..255) { - val idref = expr.left as? IdentifierReference - if(idref!=null && asmgen.isZpVar(idref)) { - // pointer var is already in zp, we can indirect index immediately - asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y") - } else { - // copy the pointer var to zp first - assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - asmgen.out(" lda $ldaInstructionArg | ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y") - } - return true - } + when(addressExpr) { + is NumericLiteralValue, is IdentifierReference -> { + assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) + asmgen.out(" sta (P8ZP_SCRATCH_W2)") + else + asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") + } + else -> { + // same as above but we need to save the A register + asmgen.out(" pha") + assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) + asmgen.out(" pla") + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) + asmgen.out(" sta (P8ZP_SCRATCH_W2)") + else + asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") + } + } + } + + fun storeAIntoPointerVar(pointervar: IdentifierReference) { + val sourceName = asmgen.asmVariableName(pointervar) + val vardecl = pointervar.targetVarDecl(program.namespace)!! + val scopedName = vardecl.makeScopedName(vardecl.name) + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { + if (asmgen.isZpVar(scopedName)) { + // pointervar is already in the zero page, no need to copy + asmgen.out(" sta ($sourceName)") + } else { + asmgen.out(""" + ldy $sourceName + sty P8ZP_SCRATCH_W2 + ldy $sourceName+1 + sty P8ZP_SCRATCH_W2+1 + sta (P8ZP_SCRATCH_W2)""") + } + } else { + if (asmgen.isZpVar(scopedName)) { + // pointervar is already in the zero page, no need to copy + asmgen.out(" ldy #0 | sta ($sourceName),y") + } else { + asmgen.out(""" + ldy $sourceName + sty P8ZP_SCRATCH_W2 + ldy $sourceName+1 + sty P8ZP_SCRATCH_W2+1 + ldy #0 + sta (P8ZP_SCRATCH_W2),y""") } } - return false } when { addressLv != null -> { - asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}") + asmgen.out(" sta ${addressLv.number.toHex()}") } addressExpr is IdentifierReference -> { - asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg) + storeAIntoPointerVar(addressExpr) } addressExpr is BinaryExpression -> { - if(!tryOptimizedPointerAccess(addressExpr)) - storeViaExprEval() - } - else -> storeViaExprEval() - } - } - - private fun storeRegisterInMemoryAddress(register: CpuRegister, memoryAddress: DirectMemoryWrite) { - // this is optimized for register A. - val addressExpr = memoryAddress.addressExpression - val addressLv = addressExpr as? NumericLiteralValue - val registerName = register.name.toLowerCase() - - fun storeViaExprEval() { - asmgen.saveRegisterStack(register, false) - assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - asmgen.restoreRegisterStack(CpuRegister.A, false) - if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) - asmgen.out(" sta (P8ZP_SCRATCH_W2)") - else - asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") - } - - fun tryOptimizedPointerAccess(expr: BinaryExpression): Boolean { - // try to optimize simple cases like storing value to ptr+1, ptr+2... - if(expr.operator=="+") { - // we can assume const operand has been moved to the right. - val constOperand = expr.right.constValue(program) - if(constOperand!=null) { - val intIndex = constOperand.number.toInt() - if(intIndex in 1..255) { - val idref = expr.left as? IdentifierReference - if(idref!=null && asmgen.isZpVar(idref)) { - // pointer var is already in zp, we can indirect index immediately - when(register) { - CpuRegister.A -> asmgen.out(" ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y") - CpuRegister.X -> asmgen.out(" txa | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y") - CpuRegister.Y -> asmgen.out(" tya | ldy #${intIndex} | sta (${asmgen.asmSymbolName(idref)}),y") - } - } else { - // copy the pointer var to zp first - asmgen.saveRegisterStack(register, false) - assignExpressionToVariable(expr.left, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - asmgen.restoreRegisterStack(CpuRegister.A, false) - asmgen.out(" ldy #${intIndex} | sta (P8ZP_SCRATCH_W2),y") - } - return true - } - } - } - return false - } - - when { - addressLv != null -> { - asmgen.out(" st$registerName ${addressLv.number.toHex()}") - } - addressExpr is IdentifierReference -> { - when (register) { - CpuRegister.A -> {} - CpuRegister.X -> asmgen.out(" txa") - CpuRegister.Y -> asmgen.out(" tya") - } - asmgen.storeByteIntoPointer(addressExpr, null) - } - addressExpr is BinaryExpression -> { - if(!tryOptimizedPointerAccess(addressExpr)) + if(!asmgen.tryOptimizedPointerAccessWithA(addressExpr, true)) storeViaExprEval() } else -> storeViaExprEval() diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 1cbb119c0..264876880 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -4,14 +4,20 @@ TODO - why is fibonacci example (and others) generating larger code now? fix? - fix textelite saving (and loading?) +- allow uwordpointer[index] syntax -> transform into @(uwordpointer+index) allow index to be >255! +- add any2(), all2(), max2(), min2(), reverse2(), sum2(), sort2() that take (array, startindex, length) arguments +- optimize for loop iterations better to allow proper inx, cpx #value, bne loop instructions (like repeat loop) +- why is there a beq _prog8_label_2_repeatend at the end of repeat loops? seems unused +- optimize swap of two memread values with index, using the same pointer expression/variable, like swap(@(ptr+1), @(ptr+2)) + - can we get rid of the --longOptionName command line options and only keep the short versions? https://github.com/Kotlin/kotlinx-cli/issues/50 - add a f_seek() routine for the Cx16 that uses its seek dos api? -- add a compiler option to generate a symbol listing at the end - optimizer: detect variables that are written but never read - mark those as unused too and remove them, such as uword unused = memory("unused222", 20) - also remove the memory slab allocation +- add a compiler option to not remove unused subroutines. this allows for building library programs - hoist all variable declarations up to the subroutine scope *before* even the constant folding takes place (to avoid undefined symbol errors when referring to a variable from another nested scope in the subroutine) - make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as '_' - option to load the built-in library files from a directory instead of the embedded ones (for easier library development/debugging) -- c64: use VIC banking to move up the graphics bitmap memory location. Move it to $e000 under the kernal rom? +- c64: make the graphics.BITMAP_ADDRESS configurable - some support for recursive subroutines? - via %option recursive?: allocate all params and local vars on estack, don't allow nested subroutines, can begin by first not allowing any local variables just fixing the parameters - Or via a special recursive call operation that copies the current values of all local vars (including arguments) to the stack, replaces the arguments, jsr subroutine, and after returning copy the stack back to the local variables diff --git a/examples/assembler/gen_opcodes.py b/examples/assembler/gen_opcodes.py deleted file mode 100644 index c91705bab..000000000 --- a/examples/assembler/gen_opcodes.py +++ /dev/null @@ -1,496 +0,0 @@ -from collections import Counter -from enum import IntEnum - - -class AddrMode(IntEnum): - Imp = 1, - Acc = 2, - Imm = 3, - Zp = 4, - ZpX = 5, - ZpY = 6, - Rel = 7, - Abs = 8, - AbsX = 9, - AbsY = 10, - Ind = 11, - IzX = 12, - IzY = 13, - Zpr = 14, - Izp = 15, - IaX = 16 - - -AllInstructions = [ - (0x00, "brk", AddrMode.Imp), - (0x01, "ora", AddrMode.IzX), - (0x02, "nop", AddrMode.Imm), - (0x03, "nop", AddrMode.Imp), - (0x04, "tsb", AddrMode.Zp), - (0x05, "ora", AddrMode.Zp), - (0x06, "asl", AddrMode.Zp), - (0x07, "rmb0", AddrMode.Zp), - (0x08, "php", AddrMode.Imp), - (0x09, "ora", AddrMode.Imm), - (0x0a, "asl", AddrMode.Acc), - (0x0b, "nop", AddrMode.Imp), - (0x0c, "tsb", AddrMode.Abs), - (0x0d, "ora", AddrMode.Abs), - (0x0e, "asl", AddrMode.Abs), - (0x0f, "bbr0", AddrMode.Zpr), - (0x10, "bpl", AddrMode.Rel), - (0x11, "ora", AddrMode.IzY), - (0x12, "ora", AddrMode.Izp), - (0x13, "nop", AddrMode.Imp), - (0x14, "trb", AddrMode.Zp), - (0x15, "ora", AddrMode.ZpX), - (0x16, "asl", AddrMode.ZpX), - (0x17, "rmb1", AddrMode.Zp), - (0x18, "clc", AddrMode.Imp), - (0x19, "ora", AddrMode.AbsY), - (0x1a, "inc", AddrMode.Acc), - (0x1b, "nop", AddrMode.Imp), - (0x1c, "trb", AddrMode.Abs), - (0x1d, "ora", AddrMode.AbsX), - (0x1e, "asl", AddrMode.AbsX), - (0x1f, "bbr1", AddrMode.Zpr), - (0x20, "jsr", AddrMode.Abs), - (0x21, "and", AddrMode.IzX), - (0x22, "nop", AddrMode.Imm), - (0x23, "nop", AddrMode.Imp), - (0x24, "bit", AddrMode.Zp), - (0x25, "and", AddrMode.Zp), - (0x26, "rol", AddrMode.Zp), - (0x27, "rmb2", AddrMode.Zp), - (0x28, "plp", AddrMode.Imp), - (0x29, "and", AddrMode.Imm), - (0x2a, "rol", AddrMode.Acc), - (0x2b, "nop", AddrMode.Imp), - (0x2c, "bit", AddrMode.Abs), - (0x2d, "and", AddrMode.Abs), - (0x2e, "rol", AddrMode.Abs), - (0x2f, "bbr2", AddrMode.Zpr), - (0x30, "bmi", AddrMode.Rel), - (0x31, "and", AddrMode.IzY), - (0x32, "and", AddrMode.Izp), - (0x33, "nop", AddrMode.Imp), - (0x34, "bit", AddrMode.ZpX), - (0x35, "and", AddrMode.ZpX), - (0x36, "rol", AddrMode.ZpX), - (0x37, "rmb3", AddrMode.Zp), - (0x38, "sec", AddrMode.Imp), - (0x39, "and", AddrMode.AbsY), - (0x3a, "dec", AddrMode.Acc), - (0x3b, "nop", AddrMode.Imp), - (0x3c, "bit", AddrMode.AbsX), - (0x3d, "and", AddrMode.AbsX), - (0x3e, "rol", AddrMode.AbsX), - (0x3f, "bbr3", AddrMode.Zpr), - (0x40, "rti", AddrMode.Imp), - (0x41, "eor", AddrMode.IzX), - (0x42, "nop", AddrMode.Imm), - (0x43, "nop", AddrMode.Imp), - (0x44, "nop", AddrMode.Zp), - (0x45, "eor", AddrMode.Zp), - (0x46, "lsr", AddrMode.Zp), - (0x47, "rmb4", AddrMode.Zp), - (0x48, "pha", AddrMode.Imp), - (0x49, "eor", AddrMode.Imm), - (0x4a, "lsr", AddrMode.Acc), - (0x4b, "nop", AddrMode.Imp), - (0x4c, "jmp", AddrMode.Abs), - (0x4d, "eor", AddrMode.Abs), - (0x4e, "lsr", AddrMode.Abs), - (0x4f, "bbr4", AddrMode.Zpr), - (0x50, "bvc", AddrMode.Rel), - (0x51, "eor", AddrMode.IzY), - (0x52, "eor", AddrMode.Izp), - (0x53, "nop", AddrMode.Imp), - (0x54, "nop", AddrMode.ZpX), - (0x55, "eor", AddrMode.ZpX), - (0x56, "lsr", AddrMode.ZpX), - (0x57, "rmb5", AddrMode.Zp), - (0x58, "cli", AddrMode.Imp), - (0x59, "eor", AddrMode.AbsY), - (0x5a, "phy", AddrMode.Imp), - (0x5b, "nop", AddrMode.Imp), - (0x5c, "nop", AddrMode.Abs), - (0x5d, "eor", AddrMode.AbsX), - (0x5e, "lsr", AddrMode.AbsX), - (0x5f, "bbr5", AddrMode.Zpr), - (0x60, "rts", AddrMode.Imp), - (0x61, "adc", AddrMode.IzX), - (0x62, "nop", AddrMode.Imm), - (0x63, "nop", AddrMode.Imp), - (0x64, "stz", AddrMode.Zp), - (0x65, "adc", AddrMode.Zp), - (0x66, "ror", AddrMode.Zp), - (0x67, "rmb6", AddrMode.Zp), - (0x68, "pla", AddrMode.Imp), - (0x69, "adc", AddrMode.Imm), - (0x6a, "ror", AddrMode.Acc), - (0x6b, "nop", AddrMode.Imp), - (0x6c, "jmp", AddrMode.Ind), - (0x6d, "adc", AddrMode.Abs), - (0x6e, "ror", AddrMode.Abs), - (0x6f, "bbr6", AddrMode.Zpr), - (0x70, "bvs", AddrMode.Rel), - (0x71, "adc", AddrMode.IzY), - (0x72, "adc", AddrMode.Izp), - (0x73, "nop", AddrMode.Imp), - (0x74, "stz", AddrMode.ZpX), - (0x75, "adc", AddrMode.ZpX), - (0x76, "ror", AddrMode.ZpX), - (0x77, "rmb7", AddrMode.Zp), - (0x78, "sei", AddrMode.Imp), - (0x79, "adc", AddrMode.AbsY), - (0x7a, "ply", AddrMode.Imp), - (0x7b, "nop", AddrMode.Imp), - (0x7c, "jmp", AddrMode.IaX), - (0x7d, "adc", AddrMode.AbsX), - (0x7e, "ror", AddrMode.AbsX), - (0x7f, "bbr7", AddrMode.Zpr), - (0x80, "bra", AddrMode.Rel), - (0x81, "sta", AddrMode.IzX), - (0x82, "nop", AddrMode.Imm), - (0x83, "nop", AddrMode.Imp), - (0x84, "sty", AddrMode.Zp), - (0x85, "sta", AddrMode.Zp), - (0x86, "stx", AddrMode.Zp), - (0x87, "smb0", AddrMode.Zp), - (0x88, "dey", AddrMode.Imp), - (0x89, "bit", AddrMode.Imm), - (0x8a, "txa", AddrMode.Imp), - (0x8b, "nop", AddrMode.Imp), - (0x8c, "sty", AddrMode.Abs), - (0x8d, "sta", AddrMode.Abs), - (0x8e, "stx", AddrMode.Abs), - (0x8f, "bbs0", AddrMode.Zpr), - (0x90, "bcc", AddrMode.Rel), - (0x91, "sta", AddrMode.IzY), - (0x92, "sta", AddrMode.Izp), - (0x93, "nop", AddrMode.Imp), - (0x94, "sty", AddrMode.ZpX), - (0x95, "sta", AddrMode.ZpX), - (0x96, "stx", AddrMode.ZpY), - (0x97, "smb1", AddrMode.Zp), - (0x98, "tya", AddrMode.Imp), - (0x99, "sta", AddrMode.AbsY), - (0x9a, "txs", AddrMode.Imp), - (0x9b, "nop", AddrMode.Imp), - (0x9c, "stz", AddrMode.Abs), - (0x9d, "sta", AddrMode.AbsX), - (0x9e, "stz", AddrMode.AbsX), - (0x9f, "bbs1", AddrMode.Zpr), - (0xa0, "ldy", AddrMode.Imm), - (0xa1, "lda", AddrMode.IzX), - (0xa2, "ldx", AddrMode.Imm), - (0xa3, "nop", AddrMode.Imp), - (0xa4, "ldy", AddrMode.Zp), - (0xa5, "lda", AddrMode.Zp), - (0xa6, "ldx", AddrMode.Zp), - (0xa7, "smb2", AddrMode.Zp), - (0xa8, "tay", AddrMode.Imp), - (0xa9, "lda", AddrMode.Imm), - (0xaa, "tax", AddrMode.Imp), - (0xab, "nop", AddrMode.Imp), - (0xac, "ldy", AddrMode.Abs), - (0xad, "lda", AddrMode.Abs), - (0xae, "ldx", AddrMode.Abs), - (0xaf, "bbs2", AddrMode.Zpr), - (0xb0, "bcs", AddrMode.Rel), - (0xb1, "lda", AddrMode.IzY), - (0xb2, "lda", AddrMode.Izp), - (0xb3, "nop", AddrMode.Imp), - (0xb4, "ldy", AddrMode.ZpX), - (0xb5, "lda", AddrMode.ZpX), - (0xb6, "ldx", AddrMode.ZpY), - (0xb7, "smb3", AddrMode.Zp), - (0xb8, "clv", AddrMode.Imp), - (0xb9, "lda", AddrMode.AbsY), - (0xba, "tsx", AddrMode.Imp), - (0xbb, "nop", AddrMode.Imp), - (0xbc, "ldy", AddrMode.AbsX), - (0xbd, "lda", AddrMode.AbsX), - (0xbe, "ldx", AddrMode.AbsY), - (0xbf, "bbs3", AddrMode.Zpr), - (0xc0, "cpy", AddrMode.Imm), - (0xc1, "cmp", AddrMode.IzX), - (0xc2, "nop", AddrMode.Imm), - (0xc3, "nop", AddrMode.Imp), - (0xc4, "cpy", AddrMode.Zp), - (0xc5, "cmp", AddrMode.Zp), - (0xc6, "dec", AddrMode.Zp), - (0xc7, "smb4", AddrMode.Zp), - (0xc8, "iny", AddrMode.Imp), - (0xc9, "cmp", AddrMode.Imm), - (0xca, "dex", AddrMode.Imp), - (0xcb, "wai", AddrMode.Imp), - (0xcc, "cpy", AddrMode.Abs), - (0xcd, "cmp", AddrMode.Abs), - (0xce, "dec", AddrMode.Abs), - (0xcf, "bbs4", AddrMode.Zpr), - (0xd0, "bne", AddrMode.Rel), - (0xd1, "cmp", AddrMode.IzY), - (0xd2, "cmp", AddrMode.Izp), - (0xd3, "nop", AddrMode.Imp), - (0xd4, "nop", AddrMode.ZpX), - (0xd5, "cmp", AddrMode.ZpX), - (0xd6, "dec", AddrMode.ZpX), - (0xd7, "smb5", AddrMode.Zp), - (0xd8, "cld", AddrMode.Imp), - (0xd9, "cmp", AddrMode.AbsY), - (0xda, "phx", AddrMode.Imp), - (0xdb, "stp", AddrMode.Imp), - (0xdc, "nop", AddrMode.Abs), - (0xdd, "cmp", AddrMode.AbsX), - (0xde, "dec", AddrMode.AbsX), - (0xdf, "bbs5", AddrMode.Zpr), - (0xe0, "cpx", AddrMode.Imm), - (0xe1, "sbc", AddrMode.IzX), - (0xe2, "nop", AddrMode.Imm), - (0xe3, "nop", AddrMode.Imp), - (0xe4, "cpx", AddrMode.Zp), - (0xe5, "sbc", AddrMode.Zp), - (0xe6, "inc", AddrMode.Zp), - (0xe7, "smb6", AddrMode.Zp), - (0xe8, "inx", AddrMode.Imp), - (0xe9, "sbc", AddrMode.Imm), - (0xea, "nop", AddrMode.Imp), - (0xeb, "nop", AddrMode.Imp), - (0xec, "cpx", AddrMode.Abs), - (0xed, "sbc", AddrMode.Abs), - (0xee, "inc", AddrMode.Abs), - (0xef, "bbs6", AddrMode.Zpr), - (0xf0, "beq", AddrMode.Rel), - (0xf1, "sbc", AddrMode.IzY), - (0xf2, "sbc", AddrMode.Izp), - (0xf3, "nop", AddrMode.Imp), - (0xf4, "nop", AddrMode.ZpX), - (0xf5, "sbc", AddrMode.ZpX), - (0xf6, "inc", AddrMode.ZpX), - (0xf7, "smb7", AddrMode.Zp), - (0xf8, "sed", AddrMode.Imp), - (0xf9, "sbc", AddrMode.AbsY), - (0xfa, "plx", AddrMode.Imp), - (0xfb, "nop", AddrMode.Imp), - (0xfc, "nop", AddrMode.AbsX), - (0xfd, "sbc", AddrMode.AbsX), - (0xfe, "inc", AddrMode.AbsX), - (0xff, "bbs7", AddrMode.Zpr) -] - -# NOP is weird, it is all over the place. -# For the 'common' immediate NOP, keep only the $EA opcode (this was the original NOP on the 6502) -Instructions = [ins for ins in AllInstructions if ins[1] != "nop"] + [(0xea, "nop", AddrMode.Imp)] - - -InstructionsByName = {} -for ins in Instructions: - if ins[1] not in InstructionsByName: - InstructionsByName[ins[1]] = {ins[2]: ins[0]} - else: - InstructionsByName[ins[1]][ins[2]] = ins[0] - -InstructionsByMode = {} -for ins in Instructions: - if ins[2] not in InstructionsByMode: - InstructionsByMode[ins[2]] = [(ins[1], ins[0])] - else: - InstructionsByMode[ins[2]].append((ins[1], ins[0])) - -# build the name->modes table - -print("; generated by opcodes.py") -print("; addressing modes:") -for mode in AddrMode: - print(";", mode.value, "=", mode.name) -print() - -print(""" - .enc "petscii" ;define an ascii to petscii encoding - .cdef " @", 32 ;characters - .cdef "AZ", $c1 - .cdef "az", $41 - .cdef "[[", $5b - .cdef "]]", $5d - .edef "", [];replace with no bytes -""") - -for instr in sorted(InstructionsByName.items()): - print("i_" + instr[0] + ":\n\t.byte ", end="") - if len(instr[1]) == 1: - # many instructions have just 1 addressing mode, save space for those - info = instr[1].popitem() - print("1,", info[0].value,",", info[1]) - else: - print("0, ", end='') - mode_opcodes = [] - for mode in AddrMode: - if mode in instr[1]: - mode_opcodes.append(instr[1][mode]) - else: - mode_opcodes.append(0) - print(",".join(str(o) for o in mode_opcodes), end="") - print() - - -def determine_mnemonics(): - mnemonics = list(sorted(set(ins[1] for ins in Instructions))) - - # opcodes histogram (ordered by occurrence) (in kernal + basic roms of the c64): - opcode_occurrences = [ - (32, 839), (133, 502), (165, 488), (0, 429), (208, 426), (169, 390), (76, 324), (240, 322), (2, 314), (160, 245), - (96, 228), (3, 201), (1, 191), (255, 186), (144, 182), (170, 175), (162, 169), (177, 165), (104, 159), (164, 158), - (132, 157), (201, 156), (72, 151), (141, 150), (200, 146), (173, 144), (166, 139), (176, 139), (16, 138), - (134, 138), (73, 127), (24, 119), (101, 113), (69, 109), (13, 107), (34, 104), (145, 103), (4, 102), (168, 101), - (221, 98), (230, 93), (48, 91), (189, 87), (41, 86), (6, 86), (9, 86), (8, 85), (79, 85), (138, 80), (10, 80), - (7, 79), (185, 77), (56, 75), (44, 75), (78, 74), (105, 73), (5, 73), (174, 73), (220, 71), (198, 69), (232, 69), - (36, 69), (202, 67), (152, 67), (95, 67), (100, 65), (102, 65), (247, 65), (188, 64), (136, 64), (84, 64), - (122, 62), (128, 61), (80, 61), (186, 60), (82, 59), (97, 58), (15, 57), (70, 57), (229, 56), (19, 55), (40, 54), - (183, 54), (65, 54), (233, 53), (180, 53), (12, 53), (171, 53), (197, 53), (83, 52), (248, 52), (112, 51), - (237, 51), (89, 50), (11, 50), (158, 50), (74, 49), (224, 48), (20, 47), (238, 47), (108, 46), (234, 46), - (251, 46), (254, 46), (184, 45), (14, 44), (163, 44), (226, 43), (211, 43), (88, 43), (98, 42), (17, 42), - (153, 42), (243, 41), (228, 41), (99, 41), (253, 41), (209, 41), (187, 39), (123, 39), (67, 39), (196, 38), - (68, 38), (35, 38), (172, 38), (175, 38), (161, 38), (85, 38), (191, 37), (113, 37), (182, 37), (151, 37), - (71, 36), (181, 35), (214, 35), (121, 35), (157, 35), (178, 35), (77, 35), (42, 34), (212, 33), (18, 33), - (127, 33), (241, 33), (21, 33), (249, 32), (23, 31), (245, 30), (142, 30), (55, 29), (140, 29), (46, 29), - (192, 29), (179, 29), (252, 29), (115, 29), (22, 29), (43, 28), (215, 28), (45, 28), (246, 28), (38, 28), - (86, 27), (225, 27), (25, 26), (239, 26), (58, 26), (167, 26), (147, 26), (217, 26), (149, 25), (30, 25), - (206, 25), (28, 24), (47, 24), (37, 24), (155, 24), (129, 23), (148, 23), (111, 23), (29, 23), (39, 23), - (51, 22), (193, 22), (236, 22), (120, 22), (64, 22), (204, 21), (210, 21), (244, 21), (52, 21), (66, 21), - (114, 20), (250, 20), (106, 20), (93, 19), (199, 19), (218, 19), (154, 19), (205, 19), (50, 19), (159, 19), - (194, 19), (49, 19), (190, 19), (103, 18), (216, 18), (213, 18), (107, 18), (131, 18), (63, 18), (94, 18), - (91, 17), (242, 17), (109, 17), (53, 16), (227, 16), (139, 16), (31, 16), (75, 16), (60, 16), (195, 15), - (231, 15), (62, 15), (59, 15), (87, 14), (207, 14), (27, 14), (90, 14), (110, 13), (223, 13), (57, 13), - (118, 12), (26, 12), (203, 12), (81, 12), (156, 12), (54, 12), (235, 12), (146, 11), (135, 11), (126, 11), - (150, 11), (130, 11), (143, 10), (61, 10), (219, 10), (124, 9), (222, 9), (125, 9), (119, 7), (137, 7), - (33, 7), (117, 5), (92, 4), (116, 3) - ] - - cnt = Counter() - for opcode, amount in opcode_occurrences: - cnt[AllInstructions[opcode][1]] += amount - cnt["nop"] = 13 - cnt["tsb"] = 13 - - four_letter_mnemonics = list(sorted([ins[1] for ins in AllInstructions if len(ins[1])>3])) - for ins4 in four_letter_mnemonics: - del cnt[ins4] - cnt[ins4] = 1 - mnem2 = [c[0] for c in cnt.most_common()] - if len(mnem2)!=len(mnemonics): - raise ValueError("mnem count mismatch") - return mnem2 - - -mnemonics = determine_mnemonics() - - -def first_letters(): - firstletters = {m[0]: 0 for m in mnemonics} - return firstletters.keys() - - -def second_letters(firstletter): - secondletters = {m[1]: 0 for m in mnemonics if m[0] == firstletter} - return secondletters.keys() - - -def third_letters(firstletter, secondletter): - thirdletters = {m[2]: 0 for m in mnemonics if m[0] == firstletter and m[1] == secondletter} - return thirdletters.keys() - - -def fourth_letters(firstletter, secondletter, thirdletter): - longmnem = [m for m in mnemonics if len(m) > 3] - fourthletters = {m[3]: 0 for m in longmnem if m[0] == firstletter and m[1] == secondletter and m[2] == thirdletter} - return fourthletters.keys() - - -def make_tree(): - tree = {} - for first in first_letters(): - tree[first] = { - secondletter: { - thirdletter: { - fourthletter: {} - for fourthletter in fourth_letters(first, secondletter, thirdletter) - } - for thirdletter in third_letters(first, secondletter) - } - for secondletter in second_letters(first) - } - return tree - - -tree = make_tree() - - -print("get_opcode_info .proc") -print("_mnem_fourth_letter = cx16.r4") -print("_mnem_fifth_letter = cx16.r5") -for first in tree: - print(" cmp #'%s'" % first) - print(" bne _not_%s" % first) - for second in tree[first]: - print(" cpx #'%s'" % second) - print(" bne _not_%s%s" % (first,second)) - for third in tree[first][second]: - print(" cpy #'%s'" % third) - print(" bne _not_%s%s%s" % (first, second, third)) - fourth = tree[first][second][third] - if fourth: - if "".join(fourth.keys()) != "01234567": - raise ValueError("fourth", fourth.keys()) - print(" bra _check_%s%s%s" % (first, second, third)) - else: - print(" lda _mnem_fourth_letter") # check that the fourth letter is not present - print(" bne _invalid") - print(" lda #i_%s%s%s" % (first, second, third)) - print(" rts") - print("_not_%s%s%s:" % (first, second, third)) - print("_not_%s%s:" % (first, second)) - print("_not_%s:" % first) -print("_invalid:") -print(" lda #0") -print(" ldy #0") -print(" rts") - -# the 4-letter mnemonics are: -# smb[0-7] -# bbr[0-7] -# rmb[0-7] -# bbs[0-7] -for fourlettermnemonic in ["smb", "bbr", "rmb", "bbs"]: - print("_check_%s" % fourlettermnemonic) - print(" lda #<_tab_%s" % fourlettermnemonic) - print(" ldy #>_tab_%s" % fourlettermnemonic) - print(""" sta P8ZP_SCRATCH_W2 - sty P8ZP_SCRATCH_W2+1 - bra _check4""") - -print("""_check4 - lda _mnem_fourth_letter - cmp #'0' - bcc _invalid - cmp #'8' - bcs _invalid - lda _mnem_fifth_letter ; must have no fifth letter - bne _invalid - tay - lda (P8ZP_SCRATCH_W2),y - pha - iny - lda (P8ZP_SCRATCH_W2),y - tay - pla - rts""") - -for fourlettermnemonic in ["smb", "bbr", "rmb", "bbs"]: - print("_tab_%s" % fourlettermnemonic) - for ii in "01234567": - print(" .word i_%s%s" % (fourlettermnemonic, ii)) - -print(" .pend") diff --git a/examples/plasma.p8 b/examples/plasma.p8 index 396a312a2..3f719b826 100644 --- a/examples/plasma.p8 +++ b/examples/plasma.p8 @@ -79,7 +79,7 @@ main { for x in 39 downto 0 { ; using a temp var here to enable expression optimization that can't be done on a 'problematic' ROM/RAM memory location ubyte cc = xbuf[x] + ybuf[y] - @(screen) = cc + @(screen+x) = cc ; this is the fastest way to do this inner part: ; %asm {{ ; ldy i @@ -90,8 +90,8 @@ main { ; ldy #0 ; sta (screen),y ; }} - screen++ - } + } + screen += 40 } } diff --git a/examples/test.p8 b/examples/test.p8 index 50e731187..0f33f7d92 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,40 +7,35 @@ main { sub start() { - str name = "abcdef" + uword screen=$0400 + ubyte[256] xbuf = 1 + ubyte[256] ybuf = 3 - uword ptr = &name - ubyte cc - cc = @(ptr) - txt.chrout(cc) - txt.nl() - cc = @(ptr+1) - txt.chrout(cc) - txt.nl() - cc = @(ptr+2) - txt.chrout(cc) - txt.nl() - txt.nl() + ubyte ix = 0 + ubyte cc = 0 - cc=0 - txt.chrout(@(ptr)+cc) - txt.chrout(@(ptr+1)+cc) - txt.chrout(@(ptr+2)+cc) - txt.nl() + repeat 20 { + cc++ + } - @(ptr) = '1' - @(ptr+1) = '2' - @(ptr+2) = '3' - txt.print(name) - txt.nl() + @(screen) = 1 + @(screen+1) = 2 + swap(@(screen), @(screen+1)) - cc=0 - @(ptr+cc) = 'a' - @(ptr+cc+1) = 'b' - @(ptr+cc+2) = 'c' - txt.print(name) - txt.nl() +; cc = @(screen+2) +; cc++ +; @(screen+2) = cc + +; cc = @(screen+ix) +; cc++ +; @(screen+ix) = cc +; for ii in 24 downto 0 { +; for i in 39 downto 0 { +; @(screen+i) = xbuf[i] + ybuf[ii] +; } +; screen+=40 +; } } } diff --git a/examples/testarrays.p8 b/examples/testarrays.p8 deleted file mode 100644 index ac04af2ef..000000000 --- a/examples/testarrays.p8 +++ /dev/null @@ -1,141 +0,0 @@ -%import textio -%import floats -%zeropage basicsafe - -; Note: this program is compatible with C64 and CX16. - -main { - - ; this is only a parser/compiler test, there's no actual working program - - sub start() { - txt.print("this is only a parser/compiler test\n") - return - - str s1 = "hello" - str s2 = @"screencodes" - - &str ms1 = $c000 - - byte[4] barray - ubyte[4] ubarray - word[4] warray - uword[4] uwarray - float[4] flarray - - &byte[4] mbarray = $c000 - &ubyte[4] mubarray = $c000 - &word[4] mwarray = $c000 - &uword[4] muwarray = $c000 - &float[4] mflarray = $c000 - - ubyte a - byte bb - ubyte ub - word ww - uword uw - float fl - - ; read array - a=s1[2] - ub=s1[2] - bb=barray[2] - ub=ubarray[2] - ww=warray[2] - uw=uwarray[2] - fl=flarray[2] - a=ms1[2] - ub=ms1[2] - bb=mbarray[2] - ub=mubarray[2] - ww=mwarray[2] - uw=muwarray[2] - fl=mflarray[2] - - a=s1[a] - ub=s1[a] - bb=barray[a] - ub=ubarray[a] - ww=warray[a] - uw=uwarray[a] - fl=flarray[a] - a=ms1[a] - ub=ms1[a] - bb=mbarray[a] - ub=mubarray[a] - ww=mwarray[a] - uw=muwarray[a] - fl=mflarray[a] - - a=s1[bb] - ub=s1[bb] - bb=barray[bb] - ub=ubarray[bb] - ww=warray[bb] - uw=uwarray[bb] - fl=flarray[bb] - a=ms1[bb] - ub=ms1[bb] - bb=mbarray[bb] - ub=mubarray[bb] - ww=mwarray[bb] - uw=muwarray[bb] - fl=mflarray[bb] - -; a=s1[bb*3] -; ub=s1[bb*3] -; bb=barray[bb*3] -; ub=ubarray[bb*3] -; ww=warray[bb*3] -; uw=uwarray[bb*3] -; fl=flarray[bb*3] -; a=ms1[bb*3] -; ub=ms1[bb*3] -; bb=mbarray[bb*3] -; ub=mubarray[bb*3] -; ww=mwarray[bb*3] -; uw=muwarray[bb*3] -; fl=mflarray[bb*3] - - ; write array - barray[2]++ - barray[2]-- - s1[2] = a - s1[2] = ub - barray[2] = bb - ubarray[2] = ub - warray[2] = ww - uwarray[2] = uw - flarray[2] = fl - ms1[2] = a - ms1[2] = ub - mbarray[2]++ - mbarray[2] = bb - mbarray[2] = bb - mubarray[2] = ub - mwarray[2] = ww - muwarray[2] = uw - mflarray[2] = fl - - s1[a] = ub - barray[a] = bb - ubarray[a] = ub - warray[a] = ww - uwarray[a] = uw - flarray[a] = fl - - s1[bb] = ub - barray[bb] = bb - ubarray[bb] = ub - warray[bb] = ww - uwarray[bb] = uw - flarray[bb] = fl - -; s1[bb*3] = ub -; barray[bb*3] = bb -; ubarray[bb*3] = ub -; warray[bb*3] = ww -; uwarray[bb*3] = uw -; flarray[bb*3] = fl - } -} diff --git a/scripts/clean.sh b/scripts/clean.sh index 0b500088d..501762675 100755 --- a/scripts/clean.sh +++ b/scripts/clean.sh @@ -1,5 +1,5 @@ #!/usr/bin/env sh -rm -f *.jar *.asm *.prg *.vm.txt *.vice-mon-list +rm -f *.jar *.asm *.prg *.vm.txt *.vice-mon-list a.out rm -rf build out