1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-10-11 12:23:45 +00:00

Implemented Voronoi renderer. Added missing fragments. Added combination limit and an iteration trying to uplift the remains.

This commit is contained in:
jespergravgaard 2017-08-07 14:53:25 +02:00
parent ec1838adba
commit 2a19c52c1d
43 changed files with 18419 additions and 27 deletions

View File

@ -73,16 +73,16 @@ public class Compiler {
program.getLog().append("REGISTER UPLIFT POTENTIAL REGISTERS");
program.getLog().append(program.getRegisterPotentials().toString());
// Find register uplift scopes
new Pass3RegisterUpliftScopeAnalysis(program).findScopes();
program.getLog().append("REGISTER UPLIFT SCOPES");
program.getLog().append(program.getRegisterUpliftProgram().toString((program.getVariableRegisterWeights())));
// Attempt uplifting registers through a lot of combinations
new Pass3RegisterUpliftCombinations(program).performUplift();
new Pass3RegisterUpliftCombinations(program).performUplift(10_000);
// Attempt uplifting registers one at a time to catch remaining potential not realized by combination search
new Pass3RegisterUpliftRemains(program).performUplift();
// Final register coalesce and code generation
new Pass3ZeroPageCoalesce(program).allocate();

View File

@ -1,10 +1,14 @@
Features
- Move the main code into a main() function, and disallow code outside functions. The main function per default has no parameters and exits with RTS.
- Add a for loop for(init;condition;increment) {stmt} -> { init; do { stmt; increment } while (condition) }
- Add Fixed Point number types
- Add for loop for(byte i: 1..100) { } and for(byte i : 100..0) {} (plus maybe .+. and .-. to make the inc/dec unambiguous)
- Add signed bytes
- Add signed words
- Add Fixed Point number types fixed[8.8], fixed[16.8] - maybe even fixed[24.4]
- Add imports
- Add structs
- Let { stmt } introduce a new anonymous scope.
- Add possibility of declaring in-program data - just like .byte/.fill in KickAss.
- Let { stmt } introduce a new anonymous scope. (But not when optimizing)
- Add preprocessing / find a way to allow some functions to run at compile time
- Implement inline compilation of functions (and a mechanism for choosing which methods / calls to inline)
- Add ability to call ASM code from KC.
@ -13,27 +17,47 @@ Features
- Add inline ASM (maybe?)
- Handle long branches
- Allow complex array expressions in lValues eg. (SCREEN+$100)[idx]
- Optimize loops by unrolling them somewhat
- Optimize loops with Strength reduction (https://en.wikipedia.org/wiki/Strength_reduction)
+ Create a proper main function for the compiler
+ Add ++/-- incrementing/decrementing operators.
Assembler Improvements
- Make generated ASM human readable. Use hex-numbers, add labels for constants and zp-variables.
- Eliminate unnecessary labels in ASM
- Eliminate CPX from DEX, CPX #0, BNE la1
- Eliminate LDA from DEC $2, LDA $2, BNE la1
- Eliminate LDA from STA $11, LDA $11
- Optimize by allowing resequencing of ASM (statements and phi assignments) in a final phase.
Known Problems
- Procedures that modify variables outside their scope doew not work. Outer vars must be transfered in/out like parameters/return values to get it working.
- Alive vars are propagated backward through procedures (correctly). However they are then propagated back through ALL calls to the procedure incorrectly. They should only be alive at calls where they are alive after the call. In summin.kc s1#0 is incirrectly backpropagated through the first call, where it is not alive.
Register Allocation
- Limit number of combinations tested
- Equivalences not tested through combinaitons should be tested individually afterwards.
- Allow user to limit number of combinations tested
- Safe-Copy based SSA deconstruction
- Reuse phi-transitions that are identical
- Optimize phi transitions by ensuring that identical phi-transitions with regards to register allocation are collected into a single transition.
- Optimize by finding optimal sequence for multiple phi assignments in entry-segments.
- Interval Analysis (variable liveness intervals)
- ComputeLoopNestDepth(b) - Assign loop nesting levels to blocks.
- ComputeRegisterPreference(v), ComputeWeight(v)
- CalculateClobbering(i)
- Maybe support several fragements for the same operation with different cost and clobbering profiles.
- Register types: A, X, Y, ZP, (memory).
- Maybe register preference should also incorporate the types of operations that can be effectively performed with the register? (Maybe based on fragment cost?)
- Implement a register allocation (coloring) algorithm using by liveness intervals, preferences, weights & clobbering information.
- Optimize register allocation by combining with knowledge of ASM program cost (bytes/cycles) and different ASM fragments with different clobbering.
- Avoid clobbering alive vars
- Maybe support several fragements for the same operation with different cost and clobbering profiles.
- Add memory registers (if we need to free some ZP)
+ Matrix Phi operation (instead of separate statements)
+ Phi Lifting
+ PhiLifting & PhiMemCoalesce (http://compilers.cs.ucla.edu/fernando/projects/soc/reports/short_tech.pdf)
+ Interval Analysis (variable liveness intervals)
+ ComputeLoopNestDepth(b) - Assign loop nesting levels to blocks.
+ ComputeRegisterPreference(v), ComputeWeight(v)
+ CalculateClobbering(i)
+ Register types: A, X, Y, ZP, (memory).
+ Implement a register allocation (coloring) algorithm using by liveness intervals, preferences, weights & clobbering information.
+ Optimize register allocation by combining with knowledge of ASM program cost (bytes/cycles) and different ASM fragments with different clobbering.
Process/Code Structure Improvement
- Eliminate copy visitor
- Refactor Expression Operator Implementation & Evaluation into one class per operator
- Improve error messages to give better context
- Offer to compile resulting ASM with KickAssembler
@ -47,10 +71,6 @@ Testing
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
+ Test the ASM program output resulting from compiling specific KC program input.
Optimizations
- Optimize by allowing resequencing of statements and phi assignemtns in a final phase. Perhaps by converting phi statements to "normal" statements and using some optimization step.
- This phase could also help simplify LDA xx, CMP#0, BNE by expressing these in a language where CMP can be eliminated before.
Usages
- Implement library for memory allocation in main memory
- Implement library for output on the screen (using basic functions)

View File

@ -0,0 +1,3 @@
lda {zpby1}
sec
sbc {zpby2}

View File

@ -0,0 +1 @@
jmp {la1}

View File

@ -0,0 +1,3 @@
stx $ff
cmp $ff
beq {la1}

View File

@ -0,0 +1,3 @@
sty $ff
cmp $ff
beq {la1}

View File

@ -0,0 +1,2 @@
cmp {zpby1}
beq {la1}

View File

@ -0,0 +1,2 @@
cmp {zpby1}
bcc {la1}

View File

@ -0,0 +1,4 @@
lda {zpby1}
sec
sbc {zpby2}
tax

View File

@ -0,0 +1,3 @@
stx $ff
cmp $ff
beq {la1}

View File

@ -0,0 +1 @@
jmp {la1}

View File

@ -0,0 +1,3 @@
sty $ff
cpx $ff
beq {la1}

View File

@ -0,0 +1,2 @@
cpx {zpby1}
beq {la1}

View File

@ -0,0 +1,4 @@
lda {zpby1}
sec
sbc {zpby2}
tay

View File

@ -0,0 +1,3 @@
sty $ff
cmp $ff
beq {la1}

View File

@ -0,0 +1,3 @@
sty $ff
cpx $ff
beq {la1}

View File

@ -0,0 +1 @@
jmp {la1}

View File

@ -0,0 +1,2 @@
cpy {zpby1}
beq {la1}

View File

@ -0,0 +1,3 @@
sec
sbc {zpby2}
sta {zpby1}

View File

@ -0,0 +1,4 @@
lda {zpby1}
sec
sbc {zpby2}
sta {zpby1}

View File

@ -0,0 +1,4 @@
lda {zpby2}
sec
sbc {zpby1}
sta {zpby1}

View File

@ -0,0 +1,4 @@
lda {zpby2}
sec
sbc {zpby3}
sta {zpby1}

View File

@ -0,0 +1,2 @@
cmp {zpby1}
beq {la1}

View File

@ -0,0 +1,2 @@
cpx {zpby1}
beq {la1}

View File

@ -0,0 +1,2 @@
cpy {zpby1}
beq {la1}

View File

@ -0,0 +1,3 @@
lda {zpby1}
cmp {zpby2}
beq {la1}

View File

@ -0,0 +1,3 @@
lda {zpby1}
cmp {zpby2}
bcc {la1}

View File

@ -0,0 +1,3 @@
tay
lda #{coby1}
sta ({zpptrby1}),y

View File

@ -0,0 +1,4 @@
txa
tay
lda #{coby1}
sta ({zpptrby1}),y

View File

@ -0,0 +1,2 @@
lda #{coby1}
sta ({zpptrby1}),y

View File

@ -0,0 +1,3 @@
lda #{coby1}
ldy {zpby1}
sta ({zpptrby1}),y

View File

@ -0,0 +1,3 @@
lda {zpby1}
tay
sta ({zpptrby1}),y

View File

@ -28,7 +28,7 @@ public class RegisterCombinationIterator implements Iterator<RegisterCombination
return nextIterationId < getNumIterations();
}
private int getNumIterations() {
public int getNumIterations() {
int numIterations = 1;
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
List<RegisterAllocation.Register> registers = registerPotentials.getPotentialRegisters(equivalenceClass);

View File

@ -56,7 +56,7 @@ public class RegisterUpliftScope {
* @param registerPotentials The potential registers to use for each live range equivalence class
* @return Iterator of all combinations
*/
public Iterator<RegisterCombination> geCombinationIterator(RegisterPotentials registerPotentials) {
public RegisterCombinationIterator getCombinationIterator(RegisterPotentials registerPotentials) {
return new RegisterCombinationIterator(equivalenceClasses, registerPotentials);
}

View File

@ -5,7 +5,6 @@ import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.AsmSegment;
import dk.camelot64.kickc.icl.*;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@ -17,8 +16,7 @@ public class Pass3RegisterUpliftCombinations extends Pass2Base {
super(program);
}
public void performUplift() {
public void performUplift(int maxCombinations) {
// Test uplift combinations to find the best one.
Set<String> unknownFragments = new LinkedHashSet<>();
List<RegisterUpliftScope> registerUpliftScopes = getProgram().getRegisterUpliftProgram().getRegisterUpliftScopes();
@ -26,8 +24,10 @@ public class Pass3RegisterUpliftCombinations extends Pass2Base {
int bestScore = Integer.MAX_VALUE;
RegisterCombination bestCombination = null;
Iterator<RegisterCombination> combinationIterator = upliftScope.geCombinationIterator(getProgram().getRegisterPotentials());
while (combinationIterator.hasNext()) {
RegisterCombinationIterator combinationIterator = upliftScope.getCombinationIterator(getProgram().getRegisterPotentials());
int countCombinations = 0;
while (combinationIterator.hasNext() && countCombinations<maxCombinations) {
countCombinations++;
RegisterCombination combination = combinationIterator.next();
// Reset register allocation to original zero page allocation
new Pass3RegistersFinalize(getProgram()).allocate(false);
@ -74,6 +74,11 @@ public class Pass3RegisterUpliftCombinations extends Pass2Base {
// Save the best combination in the equivalence class
bestCombination.store(getProgram().getLiveRangeEquivalenceClassSet());
getLog().append("Uplifting [" + upliftScope.getScopeRef() + "] best " + bestScore + " combination " + bestCombination.toString());
if(combinationIterator.hasNext()) {
getLog().append("Limited combination testing to "+countCombinations+" combinations of "+combinationIterator.getNumIterations()+" possible.");
}
}
if (unknownFragments.size() > 0) {
@ -83,7 +88,9 @@ public class Pass3RegisterUpliftCombinations extends Pass2Base {
}
}
}
private int getAsmScore(Program program) {
int score = 0;
AsmProgram asm = program.getAsm();

View File

@ -1,5 +1,6 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.asm.AsmFragment;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.parser.AsmClobber;
import dk.camelot64.kickc.icl.*;
@ -132,6 +133,8 @@ public class Pass3RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
alwaysClobbered.add(RegisterAllocation.getRegisterX());
alwaysClobbered.add(RegisterAllocation.getRegisterY());
Set<String> unknownFragments = new LinkedHashSet<>();
while (combinations.hasNext()) {
RegisterCombination combination = combinations.next();
// Reset register allocation to original zero page allocation
@ -142,7 +145,17 @@ public class Pass3RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
AsmProgram asm = new AsmProgram();
asm.startSegment(statement.getIndex(), statement.toString(getProgram()));
Pass3CodeGeneration.AsmCodegenAluState aluState = new Pass3CodeGeneration.AsmCodegenAluState();
(new Pass3CodeGeneration(getProgram())).generateStatementAsm(asm, block, statement, aluState, false);
try {
(new Pass3CodeGeneration(getProgram())).generateStatementAsm(asm, block, statement, aluState, false);
} catch (AsmFragment.UnknownFragmentException e) {
unknownFragments.add(e.getFragmentSignature());
StringBuilder msg = new StringBuilder();
msg.append("Potential register analysis " + statement );
msg.append(" missing fragment " + e.getFragmentSignature());
msg.append(" allocation: ").append(combination.toString());
getLog().append(msg.toString());
continue;
}
AsmClobber clobber = asm.getClobber();
Collection<RegisterAllocation.Register> clobberRegisters = Pass3AssertNoCpuClobber.getClobberRegisters(clobber);
Iterator<RegisterAllocation.Register> alwaysClobberIt = alwaysClobbered.iterator();
@ -157,6 +170,15 @@ public class Pass3RegisterUpliftPotentialRegisterAnalysis extends Pass2Base {
break;
}
}
if (unknownFragments.size() > 0) {
getLog().append("MISSING FRAGMENTS");
for (String unknownFragment : unknownFragments) {
getLog().append(" " + unknownFragment);
}
//throw new RuntimeException("Missing fragments!");
}
return alwaysClobbered;
}

View File

@ -0,0 +1,115 @@
package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.asm.AsmFragment;
import dk.camelot64.kickc.asm.AsmProgram;
import dk.camelot64.kickc.asm.AsmSegment;
import dk.camelot64.kickc.icl.*;
import java.util.*;
/*** For eac non-uplifted equivalence class attempt to put it in a register */
public class Pass3RegisterUpliftRemains extends Pass2Base {
public Pass3RegisterUpliftRemains(Program program) {
super(program);
}
public void performUplift() {
LiveRangeEquivalenceClassSet equivalenceClassSet = getProgram().getLiveRangeEquivalenceClassSet();
List<LiveRangeEquivalenceClass> equivalenceClasses = new ArrayList<>(equivalenceClassSet.getEquivalenceClasses());
final VariableRegisterWeights registerWeights = getProgram().getVariableRegisterWeights();
Collections.sort(equivalenceClasses, new Comparator<LiveRangeEquivalenceClass>() {
@Override
public int compare(LiveRangeEquivalenceClass o1, LiveRangeEquivalenceClass o2) {
return Double.compare(registerWeights.getTotalWeight(o2), registerWeights.getTotalWeight(o1));
}
});
Set<String> unknownFragments = new LinkedHashSet<>();
for (LiveRangeEquivalenceClass equivalenceClass : equivalenceClasses) {
if (equivalenceClass.getRegister().getType().equals(RegisterAllocation.RegisterType.ZP_BYTE)) {
int bestScore = Integer.MAX_VALUE;
RegisterCombination bestCombination = null;
RegisterCombinationIterator combinationIterator = new RegisterCombinationIterator(Arrays.asList(equivalenceClass), getProgram().getRegisterPotentials());
while (combinationIterator.hasNext()) {
RegisterCombination combination = combinationIterator.next();
// Reset register allocation to original zero page allocation
new Pass3RegistersFinalize(getProgram()).allocate(false);
// Apply the uplift combination
combination.allocate(getProgram().getAllocation());
// Generate ASM
try {
new Pass3CodeGeneration(getProgram()).generate();
} catch (AsmFragment.UnknownFragmentException e) {
unknownFragments.add(e.getFragmentSignature());
StringBuilder msg = new StringBuilder();
msg.append("Uplift remains attempt [" + equivalenceClass + "] ");
msg.append("missing fragment " + e.getFragmentSignature());
msg.append(" allocation: ").append(combination.toString());
getLog().append(msg.toString());
continue;
} catch (AsmFragment.AluNotApplicableException e) {
StringBuilder msg = new StringBuilder();
msg.append("Uplift remains attempt [" + equivalenceClass + "] ");
msg.append("alu not applicable");
msg.append(" allocation: ").append(combination.toString());
getLog().append(msg.toString());
continue;
}
// If no clobber - Find value of the resulting allocation
boolean hasClobberProblem = new Pass3AssertNoCpuClobber(getProgram()).hasClobberProblem(false);
int combinationScore = getAsmScore(getProgram());
StringBuilder msg = new StringBuilder();
msg.append("Uplift remains attempt [" + equivalenceClass + "] ");
if (hasClobberProblem) {
msg.append("clobber");
} else {
msg.append(combinationScore);
}
msg.append(" allocation: ").append(combination.toString());
getLog().append(msg.toString());
if (!hasClobberProblem) {
if (combinationScore < bestScore) {
bestScore = combinationScore;
bestCombination = combination;
}
}
}
// Save the best combination in the equivalence class
bestCombination.store(equivalenceClassSet);
getLog().append("Uplifting remains [" + equivalenceClass + "] best " + bestScore + " combination " + bestCombination.toString());
}
}
if (unknownFragments.size() > 0) {
getLog().append("MISSING FRAGMENTS");
for (String unknownFragment : unknownFragments) {
getLog().append(" " + unknownFragment);
}
}
}
private int getAsmScore(Program program) {
int score = 0;
AsmProgram asm = program.getAsm();
ControlFlowGraph graph = program.getGraph();
NaturalLoopSet loopSet = program.getLoopSet();
for (AsmSegment asmSegment : asm.getSegments()) {
double asmSegmentCycles = asmSegment.getCycles();
if (asmSegmentCycles > 0) {
Integer statementIdx = asmSegment.getStatementIdx();
ControlFlowBlock block = graph.getBlockFromStatementIdx(statementIdx);
int maxLoopDepth = loopSet.getMaxLoopDepth(block.getLabel());
score += asmSegmentCycles * Math.pow(10, maxLoopDepth);
}
}
return score;
}
}

View File

@ -24,6 +24,10 @@ public class TestCompilationOutput extends TestCase {
helper = new ReferenceHelper("dk/camelot64/kickc/test/ref/");
}
public void testVoronoi() throws IOException, URISyntaxException {
compileAndCompare("voronoi");
}
public void testFlipper() throws IOException, URISyntaxException {
compileAndCompare("flipper-rex2");
}

View File

@ -0,0 +1,198 @@
BBEGIN:
jsr main
BEND:
main:
addpoint_from_main:
lda #1
sta 2
ldx #5
ldy #0
lda #5
jsr addpoint
main__B3:
addpoint_from_B3:
lda #2
sta 2
ldx #8
ldy #1
lda #15
jsr addpoint
main__B4:
addpoint_from_B4:
lda #3
sta 2
ldx #14
ldy #2
lda #6
jsr addpoint
main__B5:
addpoint_from_B5:
lda #4
sta 2
ldx #2
ldy #3
lda #34
jsr addpoint
main__B6:
addpoint_from_B6:
lda #5
sta 2
ldx #17
ldy #4
lda #21
jsr addpoint
main__B7:
addpoint_from_B7:
lda #7
sta 2
ldx #22
ldy #5
lda #31
jsr addpoint
main__B1:
jsr render
main__B9:
jmp main__B1
main__Breturn:
rts
render:
render__B1_from_render:
lda #<1024
sta 5
lda #>1024
sta 5+1
lda #<55296
sta 3
lda #>55296
sta 3+1
lda #0
sta 2
render__B1_from_B3:
render__B1:
render__B2_from_B1:
ldy #0
render__B2_from_B5:
render__B2:
sty 10
lda 2
sta 11
jsr findcol
render__B5:
lda 9
sta (3),y
lda #230
sta (5),y
iny
cpy #40
bcc render__B2_from_B5
render__B3:
lda 5
clc
adc #40
sta 5
bcc !+
inc 5+1
!:
lda 3
clc
adc #40
sta 3
bcc !+
inc 3+1
!:
inc 2
lda 2
cmp #25
bcc render__B1_from_B3
render__Breturn:
rts
findcol:
findcol__B1_from_findcol:
lda #0
sta 9
lda #255
sta 7
ldx #0
findcol__B1_from_B13:
findcol__B1:
lda 4096,x
sta 8
lda 4352,x
sta 12
lda 10
cmp 8
beq findcol__B2
findcol__B3:
lda 10
cmp 8
bcc findcol__B6
findcol__B7:
lda 10
sec
sbc 8
sta 8
findcol__B8_from_B7:
findcol__B8:
lda 11
cmp 12
bcc findcol__B9
findcol__B10:
lda 11
sec
sbc 12
clc
adc 8
sta 8
findcol__B11_from_B10:
findcol__B11:
lda 8
cmp 7
bcc findcol__B12
findcol__B13_from_B11:
findcol__B13:
inx
cpx #6
bcc findcol__B1_from_B13
findcol__Breturn_from_B13:
jmp findcol__Breturn
findcol__Breturn_from_B2:
lda #0
sta 9
findcol__Breturn:
rts
findcol__B12:
lda 4608,x
sta 9
lda 8
sta 7
findcol__B13_from_B12:
jmp findcol__B13
findcol__B9:
lda 12
sec
sbc 11
clc
adc 8
sta 8
findcol__B11_from_B9:
jmp findcol__B11
findcol__B6:
lda 8
sec
sbc 10
sta 8
findcol__B8_from_B6:
jmp findcol__B8
findcol__B2:
lda 11
cmp 12
beq findcol__Breturn_from_B2
jmp findcol__B3
addpoint:
sta 4096,y
txa
sta 4352,y
lda 2
sta 4608,y
addpoint__Breturn:
rts

View File

@ -0,0 +1,124 @@
@BEGIN: from
[0] call main param-assignment [ findcol::return#0 ]
to:@END
@END: from @BEGIN
main: from @BEGIN
[1] call addpoint param-assignment [ findcol::return#0 ]
to:main::@3
main::@3: from main
[2] call addpoint param-assignment [ findcol::return#0 ]
to:main::@4
main::@4: from main::@3
[3] call addpoint param-assignment [ findcol::return#0 ]
to:main::@5
main::@5: from main::@4
[4] call addpoint param-assignment [ findcol::return#0 ]
to:main::@6
main::@6: from main::@5
[5] call addpoint param-assignment [ findcol::return#0 ]
to:main::@7
main::@7: from main::@6
[6] call addpoint param-assignment [ findcol::return#0 ]
to:main::@1
main::@1: from main::@7 main::@9
[7] call render param-assignment [ findcol::return#0 ]
to:main::@9
main::@9: from main::@1
[8] if(true) goto main::@1 [ findcol::return#0 ]
to:main::@return
main::@return: from main::@9
[9] return [ findcol::return#0 ]
to:@RETURN
render: from main::@1
to:render::@1
render::@1: from render render::@3
[10] (byte*) render::chrline#2 ← phi( render/(word) 1024 render::@3/(byte*) render::chrline#1 ) [ render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[10] (byte*) render::colline#2 ← phi( render/(word) 55296 render::@3/(byte*) render::colline#1 ) [ render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[10] (byte) render::y#2 ← phi( render/(byte) 0 render::@3/(byte) render::y#1 ) [ render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
to:render::@2
render::@2: from render::@1 render::@5
[11] (byte) render::x#2 ← phi( render::@1/(byte) 0 render::@5/(byte) render::x#1 ) [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[12] (byte) findcol::x#0 ← (byte) render::x#2 [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 findcol::x#0 ]
[13] (byte) findcol::y#0 ← (byte) render::y#2 [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 findcol::x#0 findcol::y#0 ]
[14] call findcol param-assignment [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 findcol::x#0 findcol::y#0 ]
to:render::@5
render::@5: from render::@2
[15] (byte) render::col#0 ← (byte) findcol::return#0 [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::col#0 render::chrline#2 ]
[16] *((byte*) render::colline#2 + (byte) render::x#2) ← (byte) render::col#0 [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[17] *((byte*) render::chrline#2 + (byte) render::x#2) ← (byte) 230 [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[18] (byte) render::x#1 ← ++ (byte) render::x#2 [ render::x#1 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
[19] if((byte) render::x#1<(byte) 40) goto render::@2 [ render::x#1 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 ]
to:render::@3
render::@3: from render::@5
[20] (byte*) render::chrline#1 ← (byte*) render::chrline#2 + (byte) 40 [ render::chrline#1 render::y#2 findcol::return#0 render::colline#2 ]
[21] (byte*) render::colline#1 ← (byte*) render::colline#2 + (byte) 40 [ render::colline#1 render::chrline#1 render::y#2 findcol::return#0 ]
[22] (byte) render::y#1 ← ++ (byte) render::y#2 [ render::y#1 render::colline#1 render::chrline#1 findcol::return#0 ]
[23] if((byte) render::y#1<(byte) 25) goto render::@1 [ render::y#1 render::colline#1 render::chrline#1 findcol::return#0 ]
to:render::@return
render::@return: from render::@3
[24] return [ findcol::return#0 ]
to:@RETURN
findcol: from render::@2
to:findcol::@1
findcol::@1: from findcol findcol::@13
[25] (byte) findcol::mincol#11 ← phi( findcol/(byte) 0 findcol::@13/(byte) findcol::mincol#2 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::mindiff#10 findcol::mincol#11 ]
[25] (byte) findcol::mindiff#10 ← phi( findcol/(byte) 255 findcol::@13/(byte) findcol::mindiff#11 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::mindiff#10 findcol::mincol#11 ]
[25] (byte) findcol::i#12 ← phi( findcol/(byte) 0 findcol::@13/(byte) findcol::i#1 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::mindiff#10 findcol::mincol#11 ]
[26] (byte) findcol::xp#0 ← (word) 4096 *idx (byte) findcol::i#12 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::mindiff#10 findcol::mincol#11 ]
[27] (byte) findcol::yp#0 ← (word) 4352 *idx (byte) findcol::i#12 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
[28] if((byte) findcol::x#0==(byte) findcol::xp#0) goto findcol::@2 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@3
findcol::@3: from findcol::@1 findcol::@2
[29] if((byte) findcol::x#0<(byte) findcol::xp#0) goto findcol::@6 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@7
findcol::@7: from findcol::@3
[30] (byte) findcol::diff#1 ← (byte) findcol::x#0 - (byte) findcol::xp#0 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::diff#1 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@8
findcol::@8: from findcol::@6 findcol::@7
[31] (byte) findcol::diff#4 ← phi( findcol::@6/(byte) findcol::diff#0 findcol::@7/(byte) findcol::diff#1 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::yp#0 findcol::diff#4 findcol::mindiff#10 findcol::mincol#11 ]
[32] if((byte) findcol::y#0<(byte) findcol::yp#0) goto findcol::@9 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::yp#0 findcol::diff#4 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@10
findcol::@10: from findcol::@8
[33] (byte~) findcol::$10 ← (byte) findcol::y#0 - (byte) findcol::yp#0 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#4 findcol::$10 findcol::mindiff#10 findcol::mincol#11 ]
[34] (byte) findcol::diff#3 ← (byte) findcol::diff#4 + (byte~) findcol::$10 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#3 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@11
findcol::@11: from findcol::@10 findcol::@9
[35] (byte) findcol::diff#6 ← phi( findcol::@10/(byte) findcol::diff#3 findcol::@9/(byte) findcol::diff#2 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#6 findcol::mindiff#10 findcol::mincol#11 ]
[36] if((byte) findcol::diff#6<(byte) findcol::mindiff#10) goto findcol::@12 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#6 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@13
findcol::@13: from findcol::@11 findcol::@12
[37] (byte) findcol::mindiff#11 ← phi( findcol::@11/(byte) findcol::mindiff#10 findcol::@12/(byte~) findcol::diff#13 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::mindiff#11 findcol::mincol#2 findcol::i#12 findcol::x#0 findcol::y#0 ]
[37] (byte) findcol::mincol#2 ← phi( findcol::@11/(byte) findcol::mincol#11 findcol::@12/(byte) findcol::mincol#1 ) [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::mindiff#11 findcol::mincol#2 findcol::i#12 findcol::x#0 findcol::y#0 ]
[38] (byte) findcol::i#1 ← ++ (byte) findcol::i#12 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#1 findcol::mindiff#11 findcol::mincol#2 findcol::x#0 findcol::y#0 ]
[39] if((byte) findcol::i#1<(byte) 6) goto findcol::@1 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#1 findcol::mindiff#11 findcol::mincol#2 findcol::x#0 findcol::y#0 ]
to:findcol::@return
findcol::@return: from findcol::@13 findcol::@2
[40] (byte) findcol::return#0 ← phi( findcol::@13/(byte) findcol::mincol#2 findcol::@2/(byte) 0 ) [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 findcol::x#0 findcol::y#0 ]
[41] return [ render::x#2 render::y#2 findcol::return#0 render::colline#2 render::chrline#2 findcol::x#0 findcol::y#0 ]
to:@RETURN
findcol::@12: from findcol::@11
[42] (byte) findcol::mincol#1 ← (word) 4608 *idx (byte) findcol::i#12 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#6 findcol::mincol#1 ]
[43] (byte~) findcol::diff#13 ← (byte) findcol::diff#6 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::mincol#1 findcol::diff#13 ]
to:findcol::@13
findcol::@9: from findcol::@8
[44] (byte~) findcol::$8 ← (byte) findcol::yp#0 - (byte) findcol::y#0 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#4 findcol::mindiff#10 findcol::mincol#11 findcol::$8 ]
[45] (byte) findcol::diff#2 ← (byte) findcol::diff#4 + (byte~) findcol::$8 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::y#0 findcol::diff#2 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@11
findcol::@6: from findcol::@3
[46] (byte) findcol::diff#0 ← (byte) findcol::xp#0 - (byte) findcol::x#0 [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::diff#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@8
findcol::@2: from findcol::@1
[47] if((byte) findcol::y#0==(byte) findcol::yp#0) goto findcol::@return [ render::x#2 render::y#2 render::colline#2 render::chrline#2 findcol::i#12 findcol::x#0 findcol::xp#0 findcol::y#0 findcol::yp#0 findcol::mindiff#10 findcol::mincol#11 ]
to:findcol::@3
addpoint: from main main::@3 main::@4 main::@5 main::@6 main::@7
[48] (byte) addpoint::c#6 ← phi( main/(byte) 1 main::@3/(byte) 2 main::@4/(byte) 3 main::@5/(byte) 4 main::@6/(byte) 5 main::@7/(byte) 7 ) [ findcol::return#0 addpoint::idx#6 addpoint::x#6 addpoint::y#6 addpoint::c#6 ]
[48] (byte) addpoint::y#6 ← phi( main/(byte) 5 main::@3/(byte) 8 main::@4/(byte) 14 main::@5/(byte) 2 main::@6/(byte) 17 main::@7/(byte) 22 ) [ findcol::return#0 addpoint::idx#6 addpoint::x#6 addpoint::y#6 addpoint::c#6 ]
[48] (byte) addpoint::idx#6 ← phi( main/(byte) 0 main::@3/(byte) 1 main::@4/(byte) 2 main::@5/(byte) 3 main::@6/(byte) 4 main::@7/(byte) 5 ) [ findcol::return#0 addpoint::idx#6 addpoint::x#6 addpoint::y#6 addpoint::c#6 ]
[48] (byte) addpoint::x#6 ← phi( main/(byte) 5 main::@3/(byte) 15 main::@4/(byte) 6 main::@5/(byte) 34 main::@6/(byte) 21 main::@7/(byte) 31 ) [ findcol::return#0 addpoint::idx#6 addpoint::x#6 addpoint::y#6 addpoint::c#6 ]
[49] *((word) 4096 + (byte) addpoint::idx#6) ← (byte) addpoint::x#6 [ findcol::return#0 addpoint::idx#6 addpoint::y#6 addpoint::c#6 ]
[50] *((word) 4352 + (byte) addpoint::idx#6) ← (byte) addpoint::y#6 [ findcol::return#0 addpoint::idx#6 addpoint::c#6 ]
[51] *((word) 4608 + (byte) addpoint::idx#6) ← (byte) addpoint::c#6 [ findcol::return#0 ]
to:addpoint::@return
addpoint::@return: from addpoint
[52] return [ findcol::return#0 ]
to:@RETURN

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
(label) @BEGIN
(label) @END
(byte*) COLORS
(byte[256]) COLS
(byte) FILL
(byte*) SCREEN
(byte[256]) XPOS
(byte[256]) YPOS
(void()) addpoint((byte) addpoint::idx , (byte) addpoint::x , (byte) addpoint::y , (byte) addpoint::c)
(label) addpoint::@return
(byte) addpoint::c
(byte) addpoint::c#6 zp byte:2 0.6666666666666666
(byte) addpoint::idx
(byte) addpoint::idx#6 reg byte y 2.0
(byte) addpoint::x
(byte) addpoint::x#6 reg byte a 2.0
(byte) addpoint::y
(byte) addpoint::y#6 reg byte x 1.0
(byte()) findcol((byte) findcol::x , (byte) findcol::y)
(byte~) findcol::$10 reg byte a 20002.0
(byte~) findcol::$8 reg byte a 20002.0
(label) findcol::@1
(label) findcol::@10
(label) findcol::@11
(label) findcol::@12
(label) findcol::@13
(label) findcol::@2
(label) findcol::@3
(label) findcol::@6
(label) findcol::@7
(label) findcol::@8
(label) findcol::@9
(label) findcol::@return
(byte) findcol::diff
(byte) findcol::diff#0 zp byte:8 20002.0
(byte) findcol::diff#1 zp byte:8 20002.0
(byte~) findcol::diff#13 zp byte:7 20002.0
(byte) findcol::diff#2 zp byte:8 20002.0
(byte) findcol::diff#3 zp byte:8 20002.0
(byte) findcol::diff#4 zp byte:8 10001.0
(byte) findcol::diff#6 zp byte:8 13334.666666666666
(byte) findcol::i
(byte) findcol::i#1 reg byte x 15001.5
(byte) findcol::i#12 reg byte x 2631.842105263158
(byte) findcol::mincol
(byte) findcol::mincol#1 zp byte:9 10001.0
(byte) findcol::mincol#11 zp byte:9 1250.125
(byte) findcol::mincol#2 zp byte:9 13334.666666666666
(byte) findcol::mindiff
(byte) findcol::mindiff#10 zp byte:7 1875.1875
(byte) findcol::mindiff#11 zp byte:7 10001.0
(byte) findcol::return
(byte) findcol::return#0 zp byte:9 343.8125
(byte) findcol::x
(byte) findcol::x#0 zp byte:10 1577.1153846153845
(byte) findcol::xp
(byte) findcol::xp#0 zp byte:8 10001.0
(byte) findcol::y
(byte) findcol::y#0 zp byte:11 1640.2
(byte) findcol::yp
(byte) findcol::yp#0 zp byte:12 6250.625
(void()) main()
(label) main::@1
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@6
(label) main::@7
(label) main::@9
(label) main::@return
(byte) numpoints
(void()) render()
(label) render::@1
(label) render::@2
(label) render::@3
(label) render::@5
(label) render::@return
(byte*) render::chrline
(byte*) render::chrline#1 zp ptr byte:5 50.5
(byte*) render::chrline#2 zp ptr byte:5 36.45454545454545
(byte) render::col
(byte) render::col#0 reg byte a 2002.0
(byte*) render::colline
(byte*) render::colline#1 zp ptr byte:3 67.33333333333333
(byte*) render::colline#2 zp ptr byte:3 35.38235294117647
(byte) render::x
(byte) render::x#1 reg byte y 1501.5
(byte) render::x#2 reg byte y 166.83333333333334
(byte) render::y
(byte) render::y#1 zp byte:2 151.5
(byte) render::y#2 zp byte:2 34.371428571428574
zp byte:2 [ render::y#2 render::y#1 addpoint::c#6 ]
zp ptr byte:3 [ render::colline#2 render::colline#1 ]
zp ptr byte:5 [ render::chrline#2 render::chrline#1 ]
reg byte y [ render::x#2 render::x#1 ]
reg byte x [ findcol::i#12 findcol::i#1 ]
zp byte:7 [ findcol::mindiff#10 findcol::mindiff#11 findcol::diff#13 ]
zp byte:8 [ findcol::diff#4 findcol::diff#0 findcol::diff#1 findcol::diff#6 findcol::diff#3 findcol::diff#2 findcol::xp#0 ]
zp byte:9 [ findcol::return#0 findcol::mincol#11 findcol::mincol#2 findcol::mincol#1 ]
reg byte a [ addpoint::x#6 ]
reg byte y [ addpoint::idx#6 ]
reg byte x [ addpoint::y#6 ]
zp byte:10 [ findcol::x#0 ]
zp byte:11 [ findcol::y#0 ]
reg byte a [ render::col#0 ]
zp byte:12 [ findcol::yp#0 ]
reg byte a [ findcol::$10 ]
reg byte a [ findcol::$8 ]

View File

@ -0,0 +1,82 @@
// The screen
byte *SCREEN = $0400;
byte *COLORS = $D800;
byte FILL = 230;
// The total number of voronoi points
byte numpoints = 6;
// Points to create the Voronoi from
byte[$100] XPOS = $1000;
byte[$100] YPOS = $1100;
byte[$100] COLS = $1200;
main();
void main() {
addpoint(0, 5, 5, 1);
addpoint(1, 15, 8, 2);
addpoint(2, 6, 14, 3);
addpoint(3, 34, 2, 4);
addpoint(4, 21, 17, 5);
addpoint(5, 31, 22, 7);
do {
render();
} while(true)
}
void addpoint(byte idx, byte x, byte y, byte c) {
XPOS[idx] = x;
YPOS[idx] = y;
COLS[idx] = c;
}
void render() {
byte* chrline = SCREEN;
byte* colline = COLORS;
byte y=0;
do {
byte x=0;
do {
byte col = findcol(x, y);
colline[x] = col;
chrline[x] = FILL;
} while(++x < 40)
chrline = chrline+40;
colline = colline+40;
} while(++y < 25)
}
byte findcol(byte x, byte y) {
byte mindiff = 255;
byte mincol = 0;
byte i=0;
do {
byte xp = XPOS[i];
byte yp = YPOS[i];
if(x==xp) {
if(y==yp) {
return 0;
}
}
byte diff;
if(x<xp) {
diff = xp-x;
} else {
diff = x-xp;
}
if(y<yp) {
diff = diff + (yp-y);
} else {
diff = diff + (y-yp);
}
if(diff<mindiff) {
mindiff=diff;
mincol = COLS[i];
}
} while(++i<numpoints)
return mincol;
}