From f962948ef83aa4c8aeb7e42d8f8f21cfcbe36f7e Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Tue, 19 Oct 2021 10:10:47 +0200 Subject: [PATCH] Upgraded ANTLR. Improved clobber handling in inline kickasm. --- .../libraries/Maven__org_antlr_antlr4_4_9.xml | 13 - .../Maven__org_antlr_antlr4_4_9_2.xml | 13 + ...Maven__org_antlr_antlr4_runtime_4_9_2.xml} | 8 +- kickc.iml | 4 +- pom.xml | 4 +- .../cache/fragment-cache-csg65ce02.asm | 2 +- .../cache/fragment-cache-mega45gs02.asm | 163 ++++------ .../fragment/cache/fragment-cache-mos6502.asm | 2 +- .../cache/fragment-cache-mos6502x.asm | 2 +- .../cache/fragment-cache-rom6502x.asm | 2 +- .../cache/fragment-cache-wdc65c02.asm | 2 +- .../camelot64/kickc/asm/AsmInlineKickAsm.java | 19 +- .../dk/camelot64/kickc/asm/AsmProgram.java | 4 +- .../asm/AsmProgramStaticRegisterValues.java | 64 ++-- .../kickc/passes/Pass4CodeGeneration.java | 6 +- .../kickc/test/TestProgramsFast.java | 5 + src/test/kc/inline-kasm-clobbermem.c | 16 + src/test/ref/examples/mega65/banked-music.asm | 4 +- src/test/ref/examples/mega65/banked-music.log | 8 +- src/test/ref/examples/mega65/dma-test3.asm | 4 +- src/test/ref/examples/mega65/dma-test3.log | 8 +- src/test/ref/inline-kasm-clobbermem.asm | 38 +++ src/test/ref/inline-kasm-clobbermem.cfg | 21 ++ src/test/ref/inline-kasm-clobbermem.log | 288 ++++++++++++++++++ src/test/ref/inline-kasm-clobbermem.sym | 9 + 25 files changed, 533 insertions(+), 176 deletions(-) delete mode 100644 .idea/libraries/Maven__org_antlr_antlr4_4_9.xml create mode 100644 .idea/libraries/Maven__org_antlr_antlr4_4_9_2.xml rename .idea/libraries/{Maven__org_antlr_antlr4_runtime_4_9.xml => Maven__org_antlr_antlr4_runtime_4_9_2.xml} (63%) create mode 100644 src/test/kc/inline-kasm-clobbermem.c create mode 100644 src/test/ref/inline-kasm-clobbermem.asm create mode 100644 src/test/ref/inline-kasm-clobbermem.cfg create mode 100644 src/test/ref/inline-kasm-clobbermem.log create mode 100644 src/test/ref/inline-kasm-clobbermem.sym diff --git a/.idea/libraries/Maven__org_antlr_antlr4_4_9.xml b/.idea/libraries/Maven__org_antlr_antlr4_4_9.xml deleted file mode 100644 index eeb625c0c..000000000 --- a/.idea/libraries/Maven__org_antlr_antlr4_4_9.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/libraries/Maven__org_antlr_antlr4_4_9_2.xml b/.idea/libraries/Maven__org_antlr_antlr4_4_9_2.xml new file mode 100644 index 000000000..30f12c7ac --- /dev/null +++ b/.idea/libraries/Maven__org_antlr_antlr4_4_9_2.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/libraries/Maven__org_antlr_antlr4_runtime_4_9.xml b/.idea/libraries/Maven__org_antlr_antlr4_runtime_4_9_2.xml similarity index 63% rename from .idea/libraries/Maven__org_antlr_antlr4_runtime_4_9.xml rename to .idea/libraries/Maven__org_antlr_antlr4_runtime_4_9_2.xml index 108bdc212..1aa359ac2 100644 --- a/.idea/libraries/Maven__org_antlr_antlr4_runtime_4_9.xml +++ b/.idea/libraries/Maven__org_antlr_antlr4_runtime_4_9_2.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/kickc.iml b/kickc.iml index 2ef040910..e9abf2081 100644 --- a/kickc.iml +++ b/kickc.iml @@ -11,12 +11,12 @@ - + - + diff --git a/pom.xml b/pom.xml index 2508a43aa..8c633b857 100644 --- a/pom.xml +++ b/pom.xml @@ -27,13 +27,13 @@ org.antlr antlr4 - 4.9 + 4.9.2 provided org.antlr antlr4-runtime - 4.9 + 4.9.2 org.junit.jupiter diff --git a/src/main/fragment/cache/fragment-cache-csg65ce02.asm b/src/main/fragment/cache/fragment-cache-csg65ce02.asm index 8d0e4bdf2..3a5319161 100644 --- a/src/main/fragment/cache/fragment-cache-csg65ce02.asm +++ b/src/main/fragment/cache/fragment-cache-csg65ce02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT vbuzz=vbuc1 ldz #{c1} //FRAGMENT vbuzz_lt_vbuc1_then_la1 diff --git a/src/main/fragment/cache/fragment-cache-mega45gs02.asm b/src/main/fragment/cache/fragment-cache-mega45gs02.asm index 73dc2b57b..0228252a7 100644 --- a/src/main/fragment/cache/fragment-cache-mega45gs02.asm +++ b/src/main/fragment/cache/fragment-cache-mega45gs02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT _deref_pbuc1=vbuc2 ldz #{c2} stz {c1} @@ -1652,110 +1652,11 @@ tza sta {c1} lda #0 sta {c1}+1 -//FRAGMENT _deref_pbuc1=_inc__deref_pbuc1 -inc {c1} //FRAGMENT vwuz1=vbuc1 lda #<{c1} sta {z1} lda #>{c1} sta {z1}+1 -//FRAGMENT _deref_pbuc1_eq_vbuz1_then_la1 -lda {c1} -cmp {z1} -beq {la1} -//FRAGMENT _deref_pbuc1=_dec__deref_pbuc1 -dec {c1} -//FRAGMENT pbuc1_derefidx_vbuz1=_inc_pbuc1_derefidx_vbuz1 -ldx {z1} -inc {c1},x -//FRAGMENT vbuz1=_byte0_vwuz2 -lda {z2} -sta {z1} -//FRAGMENT vbuz1=_byte1_vwuz2 -lda {z2}+1 -sta {z1} -//FRAGMENT vbuz1=vbuz2_bor_vbuz3 -lda {z2} -ora {z3} -sta {z1} -//FRAGMENT _deref_pbuc1_eq_vbuaa_then_la1 -cmp {c1} -beq {la1} -//FRAGMENT pbuc1_derefidx_vbuaa=_inc_pbuc1_derefidx_vbuaa -tax -inc {c1},x -//FRAGMENT pbuc1_derefidx_vbuxx=_inc_pbuc1_derefidx_vbuxx -inc {c1},x -//FRAGMENT vbuaa=_byte1_vwuz1 -lda {z1}+1 -//FRAGMENT vbuxx=_byte1_vwuz1 -ldx {z1}+1 -//FRAGMENT vbuz1=vbuxx_bor_vbuz2 -txa -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuyy_bor_vbuz2 -tya -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuzz_bor_vbuz2 -tza -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuz2_bor_vbuaa -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuxx_bor_vbuaa -stx $ff -ora $ff -sta {z1} -//FRAGMENT vbuz1=vbuyy_bor_vbuaa -sty $ff -ora $ff -sta {z1} -//FRAGMENT vbuz1=vbuzz_bor_vbuaa -tay -tza -sty $ff -ora $ff -sta {z1} -//FRAGMENT vbuz1=vbuz2_bor_vbuxx -txa -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuxx_bor_vbuxx -stx {z1} -//FRAGMENT vbuyy=_byte1_vwuz1 -ldy {z1}+1 -//FRAGMENT vbuzz=_byte1_vwuz1 -lda {z1}+1 -taz -//FRAGMENT vbuz1=vbuz2_bor_vbuyy -tya -ora {z2} -sta {z1} -//FRAGMENT vbuz1=vbuz2_bor_vbuzz -tza -ora {z2} -sta {z1} -//FRAGMENT pbuc1_derefidx_vbuyy=_inc_pbuc1_derefidx_vbuyy -lda {c1},y -inc -sta {c1},y -//FRAGMENT pbuc1_derefidx_vbuzz=_inc_pbuc1_derefidx_vbuzz -tza -tax -inc {c1},x -//FRAGMENT _deref_pbuc1_eq_vbuxx_then_la1 -cpx {c1} -beq {la1} -//FRAGMENT _deref_pbuc1_eq_vbuyy_then_la1 -tya -cmp {c1} -beq {la1} -//FRAGMENT _deref_pbuc1_eq_vbuzz_then_la1 -cpz {c1} -beq {la1} //FRAGMENT vduz1=vduc1 lda #<{c1} sta {z1} @@ -1809,6 +1710,16 @@ lda {z2} sta {z1} lda {z2}+1 sta {z1}+1 +//FRAGMENT vbuz1=_byte0_vwuz2 +lda {z2} +sta {z1} +//FRAGMENT vbuz1=_byte1_vwuz2 +lda {z2}+1 +sta {z1} +//FRAGMENT vbuz1=vbuz2_bor_vbuz3 +lda {z2} +ora {z3} +sta {z1} //FRAGMENT vduz1=vduz2_ror_4 lda {z2}+3 lsr @@ -2396,10 +2307,62 @@ dey bne !- !e: taz +//FRAGMENT vbuaa=_byte1_vwuz1 +lda {z1}+1 +//FRAGMENT vbuxx=_byte1_vwuz1 +ldx {z1}+1 +//FRAGMENT vbuz1=vbuxx_bor_vbuz2 +txa +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuyy_bor_vbuz2 +tya +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuzz_bor_vbuz2 +tza +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuz2_bor_vbuaa +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuxx_bor_vbuaa +stx $ff +ora $ff +sta {z1} +//FRAGMENT vbuz1=vbuyy_bor_vbuaa +sty $ff +ora $ff +sta {z1} +//FRAGMENT vbuz1=vbuzz_bor_vbuaa +tay +tza +sty $ff +ora $ff +sta {z1} +//FRAGMENT vbuz1=vbuz2_bor_vbuxx +txa +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuxx_bor_vbuxx +stx {z1} //FRAGMENT vbuaa=_byte1_vduz1 lda {z1}+1 //FRAGMENT vbuxx=_byte1_vduz1 ldx {z1}+1 +//FRAGMENT vbuz1=vbuz2_bor_vbuyy +tya +ora {z2} +sta {z1} +//FRAGMENT vbuz1=vbuz2_bor_vbuzz +tza +ora {z2} +sta {z1} +//FRAGMENT vbuyy=_byte1_vwuz1 +ldy {z1}+1 +//FRAGMENT vbuzz=_byte1_vwuz1 +lda {z1}+1 +taz //FRAGMENT vbuyy=_byte1_vduz1 ldy {z1}+1 //FRAGMENT vbuzz=_byte1_vduz1 diff --git a/src/main/fragment/cache/fragment-cache-mos6502.asm b/src/main/fragment/cache/fragment-cache-mos6502.asm index 771fc0be9..560783e65 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} diff --git a/src/main/fragment/cache/fragment-cache-mos6502x.asm b/src/main/fragment/cache/fragment-cache-mos6502x.asm index 54e1c35b3..e8acc91b4 100644 --- a/src/main/fragment/cache/fragment-cache-mos6502x.asm +++ b/src/main/fragment/cache/fragment-cache-mos6502x.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT vbuz1=vbuc1 lda #{c1} sta {z1} diff --git a/src/main/fragment/cache/fragment-cache-rom6502x.asm b/src/main/fragment/cache/fragment-cache-rom6502x.asm index 75b82a5b4..b8ded4b00 100644 --- a/src/main/fragment/cache/fragment-cache-rom6502x.asm +++ b/src/main/fragment/cache/fragment-cache-rom6502x.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT _deref_pbuc1=_inc__deref_pbuc1 inc {c1} //FRAGMENT isr_hardware_all_entry diff --git a/src/main/fragment/cache/fragment-cache-wdc65c02.asm b/src/main/fragment/cache/fragment-cache-wdc65c02.asm index be64f753a..3088d0cee 100644 --- a/src/main/fragment/cache/fragment-cache-wdc65c02.asm +++ b/src/main/fragment/cache/fragment-cache-wdc65c02.asm @@ -1,4 +1,4 @@ -//KICKC FRAGMENT CACHE db0ab6caa db0ab911c +//KICKC FRAGMENT CACHE d8c3d291d d8c3d4dd4 //FRAGMENT vbuz1=_deref_pbuc1 lda {c1} sta {z1} diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmInlineKickAsm.java b/src/main/java/dk/camelot64/kickc/asm/AsmInlineKickAsm.java index 7791f3341..3542ec48d 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmInlineKickAsm.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmInlineKickAsm.java @@ -1,5 +1,7 @@ package dk.camelot64.kickc.asm; +import dk.camelot64.cpufamily6502.CpuClobber; + /** * Inlined KickAssembler code. * If no cycles/byte size is specified it defaults to 256/256. @@ -12,7 +14,9 @@ public class AsmInlineKickAsm extends AsmLine { private double cycles; - public AsmInlineKickAsm(String kickAsmCode, Long bytes, Long cycles) { + private CpuClobber clobber; + + public AsmInlineKickAsm(String kickAsmCode, Long bytes, Long cycles, CpuClobber clobber) { this.kickAsmCode = kickAsmCode; if(bytes != null) { this.bytes = bytes.intValue(); @@ -24,16 +28,21 @@ public class AsmInlineKickAsm extends AsmLine { } else { this.cycles = 256; } + if(clobber==null) { + this.clobber = CpuClobber.CLOBBER_ALL; + } else { + this.clobber = clobber; + } + } + + public CpuClobber getClobber() { + return clobber; } public String getKickAsmCode() { return kickAsmCode; } - public void setKickAsmCode(String kickAsmCode) { - this.kickAsmCode = kickAsmCode; - } - /** * Get the number of source lines in the inline assembler code (for line indexing) * diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java index 605edd30e..e81b0f42c 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgram.java @@ -213,8 +213,8 @@ public class AsmProgram { * * @param kickAsmCode The kickassembler code */ - public void addInlinedKickAsm(String kickAsmCode, Long bytes, Long cycles) { - addLine(new AsmInlineKickAsm(kickAsmCode, bytes, cycles)); + public void addInlinedKickAsm(String kickAsmCode, Long bytes, Long cycles, CpuClobber cpuClobber) { + addLine(new AsmInlineKickAsm(kickAsmCode, bytes, cycles, cpuClobber)); } /** diff --git a/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java b/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java index adebf0c61..a774dc64a 100644 --- a/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java +++ b/src/main/java/dk/camelot64/kickc/asm/AsmProgramStaticRegisterValues.java @@ -83,6 +83,10 @@ public class AsmProgramStaticRegisterValues { current = new AsmRegisterValues(); } else if(line instanceof AsmScopeEnd) { current = new AsmRegisterValues(); + } else if(line instanceof AsmInlineKickAsm) { + current = new AsmRegisterValues(current); + final CpuClobber cpuClobber = ((AsmInlineKickAsm) line).getClobber(); + handleClobber(current, cpuClobber); } else if(line instanceof AsmInstruction) { AsmInstruction instruction = (AsmInstruction) line; values.put(instruction, current); @@ -92,34 +96,7 @@ public class AsmProgramStaticRegisterValues { if(instruction.getCpuOpcode().getMnemonic().equals("jsr")) { cpuClobber = CpuClobber.CLOBBER_ALL; } - if(cpuClobber.isRegisterA()) { - current.setA(null); - current.setaMem(null); - } - if(cpuClobber.isRegisterX()) { - current.setX(null); - current.setxMem(null); - } - if(cpuClobber.isRegisterY()) { - current.setY(null); - current.setyMem(null); - } - if(cpuClobber.isRegisterZ()) { - current.setZ(null); - current.setzMem(null); - } - if(cpuClobber.isFlagC()) { - current.setFlagC(null); - } - if(cpuClobber.isFlagN()) { - current.setFlagN(null); - } - if(cpuClobber.isFlagV()) { - current.setFlagV(null); - } - if(cpuClobber.isFlagZ()) { - current.setFlagZ(null); - } + handleClobber(current, cpuClobber); String mnemnonic = cpuOpcode.getMnemonic(); CpuAddressingMode addressingMode = cpuOpcode.getAddressingMode(); if((mnemnonic.equals("inc") || mnemnonic.equals("dec") || mnemnonic.equals("ror") || mnemnonic.equals("rol") || mnemnonic.equals("lsr") || mnemnonic.equals("asl")) && (addressingMode.equals(CpuAddressingMode.ZP) || addressingMode.equals(CpuAddressingMode.ABS))) { @@ -245,6 +222,37 @@ public class AsmProgramStaticRegisterValues { return current; } + private void handleClobber(AsmRegisterValues current, CpuClobber cpuClobber) { + if(cpuClobber.isRegisterA()) { + current.setA(null); + current.setaMem(null); + } + if(cpuClobber.isRegisterX()) { + current.setX(null); + current.setxMem(null); + } + if(cpuClobber.isRegisterY()) { + current.setY(null); + current.setyMem(null); + } + if(cpuClobber.isRegisterZ()) { + current.setZ(null); + current.setzMem(null); + } + if(cpuClobber.isFlagC()) { + current.setFlagC(null); + } + if(cpuClobber.isFlagN()) { + current.setFlagN(null); + } + if(cpuClobber.isFlagV()) { + current.setFlagV(null); + } + if(cpuClobber.isFlagZ()) { + current.setFlagZ(null); + } + } + /** * Known values of registers/flags at an instruction. null where value is unknown. */ diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index d3d54a938..9a774b55d 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -98,7 +98,7 @@ public class Pass4CodeGeneration { Number startAddress = program.getTargetPlatform().getStartAddress(); if(startAddress != null) linkScriptBody = linkScriptBody.replace("%P", AsmFormat.getAsmNumber(startAddress)); - asm.addLine(new AsmInlineKickAsm(linkScriptBody, 0L, 0L)); + asm.addLine(new AsmInlineKickAsm(linkScriptBody, 0L, 0L, CpuClobber.CLOBBER_ALL)); // Generate global ZP labels asm.startChunk(currentScope, null, "Global Constants & labels"); @@ -815,7 +815,7 @@ public class Pass4CodeGeneration { if(statementSource != null) stmtFormat = statementSource.format(); program.getLog().append("Warning! Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature() + "\n" + stmtFormat); - asm.addLine(new AsmInlineKickAsm(".assert \"Missing ASM fragment " + e.getFragmentSignature() + "\", 0, 1", 0L, 0L)); + asm.addLine(new AsmInlineKickAsm(".assert \"Missing ASM fragment " + e.getFragmentSignature() + "\", 0, 1", 0L, 0L, CpuClobber.CLOBBER_NONE)); } else { throw new CompileError("Unknown fragment for statement " + statement.toString(program, false) + "\nMissing ASM fragment " + e.getFragmentSignature(), statementSource); } @@ -1061,7 +1061,7 @@ public class Pass4CodeGeneration { ConstantLiteral kasmCyclesLiteral = kasmCycles.calculateLiteral(getScope()); asmCycles = ((ConstantInteger) kasmCyclesLiteral).getInteger(); } - asm.addInlinedKickAsm(statementKasm.getKickAsmCode(), asmBytes, asmCycles); + asm.addInlinedKickAsm(statementKasm.getKickAsmCode(), asmBytes, asmCycles, statementKasm.getDeclaredClobber()); } /** diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index c431ccfcb..8ba0c298d 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -3598,6 +3598,11 @@ public class TestProgramsFast extends TestPrograms { compileAndCompare("inline-kasm-clobber.c"); } + @Test + public void testInlineKickAsmClobberMem() throws IOException { + compileAndCompare("inline-kasm-clobbermem.c"); + } + @Test public void testInlineAsmClobberNone() throws IOException { diff --git a/src/test/kc/inline-kasm-clobbermem.c b/src/test/kc/inline-kasm-clobbermem.c new file mode 100644 index 000000000..9b6bb12be --- /dev/null +++ b/src/test/kc/inline-kasm-clobbermem.c @@ -0,0 +1,16 @@ +// Demonstrate problem with inline kasm clobbering memory +// And the ASM peephole optimizer not realizing this + +void main() { + __ma char tile = 0; + char * const SCREEN = (char*)0x0400; + for(char i=0;i<10;i++) { + kickasm(uses tile, clobbers "A") {{ + lda #4 + sta tile + lda #2 + sta $02 + }} + SCREEN[i] = tile; + } +} \ No newline at end of file diff --git a/src/test/ref/examples/mega65/banked-music.asm b/src/test/ref/examples/mega65/banked-music.asm index 40c1e78fc..2c4b85cb5 100644 --- a/src/test/ref/examples/mega65/banked-music.asm +++ b/src/test/ref/examples/mega65/banked-music.asm @@ -332,9 +332,9 @@ memoryRemap: { } // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) diff --git a/src/test/ref/examples/mega65/banked-music.log b/src/test/ref/examples/mega65/banked-music.log index 05a1fb839..d79e4d676 100644 --- a/src/test/ref/examples/mega65/banked-music.log +++ b/src/test/ref/examples/mega65/banked-music.log @@ -1484,9 +1484,9 @@ memoryRemap: { // memcpy_dma4 // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) @@ -2185,9 +2185,9 @@ memoryRemap: { // memcpy_dma4 // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) diff --git a/src/test/ref/examples/mega65/dma-test3.asm b/src/test/ref/examples/mega65/dma-test3.asm index c4e597db9..e6d4e5bfb 100644 --- a/src/test/ref/examples/mega65/dma-test3.asm +++ b/src/test/ref/examples/mega65/dma-test3.asm @@ -100,9 +100,9 @@ memoryRemap: { } // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) diff --git a/src/test/ref/examples/mega65/dma-test3.log b/src/test/ref/examples/mega65/dma-test3.log index c3e3d7795..f4fb1aa35 100644 --- a/src/test/ref/examples/mega65/dma-test3.log +++ b/src/test/ref/examples/mega65/dma-test3.log @@ -627,9 +627,9 @@ memoryRemap: { // memcpy_dma4 // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) @@ -890,9 +890,9 @@ memoryRemap: { // memcpy_dma4 // Copy a memory block anywhere in first 4MB memory space using MEGA65 DMagic DMA // Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination. -// - dest_bank The 64KB bank for the destination (0-63) +// - dest_bank The 64KB bank for the destination (0-127) // - dest The destination address (within the MB and bank) -// - src_bank The 64KB bank for the source (0-63) +// - src_bank The 64KB bank for the source (0-127) // - src The source address (within the MB and bank) // - num The number of bytes to copy // void memcpy_dma4(char dest_bank, void *dest, char src_bank, void *src, unsigned int num) diff --git a/src/test/ref/inline-kasm-clobbermem.asm b/src/test/ref/inline-kasm-clobbermem.asm new file mode 100644 index 000000000..8df02dbe0 --- /dev/null +++ b/src/test/ref/inline-kasm-clobbermem.asm @@ -0,0 +1,38 @@ +// Demonstrate problem with inline kasm clobbering memory +// And the ASM peephole optimizer not realizing this + // Commodore 64 PRG executable file +.file [name="inline-kasm-clobbermem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) +.segment Code +main: { + .label SCREEN = $400 + .label tile = 2 + // __ma char tile = 0 + lda #0 + sta.z tile + tax + __b1: + // for(char i=0;i<10;i++) + cpx #$a + bcc __b2 + // } + rts + __b2: + // kickasm + lda #4 + sta tile + lda #2 + sta $02 + + // SCREEN[i] = tile + lda.z tile + sta SCREEN,x + // for(char i=0;i<10;i++) + inx + jmp __b1 +} diff --git a/src/test/ref/inline-kasm-clobbermem.cfg b/src/test/ref/inline-kasm-clobbermem.cfg new file mode 100644 index 000000000..a9deb0a7a --- /dev/null +++ b/src/test/ref/inline-kasm-clobbermem.cfg @@ -0,0 +1,21 @@ + +void main() +main: scope:[main] from + [0] main::tile = 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + [1] main::i#2 = phi( main/0, main::@2/main::i#1 ) + [2] if(main::i#2<$a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 + kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} + [5] main::SCREEN[main::i#2] = main::tile + [6] main::i#1 = ++ main::i#2 + to:main::@1 diff --git a/src/test/ref/inline-kasm-clobbermem.log b/src/test/ref/inline-kasm-clobbermem.log new file mode 100644 index 000000000..aa901dc8f --- /dev/null +++ b/src/test/ref/inline-kasm-clobbermem.log @@ -0,0 +1,288 @@ +Setting inferred volatile on symbol affected by address-of: main::tile in kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + main::tile = 0 + main::i#0 = 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + main::i#2 = phi( main/main::i#0, main::@2/main::i#1 ) + main::$0 = main::i#2 < $a + if(main::$0) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + main::i#3 = phi( main::@1/main::i#2 ) + kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} + main::SCREEN[main::i#3] = main::tile + main::i#1 = ++ main::i#3 + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +void __start() +void main() +bool main::$0 +__constant char * const main::SCREEN = (char *)$400 +char main::i +char main::i#0 +char main::i#1 +char main::i#2 +char main::i#3 +__loadstore volatile char main::tile + +Adding number conversion cast (unumber) $a in main::$0 = main::i#2 < $a +Successful SSA optimization PassNAddNumberTypeConversions +Simplifying constant pointer cast (char *) 1024 +Simplifying constant integer cast $a +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (char) $a +Successful SSA optimization PassNFinalizeNumberTypeConversions +Alias main::i#2 = main::i#3 +Successful SSA optimization Pass2AliasElimination +Simple Condition main::$0 [4] if(main::i#2<$a) goto main::@2 +Successful SSA optimization Pass2ConditionalJumpSimplification +Constant main::i#0 = 0 +Successful SSA optimization Pass2ConstantIdentification +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Inlining constant with var siblings main::i#0 +Constant inlined main::i#0 = 0 +Successful SSA optimization Pass2ConstantInlining +CALL GRAPH + +Created 1 initial phi equivalence classes +Coalesced [7] main::i#4 = main::i#1 +Coalesced down to 1 phi equivalence classes + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] main::tile = 0 + to:main::@1 +main::@1: scope:[main] from main main::@2 + [1] main::i#2 = phi( main/0, main::@2/main::i#1 ) + [2] if(main::i#2<$a) goto main::@2 + to:main::@return +main::@return: scope:[main] from main::@1 + [3] return + to:@return +main::@2: scope:[main] from main::@1 + kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} + [5] main::SCREEN[main::i#2] = main::tile + [6] main::i#1 = ++ main::i#2 + to:main::@1 + + +VARIABLE REGISTER WEIGHTS +void main() +char main::i +char main::i#1 // 22.0 +char main::i#2 // 11.0 +__loadstore volatile char main::tile // 2.1666666666666665 + +Initial phi equivalence classes +[ main::i#2 main::i#1 ] +Added variable main::tile to live range equivalence class [ main::tile ] +Complete equivalence classes +[ main::i#2 main::i#1 ] +[ main::tile ] +Allocated zp[1]:2 [ main::i#2 main::i#1 ] +Allocated zp[1]:3 [ main::tile ] +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] main::tile = 0 [ main::tile ] ( [ main::tile ] { } ) always clobbers reg byte a +Statement kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} always clobbers reg byte a +Removing always clobbered register reg byte a as potential for zp[1]:2 [ main::i#2 main::i#1 ] +Statement [5] main::SCREEN[main::i#2] = main::tile [ main::tile main::i#2 ] ( [ main::tile main::i#2 ] { } ) always clobbers reg byte a +Statement [0] main::tile = 0 [ main::tile ] ( [ main::tile ] { } ) always clobbers reg byte a +Statement kickasm( uses main::tile) {{ lda #4 + sta tile + lda #2 + sta $02 + }} always clobbers reg byte a +Statement [5] main::SCREEN[main::i#2] = main::tile [ main::tile main::i#2 ] ( [ main::tile main::i#2 ] { } ) always clobbers reg byte a +Potential registers zp[1]:2 [ main::i#2 main::i#1 ] : zp[1]:2 , reg byte x , reg byte y , +Potential registers zp[1]:3 [ main::tile ] : zp[1]:3 , + +REGISTER UPLIFT SCOPES +Uplift Scope [main] 33: zp[1]:2 [ main::i#2 main::i#1 ] 2.17: zp[1]:3 [ main::tile ] +Uplift Scope [] + +Uplifting [main] best 2826 combination reg byte x [ main::i#2 main::i#1 ] zp[1]:3 [ main::tile ] +Uplifting [] best 2826 combination +Attempting to uplift remaining variables inzp[1]:3 [ main::tile ] +Uplifting [main] best 2826 combination zp[1]:3 [ main::tile ] +Allocated (was zp[1]:3) zp[1]:2 [ main::tile ] + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Demonstrate problem with inline kasm clobbering memory +// And the ASM peephole optimizer not realizing this + // Upstart + // Commodore 64 PRG executable file +.file [name="inline-kasm-clobbermem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels +.segment Code + // main +main: { + .label SCREEN = $400 + .label tile = 2 + // [0] main::tile = 0 -- vbuz1=vbuc1 + lda #0 + sta.z tile + // [1] phi from main to main::@1 [phi:main->main::@1] + __b1_from_main: + // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + ldx #0 + jmp __b1 + // main::@1 + __b1: + // [2] if(main::i#2<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$a + bcc __b2 + jmp __breturn + // main::@return + __breturn: + // [3] return + rts + // main::@2 + __b2: + // kickasm( uses main::tile) {{ lda #4 sta tile lda #2 sta $02 }} + lda #4 + sta tile + lda #2 + sta $02 + + // [5] main::SCREEN[main::i#2] = main::tile -- pbuc1_derefidx_vbuxx=vbuz1 + lda.z tile + sta SCREEN,x + // [6] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx + inx + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + __b1_from___b2: + // [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __b1 +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction __b1_from_main: +Removing instruction __breturn: +Removing instruction __b1_from___b2: +Succesful ASM optimization Pass5UnusedLabelElimination +Replacing instruction ldx #0 with TAX + +FINAL SYMBOL TABLE +void main() +__constant char * const main::SCREEN = (char *) 1024 +char main::i +char main::i#1 // reg byte x 22.0 +char main::i#2 // reg byte x 11.0 +__loadstore volatile char main::tile // zp[1]:2 2.1666666666666665 + +reg byte x [ main::i#2 main::i#1 ] +zp[1]:2 [ main::tile ] + + +FINAL ASSEMBLER +Score: 2766 + + // File Comments +// Demonstrate problem with inline kasm clobbering memory +// And the ASM peephole optimizer not realizing this + // Upstart + // Commodore 64 PRG executable file +.file [name="inline-kasm-clobbermem.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels +.segment Code + // main +main: { + .label SCREEN = $400 + .label tile = 2 + // __ma char tile = 0 + // [0] main::tile = 0 -- vbuz1=vbuc1 + lda #0 + sta.z tile + // [1] phi from main to main::@1 [phi:main->main::@1] + // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuxx=vbuc1 + tax + // main::@1 + __b1: + // for(char i=0;i<10;i++) + // [2] if(main::i#2<$a) goto main::@2 -- vbuxx_lt_vbuc1_then_la1 + cpx #$a + bcc __b2 + // main::@return + // } + // [3] return + rts + // main::@2 + __b2: + // kickasm + // kickasm( uses main::tile) {{ lda #4 sta tile lda #2 sta $02 }} + lda #4 + sta tile + lda #2 + sta $02 + + // SCREEN[i] = tile + // [5] main::SCREEN[main::i#2] = main::tile -- pbuc1_derefidx_vbuxx=vbuz1 + lda.z tile + sta SCREEN,x + // for(char i=0;i<10;i++) + // [6] main::i#1 = ++ main::i#2 -- vbuxx=_inc_vbuxx + inx + // [1] phi from main::@2 to main::@1 [phi:main::@2->main::@1] + // [1] phi main::i#2 = main::i#1 [phi:main::@2->main::@1#0] -- register_copy + jmp __b1 +} + // File Data + diff --git a/src/test/ref/inline-kasm-clobbermem.sym b/src/test/ref/inline-kasm-clobbermem.sym new file mode 100644 index 000000000..2cd1bfa03 --- /dev/null +++ b/src/test/ref/inline-kasm-clobbermem.sym @@ -0,0 +1,9 @@ +void main() +__constant char * const main::SCREEN = (char *) 1024 +char main::i +char main::i#1 // reg byte x 22.0 +char main::i#2 // reg byte x 11.0 +__loadstore volatile char main::tile // zp[1]:2 2.1666666666666665 + +reg byte x [ main::i#2 main::i#1 ] +zp[1]:2 [ main::tile ]