diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 06b205890..fa90acf52 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -12,6 +12,7 @@ import prog8.compiler.target.IAssemblyGenerator import prog8.compiler.target.IAssemblyProgram import prog8.compiler.target.c64.AssemblyProgram 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_LO_HEX import prog8.compiler.target.c64.Petscii @@ -516,17 +517,47 @@ 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 loadByteFromPointerIntoA2(pointervar: IdentifierReference): Pair { + // returns if the pointer is already on the ZP itself or not (in which case SCRATCH_W1 is used as intermediary) + val sourceName = asmIdentifierName(pointervar) + val vardecl = pointervar.targetVarDecl(program.namespace)!! + val scopedName = vardecl.makeScopedName(vardecl.name) + if(scopedName in allocatedZeropageVariables) { + // pointervar is already in the zero page, no need to copy + out(" ldy #0 | lda ($sourceName),y") + return Pair(true, sourceName) + } else { + out(""" + lda $sourceName + ldy $sourceName+1 + sta ${C64Zeropage.SCRATCH_W1} + sty ${C64Zeropage.SCRATCH_W1 + 1} + ldy #0 + lda (${C64Zeropage.SCRATCH_W1}),y""") + return Pair(false, sourceName) + } } + fun storeByteIntoPointer(pointervar: IdentifierReference, ldaInstructionArg: String?) { + val sourceName = asmIdentifierName(pointervar) + val vardecl = pointervar.targetVarDecl(program.namespace)!! + val scopedName = vardecl.makeScopedName(vardecl.name) + if(scopedName in allocatedZeropageVariables) { + // 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 ${C64Zeropage.SCRATCH_W2} + ldy $sourceName+1 + sty ${C64Zeropage.SCRATCH_W2 + 1} + ${if(ldaInstructionArg==null) "" else "lda $ldaInstructionArg"} + ldy #0 + sta (${C64Zeropage.SCRATCH_W2}),y""") + } + } internal fun fixNameSymbols(name: String) = name.replace("<", "prog8_").replace(">", "") // take care of the autogenerated invalid (anon) label names diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index cc7340436..a01135a05 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -4,7 +4,6 @@ import prog8.ast.Program 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 @@ -146,8 +145,7 @@ 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.loadByteFromPointerIntoA(sourceName) + asmgen.loadByteFromPointerIntoA2(expr.addressExpression as IdentifierReference) asmgen.out(" sta $ESTACK_LO_HEX,x | dex") } else -> { @@ -226,8 +224,8 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge if (amount <= 2) repeat(amount) { asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | asl a | ror $ESTACK_LO_PLUS1_HEX,x") } else { - asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | sta ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}") - repeat(amount) { asmgen.out(" asl a | ror ${C64MachineDefinition.C64Zeropage.SCRATCH_B1} | lda ${C64MachineDefinition.C64Zeropage.SCRATCH_B1}") } + asmgen.out(" lda $ESTACK_LO_PLUS1_HEX,x | sta ${C64Zeropage.SCRATCH_B1}") + repeat(amount) { asmgen.out(" asl a | ror ${C64Zeropage.SCRATCH_B1} | lda ${C64Zeropage.SCRATCH_B1}") } asmgen.out(" sta $ESTACK_LO_PLUS1_HEX,x") } } 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 65514db06..cf45d6197 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -10,7 +10,6 @@ import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_HI_HEX import prog8.compiler.target.c64.C64MachineDefinition.ESTACK_LO_HEX import prog8.compiler.target.c64.codegen.AsmGen import prog8.compiler.toHex -import prog8.functions.BuiltinFunctions internal class AssignmentAsmGen(private val program: Program, private val asmgen: AsmGen) { @@ -801,20 +800,20 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen TargetStorageKind.STACK -> TODO() } } else if (identifier != null) { - val sourceName = asmgen.asmIdentifierName(identifier) when(target.kind) { TargetStorageKind.VARIABLE -> { - asmgen.loadByteFromPointerIntoA(sourceName) + asmgen.loadByteFromPointerIntoA2(identifier) asmgen.out(" sta ${target.asmVarname}") } TargetStorageKind.MEMORY -> { + val sourceName = asmgen.asmIdentifierName(identifier) storeByteViaRegisterAInMemoryAddress(sourceName, target.memory!!) } TargetStorageKind.ARRAY -> { - throw AssemblyError("no asm gen for assign memory byte $sourceName to array ${target.asmVarname} ") + throw AssemblyError("no asm gen for assign memory byte $identifier to array ${target.asmVarname} ") } TargetStorageKind.REGISTER -> { - asmgen.loadByteFromPointerIntoA(sourceName) + asmgen.loadByteFromPointerIntoA2(identifier) when(target.register!!) { RegisterOrPair.A -> {} RegisterOrPair.X -> asmgen.out(" tax") @@ -835,15 +834,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" lda $ldaInstructionArg | sta ${addressLv.number.toHex()}") } addressExpr is IdentifierReference -> { - val pointerVarName = asmgen.asmIdentifierName(addressExpr) - asmgen.out(""" - lda $pointerVarName - sta ${C64Zeropage.SCRATCH_W2} - lda $pointerVarName+1 - sta ${C64Zeropage.SCRATCH_W2+1} - lda $ldaInstructionArg - ldy #0 - sta (${C64Zeropage.SCRATCH_W2}),y""") + asmgen.storeByteIntoPointer(addressExpr, ldaInstructionArg) } else -> { asmgen.translateExpression(addressExpr) @@ -870,19 +861,12 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.out(" st$registerName ${addressLv.number.toHex()}") } addressExpr is IdentifierReference -> { - val targetName = asmgen.asmIdentifierName(addressExpr) when (register) { CpuRegister.A -> {} CpuRegister.X -> asmgen.out(" txa") CpuRegister.Y -> asmgen.out(" tya") } - asmgen.out(""" - ldy $targetName - sty ${C64Zeropage.SCRATCH_W1} - ldy $targetName+1 - sty ${C64Zeropage.SCRATCH_W1+1} - ldy #0 - sta (${C64Zeropage.SCRATCH_W1}),y""") + asmgen.storeByteIntoPointer(addressExpr, null) } else -> { asmgen.saveRegister(register) 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 1c8b8e633..0d5dd586c 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -178,16 +178,16 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } } is IdentifierReference -> { - val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference) + val pointer = memory.addressExpression as IdentifierReference when { - valueLv != null -> inplaceModification_byte_litval_to_memory(name, operator, valueLv.toInt()) - ident != null -> inplaceModification_byte_variable_to_memory(name, operator, ident) + valueLv != null -> inplaceModification_byte_litval_to_memory(pointer, operator, valueLv.toInt()) + ident != null -> inplaceModification_byte_variable_to_memory(pointer, operator, ident) // TODO more specialized code for types such as memory read etc. value is TypecastExpression -> { if (tryRemoveRedundantCast(value, target, operator)) return - inplaceModification_byte_value_to_memory(name, operator, value) + inplaceModification_byte_value_to_memory(pointer, operator, value) } - else -> inplaceModification_byte_value_to_memory(name, operator, value) + else -> inplaceModification_byte_value_to_memory(pointer, operator, value) } } else -> { @@ -362,18 +362,26 @@ 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 + private fun inplaceModification_byte_value_to_memory(pointervar: IdentifierReference, operator: String, value: Expression) { + println("warning: slow stack evaluation used (3): @(${pointervar.nameInSource.last()}) $operator= ${value::class.simpleName} at ${value.position}") // TODO asmgen.translateExpression(value) when (operator) { // note: ** (power) operator requires floats. "+" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" clc | adc $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" clc | adc $ESTACK_LO_PLUS1_HEX,x") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" sec | sbc $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" sec | sbc $ESTACK_LO_PLUS1_HEX,x") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") @@ -386,33 +394,53 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "<<" -> TODO("ubyte asl") ">>" -> TODO("ubyte lsr") "&" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" and $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" and $ESTACK_LO_PLUS1_HEX,x") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" xor $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" xor $ESTACK_LO_PLUS1_HEX,x") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" ora $ESTACK_LO_PLUS1_HEX,x | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" ora $ESTACK_LO_PLUS1_HEX,x") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") } asmgen.out(" inx") } - private fun inplaceModification_byte_variable_to_memory(pointername: String, operator: String, ident: IdentifierReference) { - val otherName = asmgen.asmIdentifierName(ident) + private fun inplaceModification_byte_variable_to_memory(pointervar: IdentifierReference, operator: String, value: IdentifierReference) { + val otherName = asmgen.asmIdentifierName(value) when (operator) { // note: ** (power) operator requires floats. "+" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" clc | adc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" clc | adc $otherName") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" sec | sbc $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" sec | sbc $otherName") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "/" -> TODO("div")// asmgen.out(if(types==DataType.UBYTE) " jsr prog8_lib.idiv_ub" else " jsr prog8_lib.idiv_b") @@ -425,31 +453,51 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, "<<" -> TODO("ubyte asl") ">>" -> TODO("ubyte lsr") "&" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" and $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" and $otherName") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" xor $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" xor $otherName") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" ora $otherName | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" ora $otherName") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") } } - private fun inplaceModification_byte_litval_to_memory(pointername: String, operator: String, value: Int) { + private fun inplaceModification_byte_litval_to_memory(pointervar: IdentifierReference, operator: String, value: Int) { when (operator) { // note: ** (power) operator requires floats. "+" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" clc | adc #$value | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" clc | adc #$value") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "-" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" sec | sbc #$value | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" sec | sbc #$value") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "*" -> TODO("mul")// asmgen.out(" jsr prog8_lib.mul_byte") // the optimized routines should have been checked earlier "/" -> { @@ -468,29 +516,47 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } "<<" -> { if (value > 0) { - asmgen.loadByteFromPointerIntoA(pointername) + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) repeat(value) { asmgen.out(" asl a") } - asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } } ">>" -> { if (value > 0) { - asmgen.loadByteFromPointerIntoA(pointername) + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) repeat(value) { asmgen.out(" lsr a") } - asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } } "&" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" and #$value | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" and #$value") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "^" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" xor #$value | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" xor #$value") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } "|" -> { - asmgen.loadByteFromPointerIntoA(pointername) - asmgen.out(" ora #$value | sta (${C64Zeropage.SCRATCH_W1}),y") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(pointervar) + asmgen.out(" ora #$value") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } else -> throw AssemblyError("invalid operator for in-place modification $operator") } @@ -1047,13 +1113,15 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sta $addr""") } is IdentifierReference -> { - val name = asmgen.asmIdentifierName(mem.addressExpression as IdentifierReference) - asmgen.loadByteFromPointerIntoA(name) + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(mem.addressExpression as IdentifierReference) asmgen.out(""" beq + lda #1 -+ eor #1 - sta (${C64Zeropage.SCRATCH_W1}),y""") ++ eor #1""") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } else -> { println("warning: slow stack evaluation used (6): ${mem.addressExpression::class.simpleName} at ${mem.addressExpression.position}") // TODO @@ -1119,11 +1187,12 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, sta $addr""") } is IdentifierReference -> { - val name = asmgen.asmIdentifierName(memory.addressExpression as IdentifierReference) - asmgen.loadByteFromPointerIntoA(name) - asmgen.out(""" - eor #255 - sta (${C64Zeropage.SCRATCH_W1}),y""") + val (ptrOnZp, sourceName) = asmgen.loadByteFromPointerIntoA2(memory.addressExpression as IdentifierReference) + asmgen.out(" eor #255") + if(ptrOnZp) + asmgen.out(" sta ($sourceName),y") + else + asmgen.out(" sta (${C64Zeropage.SCRATCH_W1}),y") } else -> { println("warning: slow stack evaluation used (7): ${memory.addressExpression::class.simpleName} at ${memory.addressExpression.position}") // TODO diff --git a/examples/test.p8 b/examples/test.p8 index 61c8a6e21..78b291f53 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,60 +1,13 @@ %import c64utils +%zeropage basicsafe main { - 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() { - 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) + ubyte bb = 1 + uword addr=$d020 + @(addr) = bb + bb = @(addr) } }