diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java b/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java index 55e69f477..e563f5b59 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4InterruptClobberFix.java @@ -4,17 +4,17 @@ import dk.camelot64.kickc.asm.AsmClobber; import dk.camelot64.kickc.asm.AsmLine; import dk.camelot64.kickc.asm.AsmProgram; import dk.camelot64.kickc.asm.AsmSegment; +import dk.camelot64.kickc.model.CallGraph; import dk.camelot64.kickc.model.Program; -import dk.camelot64.kickc.model.Registers; import dk.camelot64.kickc.model.symbols.Procedure; +import dk.camelot64.kickc.model.values.LabelRef; +import dk.camelot64.kickc.model.values.ProcedureRef; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.ListIterator; -import static dk.camelot64.kickc.passes.Pass4AssertNoCpuClobber.getClobberRegisters; - /*** Ensure that all interrupt procedures with type {@link Procedure.InterruptType#HARDWARE_CLOBBER } only saves the necessary registers. */ public class Pass4InterruptClobberFix extends Pass2Base { @@ -30,13 +30,14 @@ public class Pass4InterruptClobberFix extends Pass2Base { for(Procedure procedure : procedures) { if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(procedure.getInterruptType())) { + // Find the interrupt routine clobber + AsmClobber procClobber = getProcedureClobber(procedure); + getLog().append("Interrupt procedure "+procedure.getFullName()+" clobbers "+procClobber.toString()); + + // Find the entry/exit blocks for the interrupt AsmSegment interruptEntry = null; AsmSegment interruptExit = null; - - // Iterate all procedure segments to find the interrupt routine clobber - AsmClobber procClobber = new AsmClobber(); - AsmProgram asm = getProgram().getAsm(); - for(AsmSegment asmSegment : asm.getSegments()) { + for(AsmSegment asmSegment : getProgram().getAsm().getSegments()) { if(procedure.getFullName().equals(asmSegment.getScopeLabel())) { if(asmSegment.getSource().contains(Procedure.InterruptType.HARDWARE_CLOBBER.name())) { if(asmSegment.getSource().contains("entry interrupt")) { @@ -48,11 +49,8 @@ public class Pass4InterruptClobberFix extends Pass2Base { } continue; } - AsmClobber asmSegmentClobber = asmSegment.getClobber(); - procClobber.add(asmSegmentClobber); } } - getLog().append("Interrupt procedure "+procedure.getFullName()+" clobbers "+procClobber.toString()); if(interruptEntry==null || interruptExit==null) { throw new RuntimeException("Cannot find interrupt entry/exit for interrupt "+procedure.getFullName()); } @@ -70,6 +68,34 @@ public class Pass4InterruptClobberFix extends Pass2Base { } } + private AsmClobber getProcedureClobber(Procedure procedure) { + AsmProgram asm = getProgram().getAsm(); + AsmClobber procClobber =new AsmClobber(); + for(AsmSegment asmSegment : asm.getSegments()) { + if(procedure.getFullName().equals(asmSegment.getScopeLabel())) { + if(asmSegment.getSource().contains(Procedure.InterruptType.HARDWARE_CLOBBER.name())) { + // Do not count clobber in the entry/exit + continue; + } + AsmClobber asmSegmentClobber = asmSegment.getClobber(); + procClobber.add(asmSegmentClobber); + } + } + + CallGraph callGraph = getProgram().getCallGraph(); + CallGraph.CallBlock callBlock = callGraph.getCallBlock(procedure.getLabel().getRef()); + List calls = callBlock.getCalls(); + for(CallGraph.CallBlock.Call call : calls) { + LabelRef calledProcLabel = call.getProcedure(); + ProcedureRef calledProcRef = new ProcedureRef(calledProcLabel.getFullName()); + Procedure calledProc = getProgram().getScope().getProcedure(calledProcRef); + AsmClobber calledClobber = getProcedureClobber(calledProc); + procClobber.add(calledClobber); + } + + return procClobber; + } + private List getNonClobberedRegisterNames(AsmClobber procClobber) { List notClobberedRegisters = new ArrayList<>(); if(!procClobber.isClobberA()) { diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index 868c04ea9..a986f544f 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -46,6 +46,11 @@ public class TestPrograms { AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false); } + @Test + public void testIrqHardwareClobberJsr() throws IOException, URISyntaxException { + compileAndCompare("irq-hardware-clobber-jsr"); + } + @Test public void testIrqHardwareClobber() throws IOException, URISyntaxException { compileAndCompare("irq-hardware-clobber"); diff --git a/src/test/java/dk/camelot64/kickc/test/kc/irq-hardware-clobber-jsr.kc b/src/test/java/dk/camelot64/kickc/test/kc/irq-hardware-clobber-jsr.kc new file mode 100644 index 000000000..70c5af7c7 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/kc/irq-hardware-clobber-jsr.kc @@ -0,0 +1,62 @@ +// A minimal working raster hardware IRQ with clobber-based register savings + +const void()** KERNEL_IRQ = $0314; +const void()** HARDWARE_IRQ = $fffe; +const byte* RASTER = $d012; +const byte* VIC_CONTROL = $d011; +const byte* IRQ_STATUS = $d019; +const byte* IRQ_ENABLE = $d01a; +const byte IRQ_RASTER = %00000001; +const byte IRQ_COLLISION_BG = %00000010; +const byte IRQ_COLLISION_SPRITE = %00000100; +const byte IRQ_LIGHTPEN = %00001000; +const byte* BGCOL = $d020; +const byte* FGCOL = $d021; +const byte WHITE = 1; +const byte BLACK = 0; + +const byte* CIA1_INTERRUPT = $dc0d; +const byte CIA_INTERRUPT_CLEAR = $7f; + +// Processor port data direction register +const byte* PROCPORT_DDR = $00; +// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written +const byte PROCPORT_DDR_MEMORY_MASK = %00000111; + +// Processor Port Register controlling RAM/ROM configuration and the datasette +const byte* PROCPORT = $01; +// RAM in $A000, $E000 I/O in $D000 +const byte PROCPORT_RAM_IO = %00110101; +// RAM in $A000, $E000 CHAR ROM in $D000 + +void main() { + asm { sei } + // Disable kernal & basic + *PROCPORT_DDR = PROCPORT_DDR_MEMORY_MASK; + *PROCPORT = PROCPORT_RAM_IO; + // Disable CIA 1 Timer IRQ + *CIA1_INTERRUPT = CIA_INTERRUPT_CLEAR; + // Set raster line to $100 + *VIC_CONTROL |=$80; + *RASTER = $00; + // Enable Raster Interrupt + *IRQ_ENABLE = IRQ_RASTER; + // Set the IRQ routine + *HARDWARE_IRQ = &irq; + asm { cli } + while(true) { + (*FGCOL)++; + } +} + +// Interrupt Routine +interrupt(hardware_clobber) void irq() { + do_irq(); +} + +void do_irq() { + *BGCOL = WHITE; + *BGCOL = BLACK; + // Acknowledge the IRQ + *IRQ_STATUS = IRQ_RASTER; +} \ No newline at end of file diff --git a/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.asm b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.asm new file mode 100644 index 000000000..c8d7993a9 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.asm @@ -0,0 +1,60 @@ +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" + .label HARDWARE_IRQ = $fffe + .label RASTER = $d012 + .label VIC_CONTROL = $d011 + .label IRQ_STATUS = $d019 + .label IRQ_ENABLE = $d01a + .const IRQ_RASTER = 1 + .label BGCOL = $d020 + .label FGCOL = $d021 + .const WHITE = 1 + .const BLACK = 0 + .label CIA1_INTERRUPT = $dc0d + .const CIA_INTERRUPT_CLEAR = $7f + .label PROCPORT_DDR = 0 + .const PROCPORT_DDR_MEMORY_MASK = 7 + .label PROCPORT = 1 + .const PROCPORT_RAM_IO = $35 + jsr main +main: { + sei + lda #PROCPORT_DDR_MEMORY_MASK + sta PROCPORT_DDR + lda #PROCPORT_RAM_IO + sta PROCPORT + lda #CIA_INTERRUPT_CLEAR + sta CIA1_INTERRUPT + lda VIC_CONTROL + ora #$80 + sta VIC_CONTROL + lda #0 + sta RASTER + lda #IRQ_RASTER + sta IRQ_ENABLE + lda #irq + sta HARDWARE_IRQ+1 + cli + b2: + inc FGCOL + jmp b2 +} +irq: { + sta rega+1 + jsr do_irq + rega: + lda #00 + rti +} +do_irq: { + lda #WHITE + sta BGCOL + lda #BLACK + sta BGCOL + lda #IRQ_RASTER + sta IRQ_STATUS + rts +} diff --git a/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.cfg b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.cfg new file mode 100644 index 000000000..9a4e1122e --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.cfg @@ -0,0 +1,38 @@ +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@3 +@3: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main [ ] ( ) + to:@end +@end: scope:[] from @3 + [3] phi() [ ] ( ) +main: scope:[main] from @3 + asm { sei } + [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) + [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) + [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) + [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) + [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) + [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) + [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) + asm { cli } + to:main::@2 +main::@2: scope:[main] from main main::@2 + [13] *((const byte*) FGCOL#0) ← ++ *((const byte*) FGCOL#0) [ ] ( main:2 [ ] ) + to:main::@2 +irq: scope:[irq] from + [14] phi() [ ] ( ) + [15] call do_irq [ ] ( ) + to:irq::@return +irq::@return: scope:[irq] from irq + [16] return [ ] ( ) + to:@return +do_irq: scope:[do_irq] from irq + [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) + [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) + [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) + to:do_irq::@return +do_irq::@return: scope:[do_irq] from do_irq + [20] return [ ] ( ) + to:@return diff --git a/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.log b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.log new file mode 100644 index 000000000..40f767072 --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.log @@ -0,0 +1,879 @@ +PARSING src/test/java/dk/camelot64/kickc/test/kc/irq-hardware-clobber-jsr.kc +// A minimal working raster hardware IRQ with clobber-based register savings + +const void()** KERNEL_IRQ = $0314; +const void()** HARDWARE_IRQ = $fffe; +const byte* RASTER = $d012; +const byte* VIC_CONTROL = $d011; +const byte* IRQ_STATUS = $d019; +const byte* IRQ_ENABLE = $d01a; +const byte IRQ_RASTER = %00000001; +const byte IRQ_COLLISION_BG = %00000010; +const byte IRQ_COLLISION_SPRITE = %00000100; +const byte IRQ_LIGHTPEN = %00001000; +const byte* BGCOL = $d020; +const byte* FGCOL = $d021; +const byte WHITE = 1; +const byte BLACK = 0; + +const byte* CIA1_INTERRUPT = $dc0d; +const byte CIA_INTERRUPT_CLEAR = $7f; + +// Processor port data direction register +const byte* PROCPORT_DDR = $00; +// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written +const byte PROCPORT_DDR_MEMORY_MASK = %00000111; + +// Processor Port Register controlling RAM/ROM configuration and the datasette +const byte* PROCPORT = $01; +// RAM in $A000, $E000 I/O in $D000 +const byte PROCPORT_RAM_IO = %00110101; +// RAM in $A000, $E000 CHAR ROM in $D000 + +void main() { + asm { sei } + // Disable kernal & basic + *PROCPORT_DDR = PROCPORT_DDR_MEMORY_MASK; + *PROCPORT = PROCPORT_RAM_IO; + // Disable CIA 1 Timer IRQ + *CIA1_INTERRUPT = CIA_INTERRUPT_CLEAR; + // Set raster line to $100 + *VIC_CONTROL |=$80; + *RASTER = $00; + // Enable Raster Interrupt + *IRQ_ENABLE = IRQ_RASTER; + // Set the IRQ routine + *HARDWARE_IRQ = &irq; + asm { cli } + while(true) { + (*FGCOL)++; + } +} + +// Interrupt Routine +interrupt(hardware_clobber) void irq() { + do_irq(); +} + +void do_irq() { + *BGCOL = WHITE; + *BGCOL = BLACK; + // Acknowledge the IRQ + *IRQ_STATUS = IRQ_RASTER; +} +Adding pre/post-modifier *((byte*) FGCOL) ← ++ *((byte*) FGCOL) +Resolved forward reference irq to interrupt(HARDWARE_CLOBBER)(void()) irq() +SYMBOLS +(label) @1 +(label) @2 +(label) @3 +(label) @begin +(label) @end +(byte*) BGCOL +(byte) BLACK +(byte*) CIA1_INTERRUPT +(byte) CIA_INTERRUPT_CLEAR +(byte*) FGCOL +(void()**) HARDWARE_IRQ +(byte) IRQ_COLLISION_BG +(byte) IRQ_COLLISION_SPRITE +(byte*) IRQ_ENABLE +(byte) IRQ_LIGHTPEN +(byte) IRQ_RASTER +(byte*) IRQ_STATUS +(void()**) KERNEL_IRQ +(byte*) PROCPORT +(byte*) PROCPORT_DDR +(byte) PROCPORT_DDR_MEMORY_MASK +(byte) PROCPORT_RAM_IO +(byte*) RASTER +(byte*) VIC_CONTROL +(byte) WHITE +(void()) do_irq() +(label) do_irq::@return +interrupt(HARDWARE_CLOBBER)(void()) irq() +(void~) irq::$0 +(label) irq::@return +(void()) main() +(void()*~) main::$0 +(label) main::@1 +(label) main::@2 +(label) main::@3 +(label) main::@4 +(label) main::@5 +(label) main::@6 +(label) main::@return + +Promoting word/signed word/dword/signed dword to void()** in KERNEL_IRQ ← ((void()**)) 788 +Promoting word/dword/signed dword to void()** in HARDWARE_IRQ ← ((void()**)) 65534 +Promoting word/dword/signed dword to byte* in RASTER ← ((byte*)) 53266 +Promoting word/dword/signed dword to byte* in VIC_CONTROL ← ((byte*)) 53265 +Promoting word/dword/signed dword to byte* in IRQ_STATUS ← ((byte*)) 53273 +Promoting word/dword/signed dword to byte* in IRQ_ENABLE ← ((byte*)) 53274 +Promoting word/dword/signed dword to byte* in BGCOL ← ((byte*)) 53280 +Promoting word/dword/signed dword to byte* in FGCOL ← ((byte*)) 53281 +Promoting word/dword/signed dword to byte* in CIA1_INTERRUPT ← ((byte*)) 56333 +Promoting byte/signed byte/word/signed word/dword/signed dword to byte* in PROCPORT_DDR ← ((byte*)) 0 +Promoting byte/signed byte/word/signed word/dword/signed dword to byte* in PROCPORT ← ((byte*)) 1 +INITIAL CONTROL FLOW GRAPH +@begin: scope:[] from + (void()**) KERNEL_IRQ ← ((void()**)) (word/signed word/dword/signed dword) 788 + (void()**) HARDWARE_IRQ ← ((void()**)) (word/dword/signed dword) 65534 + (byte*) RASTER ← ((byte*)) (word/dword/signed dword) 53266 + (byte*) VIC_CONTROL ← ((byte*)) (word/dword/signed dword) 53265 + (byte*) IRQ_STATUS ← ((byte*)) (word/dword/signed dword) 53273 + (byte*) IRQ_ENABLE ← ((byte*)) (word/dword/signed dword) 53274 + (byte) IRQ_RASTER ← (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) IRQ_COLLISION_BG ← (byte/signed byte/word/signed word/dword/signed dword) 2 + (byte) IRQ_COLLISION_SPRITE ← (byte/signed byte/word/signed word/dword/signed dword) 4 + (byte) IRQ_LIGHTPEN ← (byte/signed byte/word/signed word/dword/signed dword) 8 + (byte*) BGCOL ← ((byte*)) (word/dword/signed dword) 53280 + (byte*) FGCOL ← ((byte*)) (word/dword/signed dword) 53281 + (byte) WHITE ← (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) BLACK ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte*) CIA1_INTERRUPT ← ((byte*)) (word/dword/signed dword) 56333 + (byte) CIA_INTERRUPT_CLEAR ← (byte/signed byte/word/signed word/dword/signed dword) 127 + (byte*) PROCPORT_DDR ← ((byte*)) (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) PROCPORT_DDR_MEMORY_MASK ← (byte/signed byte/word/signed word/dword/signed dword) 7 + (byte*) PROCPORT ← ((byte*)) (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) PROCPORT_RAM_IO ← (byte/signed byte/word/signed word/dword/signed dword) 53 + to:@1 +main: scope:[main] from + asm { sei } + *((byte*) PROCPORT_DDR) ← (byte) PROCPORT_DDR_MEMORY_MASK + *((byte*) PROCPORT) ← (byte) PROCPORT_RAM_IO + *((byte*) CIA1_INTERRUPT) ← (byte) CIA_INTERRUPT_CLEAR + *((byte*) VIC_CONTROL) ← *((byte*) VIC_CONTROL) | (byte/word/signed word/dword/signed dword) 128 + *((byte*) RASTER) ← (byte/signed byte/word/signed word/dword/signed dword) 0 + *((byte*) IRQ_ENABLE) ← (byte) IRQ_RASTER + (void()*~) main::$0 ← & interrupt(HARDWARE_CLOBBER)(void()) irq() + *((void()**) HARDWARE_IRQ) ← (void()*~) main::$0 + asm { cli } + to:main::@1 +main::@1: scope:[main] from main main::@2 + if(true) goto main::@2 + to:main::@4 +main::@2: scope:[main] from main::@1 main::@5 + *((byte*) FGCOL) ← ++ *((byte*) FGCOL) + to:main::@1 +main::@4: scope:[main] from main::@1 + to:main::@3 +main::@3: scope:[main] from main::@4 main::@6 + to:main::@return +main::@5: scope:[main] from + to:main::@2 +main::@6: scope:[main] from + to:main::@3 +main::@return: scope:[main] from main::@3 + return + to:@return +@1: scope:[] from @begin + to:@2 +irq: scope:[irq] from + (void~) irq::$0 ← call do_irq + to:irq::@return +irq::@return: scope:[irq] from irq + return + to:@return +@2: scope:[] from @1 + to:@3 +do_irq: scope:[do_irq] from + *((byte*) BGCOL) ← (byte) WHITE + *((byte*) BGCOL) ← (byte) BLACK + *((byte*) IRQ_STATUS) ← (byte) IRQ_RASTER + to:do_irq::@return +do_irq::@return: scope:[do_irq] from do_irq + return + to:@return +@3: scope:[] from @2 + call main + to:@end +@end: scope:[] from @3 + +Eliminating unused variable (void()**) KERNEL_IRQ and assignment [0] (void()**) KERNEL_IRQ ← ((void()**)) (word/signed word/dword/signed dword) 788 +Eliminating unused variable (byte) IRQ_COLLISION_BG and assignment [7] (byte) IRQ_COLLISION_BG ← (byte/signed byte/word/signed word/dword/signed dword) 2 +Eliminating unused variable (byte) IRQ_COLLISION_SPRITE and assignment [8] (byte) IRQ_COLLISION_SPRITE ← (byte/signed byte/word/signed word/dword/signed dword) 4 +Eliminating unused variable (byte) IRQ_LIGHTPEN and assignment [9] (byte) IRQ_LIGHTPEN ← (byte/signed byte/word/signed word/dword/signed dword) 8 +Eliminating unused variable - keeping the call (void~) irq::$0 +Removing empty block main::@4 +Removing empty block main::@3 +Removing empty block main::@5 +Removing empty block main::@6 +Removing empty block @1 +Removing empty block @2 +PROCEDURE MODIFY VARIABLE ANALYSIS + +Completing Phi functions... + +CONTROL FLOW GRAPH SSA WITH ASSIGNMENT CALL & RETURN +@begin: scope:[] from + (void()**) HARDWARE_IRQ#0 ← ((void()**)) (word/dword/signed dword) 65534 + (byte*) RASTER#0 ← ((byte*)) (word/dword/signed dword) 53266 + (byte*) VIC_CONTROL#0 ← ((byte*)) (word/dword/signed dword) 53265 + (byte*) IRQ_STATUS#0 ← ((byte*)) (word/dword/signed dword) 53273 + (byte*) IRQ_ENABLE#0 ← ((byte*)) (word/dword/signed dword) 53274 + (byte) IRQ_RASTER#0 ← (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte*) BGCOL#0 ← ((byte*)) (word/dword/signed dword) 53280 + (byte*) FGCOL#0 ← ((byte*)) (word/dword/signed dword) 53281 + (byte) WHITE#0 ← (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) BLACK#0 ← (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte*) CIA1_INTERRUPT#0 ← ((byte*)) (word/dword/signed dword) 56333 + (byte) CIA_INTERRUPT_CLEAR#0 ← (byte/signed byte/word/signed word/dword/signed dword) 127 + (byte*) PROCPORT_DDR#0 ← ((byte*)) (byte/signed byte/word/signed word/dword/signed dword) 0 + (byte) PROCPORT_DDR_MEMORY_MASK#0 ← (byte/signed byte/word/signed word/dword/signed dword) 7 + (byte*) PROCPORT#0 ← ((byte*)) (byte/signed byte/word/signed word/dword/signed dword) 1 + (byte) PROCPORT_RAM_IO#0 ← (byte/signed byte/word/signed word/dword/signed dword) 53 + to:@3 +main: scope:[main] from @3 + asm { sei } + *((byte*) PROCPORT_DDR#0) ← (byte) PROCPORT_DDR_MEMORY_MASK#0 + *((byte*) PROCPORT#0) ← (byte) PROCPORT_RAM_IO#0 + *((byte*) CIA1_INTERRUPT#0) ← (byte) CIA_INTERRUPT_CLEAR#0 + *((byte*) VIC_CONTROL#0) ← *((byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 + *((byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 + *((byte*) IRQ_ENABLE#0) ← (byte) IRQ_RASTER#0 + (void()*~) main::$0 ← & interrupt(HARDWARE_CLOBBER)(void()) irq() + *((void()**) HARDWARE_IRQ#0) ← (void()*~) main::$0 + asm { cli } + to:main::@1 +main::@1: scope:[main] from main main::@2 + if(true) goto main::@2 + to:main::@return +main::@2: scope:[main] from main::@1 + *((byte*) FGCOL#0) ← ++ *((byte*) FGCOL#0) + to:main::@1 +main::@return: scope:[main] from main::@1 + return + to:@return +irq: scope:[irq] from + call do_irq + to:irq::@1 +irq::@1: scope:[irq] from irq + to:irq::@return +irq::@return: scope:[irq] from irq::@1 + return + to:@return +do_irq: scope:[do_irq] from irq + *((byte*) BGCOL#0) ← (byte) WHITE#0 + *((byte*) BGCOL#0) ← (byte) BLACK#0 + *((byte*) IRQ_STATUS#0) ← (byte) IRQ_RASTER#0 + to:do_irq::@return +do_irq::@return: scope:[do_irq] from do_irq + return + to:@return +@3: scope:[] from @begin + call main + to:@4 +@4: scope:[] from @3 + to:@end +@end: scope:[] from @4 + +SYMBOL TABLE SSA +(label) @3 +(label) @4 +(label) @begin +(label) @end +(byte*) BGCOL +(byte*) BGCOL#0 +(byte) BLACK +(byte) BLACK#0 +(byte*) CIA1_INTERRUPT +(byte*) CIA1_INTERRUPT#0 +(byte) CIA_INTERRUPT_CLEAR +(byte) CIA_INTERRUPT_CLEAR#0 +(byte*) FGCOL +(byte*) FGCOL#0 +(void()**) HARDWARE_IRQ +(void()**) HARDWARE_IRQ#0 +(byte*) IRQ_ENABLE +(byte*) IRQ_ENABLE#0 +(byte) IRQ_RASTER +(byte) IRQ_RASTER#0 +(byte*) IRQ_STATUS +(byte*) IRQ_STATUS#0 +(byte*) PROCPORT +(byte*) PROCPORT#0 +(byte*) PROCPORT_DDR +(byte*) PROCPORT_DDR#0 +(byte) PROCPORT_DDR_MEMORY_MASK +(byte) PROCPORT_DDR_MEMORY_MASK#0 +(byte) PROCPORT_RAM_IO +(byte) PROCPORT_RAM_IO#0 +(byte*) RASTER +(byte*) RASTER#0 +(byte*) VIC_CONTROL +(byte*) VIC_CONTROL#0 +(byte) WHITE +(byte) WHITE#0 +(void()) do_irq() +(label) do_irq::@return +interrupt(HARDWARE_CLOBBER)(void()) irq() +(label) irq::@1 +(label) irq::@return +(void()) main() +(void()*~) main::$0 +(label) main::@1 +(label) main::@2 +(label) main::@return + +OPTIMIZING CONTROL FLOW GRAPH +Culled Empty Block (label) irq::@1 +Culled Empty Block (label) @4 +Succesful SSA optimization Pass2CullEmptyBlocks +Constant (const void()**) HARDWARE_IRQ#0 = ((void()**))65534 +Constant (const byte*) RASTER#0 = ((byte*))53266 +Constant (const byte*) VIC_CONTROL#0 = ((byte*))53265 +Constant (const byte*) IRQ_STATUS#0 = ((byte*))53273 +Constant (const byte*) IRQ_ENABLE#0 = ((byte*))53274 +Constant (const byte) IRQ_RASTER#0 = 1 +Constant (const byte*) BGCOL#0 = ((byte*))53280 +Constant (const byte*) FGCOL#0 = ((byte*))53281 +Constant (const byte) WHITE#0 = 1 +Constant (const byte) BLACK#0 = 0 +Constant (const byte*) CIA1_INTERRUPT#0 = ((byte*))56333 +Constant (const byte) CIA_INTERRUPT_CLEAR#0 = 127 +Constant (const byte*) PROCPORT_DDR#0 = ((byte*))0 +Constant (const byte) PROCPORT_DDR_MEMORY_MASK#0 = 7 +Constant (const byte*) PROCPORT#0 = ((byte*))1 +Constant (const byte) PROCPORT_RAM_IO#0 = 53 +Constant (const void()*) main::$0 = &irq +Succesful SSA optimization Pass2ConstantIdentification +if() condition always true - replacing block destination if(true) goto main::@2 +Succesful SSA optimization Pass2ConstantIfs +Removing unused block main::@return +Succesful SSA optimization Pass2EliminateUnusedBlocks +Culled Empty Block (label) main::@1 +Succesful SSA optimization Pass2CullEmptyBlocks +OPTIMIZING CONTROL FLOW GRAPH +Constant inlined main::$0 = &interrupt(HARDWARE_CLOBBER)(void()) irq() +Succesful SSA optimization Pass2ConstantInlining +Block Sequence Planned @begin @3 @end main main::@2 irq irq::@return do_irq do_irq::@return +Block Sequence Planned @begin @3 @end main main::@2 irq irq::@return do_irq do_irq::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @3 +Adding NOP phi() at start of @end +Adding NOP phi() at start of irq +CALL GRAPH +Calls in [] to main:2 +Calls in [irq] to do_irq:15 + +Propagating live ranges... +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes +Block Sequence Planned @begin @3 @end main main::@2 irq irq::@return do_irq do_irq::@return +Adding NOP phi() at start of @begin +Adding NOP phi() at start of @3 +Adding NOP phi() at start of @end +Adding NOP phi() at start of irq +Propagating live ranges... + +FINAL CONTROL FLOW GRAPH +@begin: scope:[] from + [0] phi() [ ] ( ) + to:@3 +@3: scope:[] from @begin + [1] phi() [ ] ( ) + [2] call main [ ] ( ) + to:@end +@end: scope:[] from @3 + [3] phi() [ ] ( ) +main: scope:[main] from @3 + asm { sei } + [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) + [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) + [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) + [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) + [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) + [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) + [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) + asm { cli } + to:main::@2 +main::@2: scope:[main] from main main::@2 + [13] *((const byte*) FGCOL#0) ← ++ *((const byte*) FGCOL#0) [ ] ( main:2 [ ] ) + to:main::@2 +irq: scope:[irq] from + [14] phi() [ ] ( ) + [15] call do_irq [ ] ( ) + to:irq::@return +irq::@return: scope:[irq] from irq + [16] return [ ] ( ) + to:@return +do_irq: scope:[do_irq] from irq + [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) + [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) + [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) + to:do_irq::@return +do_irq::@return: scope:[do_irq] from do_irq + [20] return [ ] ( ) + to:@return + +DOMINATORS +@begin dominated by @begin +@3 dominated by @begin @3 +@end dominated by @begin @3 @end +main dominated by @begin @3 main +main::@2 dominated by @begin @3 main::@2 main +irq dominated by @begin @3 @end main::@2 irq irq::@return do_irq main do_irq::@return +irq::@return dominated by @begin @3 @end main::@2 irq irq::@return do_irq main do_irq::@return +do_irq dominated by @begin @3 @end main::@2 irq irq::@return do_irq main do_irq::@return +do_irq::@return dominated by @begin @3 @end main::@2 irq irq::@return do_irq main do_irq::@return + +NATURAL LOOPS +Found back edge: Loop head: main::@2 tails: main::@2 blocks: null +Found back edge: Loop head: irq::@return tails: irq blocks: null +Found back edge: Loop head: do_irq tails: irq blocks: null +Found back edge: Loop head: do_irq::@return tails: do_irq blocks: null +Populated: Loop head: main::@2 tails: main::@2 blocks: main::@2 +Populated: Loop head: irq::@return tails: irq blocks: irq +Populated: Loop head: do_irq tails: irq blocks: irq +Populated: Loop head: do_irq::@return tails: do_irq blocks: do_irq irq +Loop head: main::@2 tails: main::@2 blocks: main::@2 +Loop head: irq::@return tails: irq blocks: irq +Loop head: do_irq tails: irq blocks: irq +Loop head: do_irq::@return tails: do_irq blocks: do_irq irq + +NATURAL LOOPS WITH DEPTH +Found 1 loops in scope [irq] + Loop head: irq::@return tails: irq blocks: irq +Found 0 loops in scope [] +null depth in calling loop Loop head: do_irq tails: irq blocks: irq in scope do_irq +null depth in calling loop Loop head: do_irq::@return tails: do_irq blocks: do_irq irq in scope do_irq +Found 2 loops in scope [do_irq] + Loop head: do_irq tails: irq blocks: irq + Loop head: do_irq::@return tails: do_irq blocks: do_irq irq +Found 1 loops in scope [main] + Loop head: main::@2 tails: main::@2 blocks: main::@2 +Loop head: main::@2 tails: main::@2 blocks: main::@2 depth: 1 +Loop head: irq::@return tails: irq blocks: irq depth: 1 +Loop head: do_irq tails: irq blocks: irq depth: 3 +Loop head: do_irq::@return tails: do_irq blocks: do_irq irq depth: 2 + + +VARIABLE REGISTER WEIGHTS +(byte*) BGCOL +(byte) BLACK +(byte*) CIA1_INTERRUPT +(byte) CIA_INTERRUPT_CLEAR +(byte*) FGCOL +(void()**) HARDWARE_IRQ +(byte*) IRQ_ENABLE +(byte) IRQ_RASTER +(byte*) IRQ_STATUS +(byte*) PROCPORT +(byte*) PROCPORT_DDR +(byte) PROCPORT_DDR_MEMORY_MASK +(byte) PROCPORT_RAM_IO +(byte*) RASTER +(byte*) VIC_CONTROL +(byte) WHITE +(void()) do_irq() +interrupt(HARDWARE_CLOBBER)(void()) irq() +(void()) main() + +Initial phi equivalence classes +Complete equivalence classes + +INITIAL ASM +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label HARDWARE_IRQ = $fffe + .label RASTER = $d012 + .label VIC_CONTROL = $d011 + .label IRQ_STATUS = $d019 + .label IRQ_ENABLE = $d01a + .const IRQ_RASTER = 1 + .label BGCOL = $d020 + .label FGCOL = $d021 + .const WHITE = 1 + .const BLACK = 0 + .label CIA1_INTERRUPT = $dc0d + .const CIA_INTERRUPT_CLEAR = $7f + .label PROCPORT_DDR = 0 + .const PROCPORT_DDR_MEMORY_MASK = 7 + .label PROCPORT = 1 + .const PROCPORT_RAM_IO = $35 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @3 [phi:@begin->@3] +b3_from_bbegin: + jmp b3 +//SEG4 @3 +b3: +//SEG5 [2] call main [ ] ( ) + jsr main +//SEG6 [3] phi from @3 to @end [phi:@3->@end] +bend_from_b3: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 asm { sei } + sei + //SEG10 [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_DDR_MEMORY_MASK + sta PROCPORT_DDR + //SEG11 [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_RAM_IO + sta PROCPORT + //SEG12 [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #CIA_INTERRUPT_CLEAR + sta CIA1_INTERRUPT + //SEG13 [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2 + lda VIC_CONTROL + ora #$80 + sta VIC_CONTROL + //SEG14 [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #0 + sta RASTER + //SEG15 [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_ENABLE + //SEG16 [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2 + lda #irq + sta HARDWARE_IRQ+1 + //SEG17 asm { cli } + cli + jmp b2 + //SEG18 main::@2 + b2: + //SEG19 [13] *((const byte*) FGCOL#0) ← ++ *((const byte*) FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1 + inc FGCOL + jmp b2 +} +//SEG20 irq +irq: { + //SEG21 entry interrupt(HARDWARE_CLOBBER) + sta rega+1 + stx regx+1 + sty regy+1 + //SEG22 [15] call do_irq [ ] ( ) + jsr do_irq + jmp breturn + //SEG23 irq::@return + breturn: + //SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) + rega: + lda #00 + regx: + ldx #00 + regy: + ldy #00 + rti +} +//SEG25 do_irq +do_irq: { + //SEG26 [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #WHITE + sta BGCOL + //SEG27 [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG28 [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_STATUS + jmp breturn + //SEG29 do_irq::@return + breturn: + //SEG30 [20] return [ ] ( ) + rts +} + +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) always clobbers reg byte a +Statement [16] return [ ] ( ) always clobbers reg byte a reg byte x reg byte y +Statement [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) always clobbers reg byte a +Statement [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) always clobbers reg byte a +Statement [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [irq] +Uplift Scope [do_irq] +Uplift Scope [] + +Uplifting [main] best 11399 combination +Uplifting [irq] best 11399 combination +Uplifting [do_irq] best 11399 combination +Uplifting [] best 11399 combination +Interrupt procedure irq clobbers ANZ +Removing interrupt register storage stx regx+1 in SEG21 entry interrupt(HARDWARE_CLOBBER) +Removing interrupt register storage sty regy+1 in SEG21 entry interrupt(HARDWARE_CLOBBER) +Removing interrupt register storage regx: in SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) +Removing interrupt register storage ldx #00 in SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) +Removing interrupt register storage regy: in SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) +Removing interrupt register storage ldy #00 in SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) + +ASSEMBLER BEFORE OPTIMIZATION +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label HARDWARE_IRQ = $fffe + .label RASTER = $d012 + .label VIC_CONTROL = $d011 + .label IRQ_STATUS = $d019 + .label IRQ_ENABLE = $d01a + .const IRQ_RASTER = 1 + .label BGCOL = $d020 + .label FGCOL = $d021 + .const WHITE = 1 + .const BLACK = 0 + .label CIA1_INTERRUPT = $dc0d + .const CIA_INTERRUPT_CLEAR = $7f + .label PROCPORT_DDR = 0 + .const PROCPORT_DDR_MEMORY_MASK = 7 + .label PROCPORT = 1 + .const PROCPORT_RAM_IO = $35 +//SEG2 @begin +bbegin: +//SEG3 [1] phi from @begin to @3 [phi:@begin->@3] +b3_from_bbegin: + jmp b3 +//SEG4 @3 +b3: +//SEG5 [2] call main [ ] ( ) + jsr main +//SEG6 [3] phi from @3 to @end [phi:@3->@end] +bend_from_b3: + jmp bend +//SEG7 @end +bend: +//SEG8 main +main: { + //SEG9 asm { sei } + sei + //SEG10 [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_DDR_MEMORY_MASK + sta PROCPORT_DDR + //SEG11 [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_RAM_IO + sta PROCPORT + //SEG12 [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #CIA_INTERRUPT_CLEAR + sta CIA1_INTERRUPT + //SEG13 [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2 + lda VIC_CONTROL + ora #$80 + sta VIC_CONTROL + //SEG14 [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #0 + sta RASTER + //SEG15 [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_ENABLE + //SEG16 [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2 + lda #irq + sta HARDWARE_IRQ+1 + //SEG17 asm { cli } + cli + jmp b2 + //SEG18 main::@2 + b2: + //SEG19 [13] *((const byte*) FGCOL#0) ← ++ *((const byte*) FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1 + inc FGCOL + jmp b2 +} +//SEG20 irq +irq: { + //SEG21 entry interrupt(HARDWARE_CLOBBER) + sta rega+1 + //SEG22 [15] call do_irq [ ] ( ) + jsr do_irq + jmp breturn + //SEG23 irq::@return + breturn: + //SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) + rega: + lda #00 + rti +} +//SEG25 do_irq +do_irq: { + //SEG26 [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #WHITE + sta BGCOL + //SEG27 [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG28 [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_STATUS + jmp breturn + //SEG29 do_irq::@return + breturn: + //SEG30 [20] return [ ] ( ) + rts +} + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp b3 +Removing instruction jmp bend +Removing instruction jmp b2 +Removing instruction jmp breturn +Removing instruction jmp breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction bbegin: +Removing instruction b3_from_bbegin: +Removing instruction bend_from_b3: +Removing instruction breturn: +Succesful ASM optimization Pass5RedundantLabelElimination +Removing instruction b3: +Removing instruction bend: +Removing instruction breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +(label) @3 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) 53280 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte/signed byte/word/signed word/dword/signed dword) 0 +(byte*) CIA1_INTERRUPT +(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) 56333 +(byte) CIA_INTERRUPT_CLEAR +(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) 127 +(byte*) FGCOL +(const byte*) FGCOL#0 FGCOL = ((byte*))(word/dword/signed dword) 53281 +(void()**) HARDWARE_IRQ +(const void()**) HARDWARE_IRQ#0 HARDWARE_IRQ = ((void()**))(word/dword/signed dword) 65534 +(byte*) IRQ_ENABLE +(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) 53274 +(byte) IRQ_RASTER +(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1 +(byte*) IRQ_STATUS +(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) 53273 +(byte*) PROCPORT +(const byte*) PROCPORT#0 PROCPORT = ((byte*))(byte/signed byte/word/signed word/dword/signed dword) 1 +(byte*) PROCPORT_DDR +(const byte*) PROCPORT_DDR#0 PROCPORT_DDR = ((byte*))(byte/signed byte/word/signed word/dword/signed dword) 0 +(byte) PROCPORT_DDR_MEMORY_MASK +(const byte) PROCPORT_DDR_MEMORY_MASK#0 PROCPORT_DDR_MEMORY_MASK = (byte/signed byte/word/signed word/dword/signed dword) 7 +(byte) PROCPORT_RAM_IO +(const byte) PROCPORT_RAM_IO#0 PROCPORT_RAM_IO = (byte/signed byte/word/signed word/dword/signed dword) 53 +(byte*) RASTER +(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) 53266 +(byte*) VIC_CONTROL +(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) 53265 +(byte) WHITE +(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word/dword/signed dword) 1 +(void()) do_irq() +(label) do_irq::@return +interrupt(HARDWARE_CLOBBER)(void()) irq() +(label) irq::@return +(void()) main() +(label) main::@2 + + + +FINAL ASSEMBLER +Score: 8006 + +//SEG0 Basic Upstart +.pc = $801 "Basic" +:BasicUpstart(main) +.pc = $80d "Program" +//SEG1 Global Constants & labels + .label HARDWARE_IRQ = $fffe + .label RASTER = $d012 + .label VIC_CONTROL = $d011 + .label IRQ_STATUS = $d019 + .label IRQ_ENABLE = $d01a + .const IRQ_RASTER = 1 + .label BGCOL = $d020 + .label FGCOL = $d021 + .const WHITE = 1 + .const BLACK = 0 + .label CIA1_INTERRUPT = $dc0d + .const CIA_INTERRUPT_CLEAR = $7f + .label PROCPORT_DDR = 0 + .const PROCPORT_DDR_MEMORY_MASK = 7 + .label PROCPORT = 1 + .const PROCPORT_RAM_IO = $35 +//SEG2 @begin +//SEG3 [1] phi from @begin to @3 [phi:@begin->@3] +//SEG4 @3 +//SEG5 [2] call main [ ] ( ) + jsr main +//SEG6 [3] phi from @3 to @end [phi:@3->@end] +//SEG7 @end +//SEG8 main +main: { + //SEG9 asm { sei } + sei + //SEG10 [5] *((const byte*) PROCPORT_DDR#0) ← (const byte) PROCPORT_DDR_MEMORY_MASK#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_DDR_MEMORY_MASK + sta PROCPORT_DDR + //SEG11 [6] *((const byte*) PROCPORT#0) ← (const byte) PROCPORT_RAM_IO#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #PROCPORT_RAM_IO + sta PROCPORT + //SEG12 [7] *((const byte*) CIA1_INTERRUPT#0) ← (const byte) CIA_INTERRUPT_CLEAR#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #CIA_INTERRUPT_CLEAR + sta CIA1_INTERRUPT + //SEG13 [8] *((const byte*) VIC_CONTROL#0) ← *((const byte*) VIC_CONTROL#0) | (byte/word/signed word/dword/signed dword) 128 [ ] ( main:2 [ ] ) -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2 + lda VIC_CONTROL + ora #$80 + sta VIC_CONTROL + //SEG14 [9] *((const byte*) RASTER#0) ← (byte/signed byte/word/signed word/dword/signed dword) 0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #0 + sta RASTER + //SEG15 [10] *((const byte*) IRQ_ENABLE#0) ← (const byte) IRQ_RASTER#0 [ ] ( main:2 [ ] ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_ENABLE + //SEG16 [11] *((const void()**) HARDWARE_IRQ#0) ← &interrupt(HARDWARE_CLOBBER)(void()) irq() [ ] ( main:2 [ ] ) -- _deref_pptc1=pprc2 + lda #irq + sta HARDWARE_IRQ+1 + //SEG17 asm { cli } + cli + //SEG18 main::@2 + b2: + //SEG19 [13] *((const byte*) FGCOL#0) ← ++ *((const byte*) FGCOL#0) [ ] ( main:2 [ ] ) -- _deref_pbuc1=_inc__deref_pbuc1 + inc FGCOL + jmp b2 +} +//SEG20 irq +irq: { + //SEG21 entry interrupt(HARDWARE_CLOBBER) + sta rega+1 + //SEG22 [15] call do_irq [ ] ( ) + jsr do_irq + //SEG23 irq::@return + //SEG24 [16] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER) + rega: + lda #00 + rti +} +//SEG25 do_irq +do_irq: { + //SEG26 [17] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #WHITE + sta BGCOL + //SEG27 [18] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #BLACK + sta BGCOL + //SEG28 [19] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2 + lda #IRQ_RASTER + sta IRQ_STATUS + //SEG29 do_irq::@return + //SEG30 [20] return [ ] ( ) + rts +} + diff --git a/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.sym b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.sym new file mode 100644 index 000000000..5171a291b --- /dev/null +++ b/src/test/java/dk/camelot64/kickc/test/ref/irq-hardware-clobber-jsr.sym @@ -0,0 +1,42 @@ +(label) @3 +(label) @begin +(label) @end +(byte*) BGCOL +(const byte*) BGCOL#0 BGCOL = ((byte*))(word/dword/signed dword) 53280 +(byte) BLACK +(const byte) BLACK#0 BLACK = (byte/signed byte/word/signed word/dword/signed dword) 0 +(byte*) CIA1_INTERRUPT +(const byte*) CIA1_INTERRUPT#0 CIA1_INTERRUPT = ((byte*))(word/dword/signed dword) 56333 +(byte) CIA_INTERRUPT_CLEAR +(const byte) CIA_INTERRUPT_CLEAR#0 CIA_INTERRUPT_CLEAR = (byte/signed byte/word/signed word/dword/signed dword) 127 +(byte*) FGCOL +(const byte*) FGCOL#0 FGCOL = ((byte*))(word/dword/signed dword) 53281 +(void()**) HARDWARE_IRQ +(const void()**) HARDWARE_IRQ#0 HARDWARE_IRQ = ((void()**))(word/dword/signed dword) 65534 +(byte*) IRQ_ENABLE +(const byte*) IRQ_ENABLE#0 IRQ_ENABLE = ((byte*))(word/dword/signed dword) 53274 +(byte) IRQ_RASTER +(const byte) IRQ_RASTER#0 IRQ_RASTER = (byte/signed byte/word/signed word/dword/signed dword) 1 +(byte*) IRQ_STATUS +(const byte*) IRQ_STATUS#0 IRQ_STATUS = ((byte*))(word/dword/signed dword) 53273 +(byte*) PROCPORT +(const byte*) PROCPORT#0 PROCPORT = ((byte*))(byte/signed byte/word/signed word/dword/signed dword) 1 +(byte*) PROCPORT_DDR +(const byte*) PROCPORT_DDR#0 PROCPORT_DDR = ((byte*))(byte/signed byte/word/signed word/dword/signed dword) 0 +(byte) PROCPORT_DDR_MEMORY_MASK +(const byte) PROCPORT_DDR_MEMORY_MASK#0 PROCPORT_DDR_MEMORY_MASK = (byte/signed byte/word/signed word/dword/signed dword) 7 +(byte) PROCPORT_RAM_IO +(const byte) PROCPORT_RAM_IO#0 PROCPORT_RAM_IO = (byte/signed byte/word/signed word/dword/signed dword) 53 +(byte*) RASTER +(const byte*) RASTER#0 RASTER = ((byte*))(word/dword/signed dword) 53266 +(byte*) VIC_CONTROL +(const byte*) VIC_CONTROL#0 VIC_CONTROL = ((byte*))(word/dword/signed dword) 53265 +(byte) WHITE +(const byte) WHITE#0 WHITE = (byte/signed byte/word/signed word/dword/signed dword) 1 +(void()) do_irq() +(label) do_irq::@return +interrupt(HARDWARE_CLOBBER)(void()) irq() +(label) irq::@return +(void()) main() +(label) main::@2 +