From 3dcef89a7408115899ad0b5c6b635059329e3510 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Fri, 15 Jan 2021 18:46:23 +0100 Subject: [PATCH] optimize (zp),y instructions for 65c02 to use (zp) --- .../compiler/target/c64/codegen/AsmGen.kt | 83 +++++++++++++------ .../target/c64/codegen/ExpressionsAsmGen.kt | 14 +++- .../codegen/assignment/AssignmentAsmGen.kt | 15 +++- docs/source/todo.rst | 1 - examples/cx16/assembler/assem.p8 | 17 ++-- examples/test.p8 | 41 +++++---- 6 files changed, 114 insertions(+), 57 deletions(-) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 4e6f38113..1006593da 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -526,19 +526,35 @@ internal class AsmGen(private val program: Program, val sourceName = asmVariableName(pointervar) val vardecl = pointervar.targetVarDecl(program.namespace)!! val scopedName = vardecl.makeScopedName(vardecl.name) - return if(scopedName in allocatedZeropageVariables) { - // pointervar is already in the zero page, no need to copy - out(" ldy #0 | lda ($sourceName),y") - Pair(true, sourceName) + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { + return if (scopedName in allocatedZeropageVariables) { + // pointervar is already in the zero page, no need to copy + out(" lda ($sourceName)") + Pair(true, sourceName) + } else { + out(""" + lda $sourceName + ldy $sourceName+1 + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + lda (P8ZP_SCRATCH_W1)""") + Pair(false, sourceName) + } } else { - out(""" - lda $sourceName - ldy $sourceName+1 - sta P8ZP_SCRATCH_W1 - sty P8ZP_SCRATCH_W1+1 - ldy #0 - lda (P8ZP_SCRATCH_W1),y""") - Pair(false, sourceName) + return if (scopedName in allocatedZeropageVariables) { + // pointervar is already in the zero page, no need to copy + out(" ldy #0 | lda ($sourceName),y") + Pair(true, sourceName) + } else { + out(""" + lda $sourceName + ldy $sourceName+1 + sta P8ZP_SCRATCH_W1 + sty P8ZP_SCRATCH_W1+1 + ldy #0 + lda (P8ZP_SCRATCH_W1),y""") + Pair(false, sourceName) + } } } @@ -546,20 +562,37 @@ internal class AsmGen(private val program: Program, val sourceName = asmVariableName(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") + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { + if (scopedName in allocatedZeropageVariables) { + // 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 { - 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""") + 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 P8ZP_SCRATCH_W2 + ldy $sourceName+1 + sty P8ZP_SCRATCH_W2+1 + ${if (ldaInstructionArg == null) "" else "lda $ldaInstructionArg"} + ldy #0 + sta (P8ZP_SCRATCH_W2),y""") + } } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index 598f1252f..21e970a81 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -1472,10 +1472,18 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge } else -> { asmgen.assignExpressionToVariable(expr.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - if(pushResultOnEstack) { - asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x") + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { + if (pushResultOnEstack) { + asmgen.out(" dex | lda (P8ZP_SCRATCH_W2) | sta P8ESTACK_LO+1,x") + } else { + asmgen.out(" lda (P8ZP_SCRATCH_W2)") + } } else { - asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") + if (pushResultOnEstack) { + asmgen.out(" dex | ldy #0 | lda (P8ZP_SCRATCH_W2),y | sta P8ESTACK_LO+1,x") + } else { + asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") + } } } } 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 ab8bff5c3..dbd6b9046 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -123,7 +123,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } else -> { assignExpressionToVariable(value.addressExpression, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, assign.target.scope) - asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) + asmgen.out(" lda (P8ZP_SCRATCH_W2)") + else + asmgen.out(" ldy #0 | lda (P8ZP_SCRATCH_W2),y") assignRegisterByte(assign.target, CpuRegister.A) } } @@ -1943,7 +1946,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen } else -> { assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) - asmgen.out(" ldy #0 | lda $ldaInstructionArg | sta (P8ZP_SCRATCH_W2),y") + 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") } } } @@ -1969,7 +1975,10 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen asmgen.saveRegisterStack(register, false) assignExpressionToVariable(addressExpr, asmgen.asmVariableName("P8ZP_SCRATCH_W2"), DataType.UWORD, null) asmgen.restoreRegisterStack(CpuRegister.A, false) - asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") + if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) + asmgen.out(" sta (P8ZP_SCRATCH_W2)") + else + asmgen.out(" ldy #0 | sta (P8ZP_SCRATCH_W2),y") } } } diff --git a/docs/source/todo.rst b/docs/source/todo.rst index ca7aac174..9bd4d0914 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -2,7 +2,6 @@ TODO ==== -- use (zp) addressing mode on 65c02 specific code rather than ldy#0 / lda (zp),y - optimize pointer access code @(pointer)? use a subroutine? macro? 65c02 vs 6502? - 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 compiler option to generate a symbol listing at the end diff --git a/examples/cx16/assembler/assem.p8 b/examples/cx16/assembler/assem.p8 index 5cc243c51..366069016 100644 --- a/examples/cx16/assembler/assem.p8 +++ b/examples/cx16/assembler/assem.p8 @@ -12,7 +12,7 @@ main { sub start() { - txt.print("\n65c02 file based assembler.\n\nfilename or enter for interactive: ") + txt.print("\nCommanderX16 65c02 file based assembler.\n\nfilename or enter for interactive: ") str filename = "?" * 20 if txt.input_chars(filename) @@ -639,11 +639,10 @@ instructions { phx sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - ldy #0 - lda (P8ZP_SCRATCH_W1),y + lda (P8ZP_SCRATCH_W1) and #$7f ; lowercase pha - iny + ldy #1 lda (P8ZP_SCRATCH_W1),y and #$7f ; lowercase pha @@ -686,10 +685,9 @@ instructions { ;lda #13 ;jsr c64.CHROUT - ldy #0 - lda (P8ZP_SCRATCH_W2),y + lda (P8ZP_SCRATCH_W2) beq _multi_addrmodes - iny + ldy #1 lda (P8ZP_SCRATCH_W2),y cmp cx16.r5 ; check single possible addr.mode bne _not_found @@ -707,12 +705,11 @@ _multi_addrmodes lda (P8ZP_SCRATCH_W2),y ; check opcode for addr.mode bne _valid ; opcode $00 usually means 'invalid' but for "brk" it is actually valid so check for "brk" - ldy #0 - lda (P8ZP_SCRATCH_W1),y + lda (P8ZP_SCRATCH_W1) and #$7f ; lowercase cmp #'b' bne _not_found - iny + ldy #1 lda (P8ZP_SCRATCH_W1),y and #$7f ; lowercase cmp #'r' diff --git a/examples/test.p8 b/examples/test.p8 index 624bcfcd9..00f1e59ad 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -7,27 +7,38 @@ main { sub start() { - str filename="?"*40 - txt.print("> ") - ubyte il = txt.input_chars(filename) - txt.print_ub(il) + str name = "abcdef" + + uword ptr = &name + ubyte cc + + cc = @(ptr) + txt.chrout(cc) txt.nl() - txt.print_ubhex(filename[0],1) - txt.print_ubhex(filename[1],1) - txt.print_ubhex(filename[2],1) + cc = @(ptr+1) + txt.chrout(cc) + txt.nl() + cc = @(ptr+2) + txt.chrout(cc) txt.nl() - txt.print(filename) txt.nl() - txt.print("> ") - il = txt.input_chars(filename) - txt.print_ub(il) + txt.chrout(@(ptr)) + txt.chrout(@(ptr+1)) + txt.chrout(@(ptr+2)) txt.nl() - txt.print_ubhex(filename[0],1) - txt.print_ubhex(filename[1],1) - txt.print_ubhex(filename[2],1) + + @(ptr) = '1' + @(ptr+1) = '2' + @(ptr+2) = '3' + txt.print(name) txt.nl() - txt.print(filename) + + cc=0 + @(ptr+cc) = 'a' + @(ptr+cc+1) = 'b' + @(ptr+cc+2) = 'c' + txt.print(name) txt.nl() }