1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-08-02 09:29:35 +00:00

Implemented clobber analysis to ensure that hardware clobber interrupts only save the registers clobbered.

This commit is contained in:
jespergravgaard 2018-08-11 00:48:15 +02:00
parent 9ef574f32d
commit f33d7018ba
12 changed files with 1065 additions and 23 deletions

View File

@ -357,6 +357,9 @@ public class Compiler {
new Pass4CodeGeneration(program, true).generate();
new Pass4AssertNoCpuClobber(program).check();
// Remove unnecessary register savings from interrupts {@link InterruptType#HARDWARE_NOCLOBBER}
new Pass4InterruptClobberFix(program).fix();
getLog().append("\nASSEMBLER BEFORE OPTIMIZATION");
getLog().append(program.getAsm().toString());

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.fragment.AsmFormat;
import dk.camelot64.kickc.model.values.ScopeRef;
import java.util.ArrayList;
import java.util.Collection;
@ -36,8 +37,8 @@ public class AsmProgram {
return segments;
}
public AsmSegment startSegment(Integer statementIndex, String source) {
AsmSegment segment = new AsmSegment(nextSegmentIndex++, statementIndex, source);
public AsmSegment startSegment(ScopeRef scopeRef, Integer statementIndex, String source) {
AsmSegment segment = new AsmSegment(nextSegmentIndex++, scopeRef, statementIndex, source);
segments.add(segment);
return segment;
}

View File

@ -1,6 +1,7 @@
package dk.camelot64.kickc.asm;
import dk.camelot64.kickc.model.PhiTransitions;
import dk.camelot64.kickc.model.values.ScopeRef;
import java.util.ArrayList;
import java.util.List;
@ -44,8 +45,12 @@ public class AsmSegment {
/** If the segment is an assignment in a PHI transition this contains the index of the assignment within the transition. */
private Integer phiTransitionAssignmentIdx;
public AsmSegment(int index, Integer statementIdx, String source) {
/** The full name of the containing scope (procedure). */
private String scopeLabel;
public AsmSegment(int index, ScopeRef scope, Integer statementIdx, String source) {
this.lines = new ArrayList<>();
this.scopeLabel = scope.getFullName();
this.index = index;
this.statementIdx = statementIdx;
this.source = source;
@ -108,6 +113,10 @@ public class AsmSegment {
this.phiTransitionAssignmentIdx = phiTransitionAssignmentIdx;
}
public String getScopeLabel() {
return scopeLabel;
}
/**
* Get the number of bytes the segment occupies in memory.
* Per default calculated by adding up the bytes of each ASM line in the segment.
@ -219,4 +228,7 @@ public class AsmSegment {
return toString(new AsmProgram.AsmPrintState(true, false));
}
public void setSource(String source) {
this.source = source;
}
}

View File

@ -109,7 +109,7 @@ public class AsmFragmentTemplate {
AsmFragmentInstance fragmentInstance =
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
AsmProgram asm = new AsmProgram();
asm.startSegment(null, signature);
asm.startSegment( ScopeRef.ROOT, null, signature);
fragmentInstance.generate(asm);
AsmClobber asmClobber = asm.getClobber();
this.clobber = new AsmFragmentClobber(asmClobber);

View File

@ -45,13 +45,13 @@ public class Pass4CodeGeneration {
AsmProgram asm = new AsmProgram();
ScopeRef currentScope = ScopeRef.ROOT;
asm.startSegment(null, "Basic Upstart");
asm.startSegment( currentScope, null, "Basic Upstart");
asm.addLine(new AsmSetPc("Basic", AsmFormat.getAsmNumber(0x0801)));
asm.addLine(new AsmBasicUpstart("main"));
asm.addLine(new AsmSetPc("Program", AsmFormat.getAsmNumber(0x080d)));
// Generate global ZP labels
asm.startSegment(null, "Global Constants & labels");
asm.startSegment( currentScope, null, "Global Constants & labels");
addConstants(asm, currentScope);
addZpLabels(asm, currentScope);
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
@ -61,7 +61,7 @@ public class Pass4CodeGeneration {
asm.addScopeEnd();
}
currentScope = block.getScope();
asm.startSegment(null, block.getLabel().getFullName());
asm.startSegment(currentScope, null, block.getLabel().getFullName());
asm.addScopeBegin(block.getLabel().getFullName().replace('@', 'b').replace(':', '_'));
// Add all ZP labels for the scope
addConstants(asm, currentScope);
@ -75,11 +75,11 @@ public class Pass4CodeGeneration {
// Generate interrupt entry if needed
Procedure procedure = block.getProcedure(program);
if(procedure!=null && procedure.getInterruptType()!=null) {
generateInterruptEntry(asm, procedure.getInterruptType());
generateInterruptEntry(asm, procedure);
}
} else {
// Generate label for block inside procedure
asm.startSegment(null, block.getLabel().getFullName());
asm.startSegment(currentScope, null, block.getLabel().getFullName());
asm.addLabel(block.getLabel().getLocalName().replace('@', 'b').replace(':', '_'));
}
// Generate statements
@ -376,7 +376,7 @@ public class Pass4CodeGeneration {
*/
public void generateStatementAsm(AsmProgram asm, ControlFlowBlock block, Statement statement, AsmCodegenAluState aluState, boolean genCallPhiEntry) {
asm.startSegment(statement.getIndex(), statement.toString(program, verboseAliveInfo));
asm.startSegment(block.getScope(), statement.getIndex(), statement.toString(program, verboseAliveInfo));
// IF the previous statement was added to the ALU register - generate the composite ASM fragment
if(aluState.hasAluAssignment()) {
@ -469,10 +469,11 @@ public class Pass4CodeGeneration {
/**
* Generate exit-code for entering an interrupt procedure based on the interrupt type
* @param asm The assembler to generate code into
* @param interruptType The type of interrupt to generate
* @param procedure The interrupt procedure
*/
private void generateInterruptEntry(AsmProgram asm, Procedure.InterruptType interruptType) {
asm.startSegment(null, "interrupt "+interruptType.name());
private void generateInterruptEntry(AsmProgram asm, Procedure procedure) {
Procedure.InterruptType interruptType = procedure.getInterruptType();
asm.startSegment( procedure.getRef(), null, "entry interrupt("+interruptType.name()+")");
//asm.getCurrentSegment().setXXX();
if(Procedure.InterruptType.KERNEL_MIN.equals(interruptType)) {
// No entry ASM needed
@ -485,8 +486,9 @@ public class Pass4CodeGeneration {
} else if(Procedure.InterruptType.HARDWARE_NONE.equals(interruptType)) {
// No entry ASM needed
} else if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(interruptType)) {
throw new CompileError("Not implemented! "+interruptType.name());
} else {
asm.addInstruction("sta", AsmAddressingMode.ABS, "rega+1", false).setDontOptimize(true);
asm.addInstruction("stx", AsmAddressingMode.ABS, "regx+1", false).setDontOptimize(true);
asm.addInstruction("sty", AsmAddressingMode.ABS, "regy+1", false).setDontOptimize(true); } else {
throw new RuntimeException("Interrupt Type not supported " + interruptType.name());
}
}
@ -498,6 +500,7 @@ public class Pass4CodeGeneration {
* @param interruptType The type of interrupt to generate
*/
private void generateInterruptExit(AsmProgram asm, Statement statement, Procedure.InterruptType interruptType) {
asm.getCurrentSegment().setSource(asm.getCurrentSegment().getSource() + " - exit interrupt("+interruptType.name()+")");
if(Procedure.InterruptType.KERNEL_MIN.equals(interruptType)) {
asm.addInstruction("jmp", AsmAddressingMode.ABS, "$ea81", false);
} else if(Procedure.InterruptType.KERNEL_KEYBOARD.equals(interruptType)) {
@ -513,7 +516,13 @@ public class Pass4CodeGeneration {
} else if(Procedure.InterruptType.HARDWARE_NONE.equals(interruptType)) {
asm.addInstruction("rti", AsmAddressingMode.NON, null, false);
} else if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(interruptType)) {
throw new CompileError("Not implemented! "+interruptType.name());
asm.addLabel("rega").setDontOptimize(true);
asm.addInstruction("lda", AsmAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regx").setDontOptimize(true);
asm.addInstruction("ldx", AsmAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addLabel("regy").setDontOptimize(true);
asm.addInstruction("ldy", AsmAddressingMode.IMM, "00", false).setDontOptimize(true);
asm.addInstruction("rti", AsmAddressingMode.NON, null, false);
} else {
throw new RuntimeException("Interrupt Type not supported " + statement);
}
@ -574,7 +583,7 @@ public class Pass4CodeGeneration {
segmentSrc += fBlock.getLabel().getFullName() + " ";
}
segmentSrc += "to " + toBlock.getLabel().getFullName();
asm.startSegment(toFirstStatement.getIndex(), segmentSrc);
asm.startSegment( scope, toFirstStatement.getIndex(), segmentSrc);
asm.getCurrentSegment().setPhiTransitionId(transition.getTransitionId());
for(ControlFlowBlock fBlock : transition.getFromBlocks()) {
asm.addLabel((toBlock.getLabel().getLocalName() + "_from_" + fBlock.getLabel().getLocalName()).replace('@', 'b').replace(':', '_'));
@ -585,7 +594,7 @@ public class Pass4CodeGeneration {
RValue rValue = assignment.getrValue();
Statement statement = assignment.getPhiBlock();
// Generate an ASM move fragment
asm.startSegment(statement.getIndex(), "[" + statement.getIndex() + "] phi " + lValue.toString(program) + " = " + rValue.toString(program));
asm.startSegment(scope, statement.getIndex(), "[" + statement.getIndex() + "] phi " + lValue.toString(program) + " = " + rValue.toString(program));
asm.getCurrentSegment().setPhiTransitionId(transition.getTransitionId());
asm.getCurrentSegment().setPhiTransitionAssignmentIdx(assignment.getAssignmentIdx());
if(isRegisterCopy(lValue, rValue)) {

View File

@ -0,0 +1,101 @@
package dk.camelot64.kickc.passes;
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.Program;
import dk.camelot64.kickc.model.Registers;
import dk.camelot64.kickc.model.symbols.Procedure;
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 {
public Pass4InterruptClobberFix(Program program) {
super(program);
}
/**
* Check that no statement clobbers a CPU register used by an alive variable
*/
public void fix() {
Collection<Procedure> procedures = getProgram().getScope().getAllProcedures(true);
for(Procedure procedure : procedures) {
if(Procedure.InterruptType.HARDWARE_CLOBBER.equals(procedure.getInterruptType())) {
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()) {
if(procedure.getFullName().equals(asmSegment.getScopeLabel())) {
if(asmSegment.getSource().contains(Procedure.InterruptType.HARDWARE_CLOBBER.name())) {
if(asmSegment.getSource().contains("entry interrupt")) {
interruptEntry = asmSegment;
} else if(asmSegment.getSource().contains("exit interrupt")) {
interruptExit = asmSegment;
} else {
throw new RuntimeException("Unknown interrupt ASM segment "+asmSegment.getSource());
}
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());
}
List<String> notClobberedRegisters = getNonClobberedRegisterNames(procClobber);
if(notClobberedRegisters.isEmpty()) {
// All registers clobbered - no need to fix anything
continue;
}
// Remove all lines saving/restoring non-clobbered registers in entry
pruneNonClobberedInterruptLines(interruptEntry, notClobberedRegisters);
// Remove all lines saving/restoring non-clobbered registers in entry
pruneNonClobberedInterruptLines(interruptExit, notClobberedRegisters);
}
}
}
private List<String> getNonClobberedRegisterNames(AsmClobber procClobber) {
List<String> notClobberedRegisters = new ArrayList<>();
if(!procClobber.isClobberA()) {
notClobberedRegisters.add("a");
}
if(!procClobber.isClobberX()) {
notClobberedRegisters.add("x");
}
if(!procClobber.isClobberY()) {
notClobberedRegisters.add("y");
}
return notClobberedRegisters;
}
private void pruneNonClobberedInterruptLines(AsmSegment interruptEntryExit, List<String> notClobberedRegisters) {
ListIterator<AsmLine> entryLines = interruptEntryExit.getLines().listIterator();
while(entryLines.hasNext()) {
AsmLine line = entryLines.next();
for(String notClobberedReg : notClobberedRegisters) {
if(line.getAsm().contains(notClobberedReg)) {
// Found an A/X/Y in the asm where A/X/Y is not clobbered - remove the line
getLog().append("Removing interrupt register storage "+line.toString()+" in SEG"+interruptEntryExit.getIndex()+" "+interruptEntryExit.getSource());
entryLines.remove();
}
}
}
}
}

View File

@ -160,7 +160,7 @@ public class Pass4RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
combination.allocate(getProgram());
// Generate ASM
AsmProgram asm = new AsmProgram();
asm.startSegment(statement.getIndex(), statement.toString(getProgram(), true));
asm.startSegment(block.getScope(), statement.getIndex(), statement.toString(getProgram(), true));
Pass4CodeGeneration.AsmCodegenAluState aluState = new Pass4CodeGeneration.AsmCodegenAluState();
try {
(new Pass4CodeGeneration(getProgram(), false)).generateStatementAsm(asm, block, statement, aluState, false);

View File

@ -46,10 +46,10 @@ public class TestPrograms {
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
}
//@Test
//public void testIrqHardwareClobber() throws IOException, URISyntaxException {
// compileAndCompare("irq-hardware-clobber");
//}
@Test
public void testIrqHardwareClobber() throws IOException, URISyntaxException {
compileAndCompare("irq-hardware-clobber");
}
@Test
public void testIrqHardware() throws IOException, URISyntaxException {

View File

@ -0,0 +1,56 @@
.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
lda #>irq
sta HARDWARE_IRQ+1
cli
b2:
inc FGCOL
jmp b2
}
irq: {
sta rega+1
lda #WHITE
sta BGCOL
lda #BLACK
sta BGCOL
lda #IRQ_RASTER
sta IRQ_STATUS
rega:
lda #00
rti
}

View File

@ -0,0 +1,31 @@
@begin: scope:[] from
[0] phi() [ ] ( )
to:@2
@2: scope:[] from @begin
[1] phi() [ ] ( )
[2] call main [ ] ( )
to:@end
@end: scope:[] from @2
[3] phi() [ ] ( )
main: scope:[main] from @2
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] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( )
[15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( )
[16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( )
to:irq::@return
irq::@return: scope:[irq] from irq
[17] return [ ] ( )
to:@return

View File

@ -0,0 +1,789 @@
PARSING src/test/java/dk/camelot64/kickc/test/kc/irq-hardware-clobber.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() {
*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) @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
interrupt(HARDWARE_CLOBBER)(void()) irq()
(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
*((byte*) BGCOL) ← (byte) WHITE
*((byte*) BGCOL) ← (byte) BLACK
*((byte*) IRQ_STATUS) ← (byte) IRQ_RASTER
to:irq::@return
irq::@return: scope:[irq] from irq
return
to:@return
@2: scope:[] from @1
call main
to:@end
@end: scope:[] from @2
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
Removing empty block main::@4
Removing empty block main::@3
Removing empty block main::@5
Removing empty block main::@6
Removing empty block @1
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:@2
main: scope:[main] from @2
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
*((byte*) BGCOL#0) ← (byte) WHITE#0
*((byte*) BGCOL#0) ← (byte) BLACK#0
*((byte*) IRQ_STATUS#0) ← (byte) IRQ_RASTER#0
to:irq::@return
irq::@return: scope:[irq] from irq
return
to:@return
@2: scope:[] from @begin
call main
to:@3
@3: scope:[] from @2
to:@end
@end: scope:[] from @3
SYMBOL TABLE SSA
(label) @2
(label) @3
(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
interrupt(HARDWARE_CLOBBER)(void()) irq()
(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) @3
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 @2 @end main main::@2 irq irq::@return
Block Sequence Planned @begin @2 @end main main::@2 irq irq::@return
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
CALL GRAPH
Calls in [] to main:2
Propagating live ranges...
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
Block Sequence Planned @begin @2 @end main main::@2 irq irq::@return
Adding NOP phi() at start of @begin
Adding NOP phi() at start of @2
Adding NOP phi() at start of @end
Propagating live ranges...
FINAL CONTROL FLOW GRAPH
@begin: scope:[] from
[0] phi() [ ] ( )
to:@2
@2: scope:[] from @begin
[1] phi() [ ] ( )
[2] call main [ ] ( )
to:@end
@end: scope:[] from @2
[3] phi() [ ] ( )
main: scope:[main] from @2
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] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( )
[15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( )
[16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( )
to:irq::@return
irq::@return: scope:[irq] from irq
[17] return [ ] ( )
to:@return
DOMINATORS
@begin dominated by @begin
@2 dominated by @2 @begin
@end dominated by @2 @begin @end
main dominated by @2 @begin main
main::@2 dominated by @2 @begin main::@2 main
irq dominated by @2 @begin @end main::@2 irq irq::@return main
irq::@return dominated by @2 @begin @end main::@2 irq irq::@return main
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
Populated: Loop head: main::@2 tails: main::@2 blocks: main::@2
Populated: Loop head: irq::@return tails: irq blocks: irq
Loop head: main::@2 tails: main::@2 blocks: main::@2
Loop head: irq::@return tails: irq blocks: irq
NATURAL LOOPS WITH DEPTH
Found 1 loops in scope [irq]
Loop head: irq::@return tails: irq blocks: irq
Found 0 loops in scope []
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
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
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 @2 [phi:@begin->@2]
b2_from_bbegin:
jmp b2
//SEG4 @2
b2:
//SEG5 [2] call main [ ] ( )
jsr main
//SEG6 [3] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
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
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 [14] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #WHITE
sta BGCOL
//SEG23 [15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #BLACK
sta BGCOL
//SEG24 [16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
jmp breturn
//SEG25 irq::@return
breturn:
//SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
rega:
lda #00
regx:
ldx #00
regy:
ldy #00
rti
}
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 [14] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) always clobbers reg byte a
Statement [15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) always clobbers reg byte a
Statement [16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) always clobbers reg byte a
Statement [17] return [ ] ( ) always clobbers reg byte a reg byte x reg byte y
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope [irq]
Uplift Scope []
Uplifting [main] best 503 combination
Uplifting [irq] best 503 combination
Uplifting [] best 503 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 SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
Removing interrupt register storage ldx #00 in SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
Removing interrupt register storage regy: in SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
Removing interrupt register storage ldy #00 in SEG26 [17] 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 @2 [phi:@begin->@2]
b2_from_bbegin:
jmp b2
//SEG4 @2
b2:
//SEG5 [2] call main [ ] ( )
jsr main
//SEG6 [3] phi from @2 to @end [phi:@2->@end]
bend_from_b2:
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
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 [14] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #WHITE
sta BGCOL
//SEG23 [15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #BLACK
sta BGCOL
//SEG24 [16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
jmp breturn
//SEG25 irq::@return
breturn:
//SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
rega:
lda #00
rti
}
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp b2
Removing instruction jmp bend
Removing instruction jmp b2
Removing instruction jmp breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction bbegin:
Removing instruction b2_from_bbegin:
Removing instruction bend_from_b2:
Removing instruction breturn:
Succesful ASM optimization Pass5RedundantLabelElimination
Removing instruction b2:
Removing instruction bend:
Succesful ASM optimization Pass5UnusedLabelElimination
FINAL SYMBOL TABLE
(label) @2
(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
interrupt(HARDWARE_CLOBBER)(void()) irq()
(label) irq::@return
(void()) main()
(label) main::@2
FINAL ASSEMBLER
Score: 380
//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 @2 [phi:@begin->@2]
//SEG4 @2
//SEG5 [2] call main [ ] ( )
jsr main
//SEG6 [3] phi from @2 to @end [phi:@2->@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
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 [14] *((const byte*) BGCOL#0) ← (const byte) WHITE#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #WHITE
sta BGCOL
//SEG23 [15] *((const byte*) BGCOL#0) ← (const byte) BLACK#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #BLACK
sta BGCOL
//SEG24 [16] *((const byte*) IRQ_STATUS#0) ← (const byte) IRQ_RASTER#0 [ ] ( ) -- _deref_pbuc1=vbuc2
lda #IRQ_RASTER
sta IRQ_STATUS
//SEG25 irq::@return
//SEG26 [17] return [ ] ( ) - exit interrupt(HARDWARE_CLOBBER)
rega:
lda #00
rti
}

View File

@ -0,0 +1,40 @@
(label) @2
(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
interrupt(HARDWARE_CLOBBER)(void()) irq()
(label) irq::@return
(void()) main()
(label) main::@2