diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 5e91847a4..06b205890 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -507,14 +507,6 @@ internal class AsmGen(private val program: Program, } } - internal fun signExtendAtoMsb(destination: String) = - """ - ora #$7f - bmi + - lda #0 -+ sta $destination - """ - internal fun asmIdentifierName(identifier: IdentifierReference): String { val name = if(identifier.memberOfStruct(program.namespace)!=null) { identifier.targetVarDecl(program.namespace)!!.name @@ -524,6 +516,18 @@ internal class AsmGen(private val program: Program, return fixNameSymbols(name) } + internal fun loadByteFromPointerIntoA(pointername: String) { + // TODO if pointer is already in the zeropage, we can omit the copy + out(""" + lda $pointername + ldy $pointername+1 + sta ${C64MachineDefinition.C64Zeropage.SCRATCH_W1} + sty ${C64MachineDefinition.C64Zeropage.SCRATCH_W1 + 1} + ldy #0 + lda (${C64MachineDefinition.C64Zeropage.SCRATCH_W1}),y""") + } + + internal fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names internal fun saveRegister(register: CpuRegister) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index b47274a0f..cc7340436 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -5,6 +5,7 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.compiler.AssemblyError import prog8.compiler.target.c64.C64MachineDefinition +import prog8.compiler.target.c64.C64MachineDefinition.C64Zeropage import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_PLUS1_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX @@ -84,7 +85,15 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge DataType.BYTE -> { when(expr.type) { DataType.UBYTE, DataType.BYTE -> {} - DataType.UWORD, DataType.WORD -> asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | ${asmgen.signExtendAtoMsb("$ESTACK_HI_PLUS1_HEX,x")}") + DataType.UWORD, DataType.WORD -> { + // sign extend + asmgen.out(""" + lda $ESTACK_LO_PLUS1_HEX,x + ora #$7f + bmi + + lda #0 ++ sta $ESTACK_HI_PLUS1_HEX,x""") + } DataType.FLOAT -> asmgen.out(" jsr c64flt.stack_b2float") in PassByReferenceDatatypes -> throw AssemblyError("cannot cast to a pass-by-reference datatype") else -> throw AssemblyError("weird type") @@ -138,15 +147,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge is IdentifierReference -> { // the identifier is a pointer variable, so read the value from the address in it val sourceName = asmgen.asmIdentifierName(expr.addressExpression as IdentifierReference) - asmgen.out(""" - lda $sourceName - sta ${C64MachineDefinition.C64Zeropage.SCRATCH_W1} - lda $sourceName+1 - sta ${C64MachineDefinition.C64Zeropage.SCRATCH_W1+1} - ldy #0 - lda (${C64MachineDefinition.C64Zeropage.SCRATCH_W1}),y - sta $ESTACK_LO_HEX,x - dex""") + asmgen.loadByteFromPointerIntoA(sourceName) + asmgen.out(" sta $ESTACK_LO_HEX,x | dex") } else -> { translateExpression(expr.addressExpression) 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 597d5637a..65514db06 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -804,14 +804,8 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen val sourceName = asmgen.asmIdentifierName(identifier) when(target.kind) { TargetStorageKind.VARIABLE -> { - asmgen.out(""" - lda $sourceName - sta ${C64Zeropage.SCRATCH_W1} - lda $sourceName+1 - sta ${C64Zeropage.SCRATCH_W1+1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y - sta ${target.asmVarname}""") + asmgen.loadByteFromPointerIntoA(sourceName) + asmgen.out(" sta ${target.asmVarname}") } TargetStorageKind.MEMORY -> { storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!) @@ -820,13 +814,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen throw AssemblyError("no asm gen for assign memory byte $sourceName to array ${target.asmVarname} ") } TargetStorageKind.REGISTER -> { - asmgen.out(""" - lda $sourceName - sta ${C64Zeropage.SCRATCH_W1} - lda $sourceName+1 - sta ${C64Zeropage.SCRATCH_W1+1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y""") + asmgen.loadByteFromPointerIntoA(sourceName) when(target.register!!) { RegisterOrPair.A -> {} RegisterOrPair.X -> asmgen.out(" tax") 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 af90c3255..1c8b8e633 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -365,23 +365,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, private fun inplaceModification_byte_value_to_memory(pointername: String, operator: String, value: Expression) { println("warning: slow stack evaluation used (3): @($pointername) $operator= ${value::class.simpleName} at ${value.position}") // TODO asmgen.translateExpression(value) - fun loadByteFromPointerIntoA() { - asmgen.out(""" - lda $pointername - ldy $pointername+1 - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1 + 1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y""") - } when (operator) { // note: ** (power) operator requires floats. "+" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" clc | adc $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier @@ -395,15 +386,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "<<" -> TODO("ubyte asl") ">>" -> TODO("ubyte lsr") "&" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" and $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" xor $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" ora $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") @@ -413,23 +404,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, private fun inplaceModification_byte_variable_to_memory(pointername: String, operator: String, ident: IdentifierReference) { val otherName = asmgen.asmIdentifierName(ident) - fun loadByteFromPointerIntoA() { - asmgen.out(""" - lda $pointername - ldy $pointername+1 - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1 + 1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y""") - } when (operator) { // note: ** (power) operator requires floats. "+" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" clc | adc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" sec | sbc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier @@ -443,15 +425,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "<<" -> TODO("ubyte asl") ">>" -> TODO("ubyte lsr") "&" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" and $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" xor $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - loadByteFromPointerIntoA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" ora $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") @@ -459,23 +441,14 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } private fun inplaceModification_byte_litval_to_memory(pointername: String, operator: String, value: Int) { - fun loadByteFromPointerInA() { - asmgen.out(""" - lda $pointername - ldy $pointername+1 - sta ${C64Zeropage.SCRATCH_W1} - sty ${C64Zeropage.SCRATCH_W1 + 1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y""") - } when (operator) { // note: ** (power) operator requires floats. "+" -> { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" clc | adc #$value | sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier @@ -495,28 +468,28 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "<<" -> { if (value > 0) { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) repeat(value) { asmgen.out(" asl a") } asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } } ">>" -> { if (value > 0) { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) repeat(value) { asmgen.out(" lsr a") } asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } } "&" -> { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" and #$value | sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" xor #$value | sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - loadByteFromPointerInA() + asmgen.loadByteFromPointerIntoA(pointername) asmgen.out(" ora #$value | sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") @@ -1075,13 +1048,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } is IdentifierReference -> { val name = asmgen.asmIdentifierName(mem.addressExpression as IdentifierReference) + asmgen.loadByteFromPointerIntoA(name) asmgen.out(""" - lda $name - sta ${C64Zeropage.SCRATCH_W1} - lda $name+1 - sta ${C64Zeropage.SCRATCH_W1 + 1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y beq + lda #1 + eor #1 @@ -1152,13 +1120,8 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } is IdentifierReference -> { val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference) + asmgen.loadByteFromPointerIntoA(name) asmgen.out(""" - lda $name - sta ${C64Zeropage.SCRATCH_W1} - lda $name+1 - sta ${C64Zeropage.SCRATCH_W1 + 1} - ldy #0 - lda (${C64Zeropage.SCRATCH_W1}),y eor #255 sta (${C64Zeropage.SCRATCH_W1}),y""") } diff --git a/examples/test.p8 b/examples/test.p8 index f9b7678ed..61c8a6e21 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,27 +1,60 @@ %import c64utils -%zeropage basicsafe main { - uword glob=11222 + const uword rom = $e000 + + sub sumrom() -> uword { + uword p = rom + uword s = 0 + ubyte i + repeat $20 { + repeat $100 { + s += @(p) + p++ + } + } + return s + } sub start() { - uword lines = 1 - uword score = $1000 - - ubyte x - ubyte y - - c64scr.print_uw(lines) - c64.CHROUT('\n') - lines=glob - c64scr.print_uw(lines) - c64.CHROUT('\n') - - lines = mkword(x, y) - c64scr.print_uw(lines) - c64.CHROUT('\n') - c64scr.print_uw(score) - c64.CHROUT('\n') + benchcommon.begin() + ubyte i + for i in 0 to 5 { + c64scr.print_uw(sumrom()) + c64.CHROUT('\n') + } + benchcommon.end() } } + + +benchcommon { + uword last_time = 0 + uword time_start = 0 + + + asmsub read_time () clobbers(A,X,Y) { + %asm {{ + jsr $FFDE + sta last_time + stx last_time+1 + rts + }} + } + + sub begin() { + benchcommon.read_time() + benchcommon.time_start = benchcommon.last_time + } + + sub end() { + benchcommon.read_time() + + c64scr.print_uwhex(benchcommon.last_time-benchcommon.time_start, false) + c64.CHROUT('\n') + + void c64scr.input_chars($c000) + } +} +