1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-09-08 17:54:40 +00:00

Implemented most of flipper in KickC

This commit is contained in:
Jesper Gravgaard 2017-07-13 00:13:26 +02:00
parent b25be31ba1
commit 8d7dfa8a8d
25 changed files with 235 additions and 58 deletions

View File

@ -0,0 +1,40 @@
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.
- Implement Register Allocation (that utilize real registers - and non-zeropage memory)
- Add Fixed Point number types
- Create a proper main function for the compiler
- Add for loop
- Add imports
- Add structs
- 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.
- Add ability to call KC code from ASM. (maybe declare some functions external to ensure their interface is well defined. Maybe generate ASM call stubs.)
- Add inline ASM (maybe?)
Process/Code Structure Improvement
- Make each phase return a separate object graph (allowing for keeping the history in memory & performing rollbacks)
- Implemenent Assertions for the output of different phases (ensuring that the result of the phase is consistent)
- Refactor Expression Operator Implementation & Evaluation into one class per operator
Testing
- Test that the parse tree for specific KC syntax is as expected. Use a print function for the parse tree to generate output for comparison.
- Test the ICL result of a specific phase on a specific ICL input. Create an ICL syntax for parsing directly to ICL and a printer for the syntax.
- Test the ASM program output resulting from compiling specific KC program input.
- Emulate/Run the ASM for a specific KC program compiled. Compare the emulated ASM output to output calculated by executing directly on the KC tree.
- Add assert statements to the language. Create KC programs that test the compiler by compiling, running and testing assertions.
Optimizations
- Optimize register allocation by combining with knowledge of ASM program cost (bytes/cycles) and different ASM fragments with different clobbering.
- Optimize by finding optimal sequence for multiple phi assignments in entry-segments.
- 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.
Usages
- Implement library for memory allocation in main memory
- Implement library for output on the screen (using basic functions)
Real Usage
- Implement library for fast multiply (mul.asm)
- Implement spline library (spline.asm)
- Implement polygon filler for complex polygons.
- Implement true type font renderer.

View File

@ -127,7 +127,10 @@ public class AsmFragment {
}
if (conditionalJump.getRValue2() instanceof ConstantInteger && ((ConstantInteger) conditionalJump.getRValue2()).getNumber() == 0) {
signature.append("0");
} else {
} else if (conditionalJump.getRValue2() instanceof ConstantBool) {
ConstantBool boolValue = (ConstantBool) conditionalJump.getRValue2();
signature.append(boolValue.toString());
} else{
signature.append(bind(conditionalJump.getRValue2()));
}
signature.append("_then_");
@ -135,7 +138,7 @@ public class AsmFragment {
ControlFlowBlock destinationBlock = graph.getBlock(destination);
String destinationLabel = destination.getFullName();
if (destinationBlock.hasPhiStatements()) {
destinationLabel = destination.getFullName() + "_from_" + block.getLabel().getFullName();
destinationLabel = (destinationBlock.getLabel().getLocalName() + "_from_" + block.getLabel().getLocalName()).replace('@', 'B').replace(':','_');
}
signature.append(bind(new Label(destinationLabel, destination.getScope(),false)));
return signature.toString();
@ -348,7 +351,7 @@ public class AsmFragment {
bound = Integer.toString(boundInt.getNumber());
}
} else if (boundValue instanceof Label) {
bound = ((Label) boundValue).getFullName().replace('@', 'B');
bound = ((Label) boundValue).getFullName().replace('@', 'B').replace(':','_');
} else {
throw new RuntimeException("Bound Value Type not implemented " + boundValue);
}

View File

@ -0,0 +1,2 @@
lda {zpby1}
sta {coptr1}

View File

@ -0,0 +1,2 @@
txa
sta {cowo1},x

View File

@ -0,0 +1 @@
sta {cowo1},y

View File

@ -0,0 +1,3 @@
ldy {zpby1}
tya
sta {cowo1},y

View File

@ -0,0 +1 @@
sta ({zpptrby1}),y

View File

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

View File

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

View File

@ -0,0 +1 @@
iny

View File

@ -0,0 +1,2 @@
cpy #{coby1}
bcc {la1}

View File

@ -0,0 +1,3 @@
ldy {zpby2}
lda {cowo1},y
sta {zpby1}

View File

@ -0,0 +1 @@
stx {zpby1}

View File

@ -0,0 +1,2 @@
lda {zpby1}
bne {la1}

View File

@ -151,7 +151,9 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
}
procedure.setParameters(parameterList);
sequence.addStatement(new StatementProcedureBegin(procedure));
this.visit(ctx.stmtSeq());
if(ctx.stmtSeq()!=null) {
this.visit(ctx.stmtSeq());
}
sequence.addStatement(new StatementLabel(procExit));
if(returnVar!=null) {
sequence.addStatement(new StatementAssignment(returnVar, returnVar));
@ -285,7 +287,13 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitExprCall(KickCParser.ExprCallContext ctx) {
List<RValue> parameters = (List<RValue>) this.visit(ctx.parameterList());
List<RValue> parameters;
KickCParser.ParameterListContext parameterList = ctx.parameterList();
if(parameterList!=null) {
parameters = (List<RValue>) this.visit(parameterList);
} else {
parameters = new ArrayList<>();
}
VariableIntermediate tmpVar = getCurrentSymbols().addVariableIntermediate();
sequence.addStatement(new StatementCall(tmpVar, ctx.NAME().getText(), parameters));
return tmpVar;

View File

@ -38,7 +38,9 @@ public class Pass1ProcedureCallParameters extends ControlFlowGraphCopyVisitor {
addStatementToCurrentBlock(copyCall);
getCurrentBlock().setCallSuccessor(procedure.getLabel());
splitCurrentBlock(scope.addLabelIntermediate());
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
addStatementToCurrentBlock(new StatementAssignment(origCall.getLValue(), procReturnVar));
}
return null;
}

View File

@ -28,25 +28,26 @@ public class Pass1ProcedureCallsReturnValue extends ControlFlowGraphCopyVisitor
copyCall.setProcedure(procedure);
addStatementToCurrentBlock(copyCall);
getCurrentBlock().setCallSuccessor(procedure.getLabel());
// Find return variable final version
Label returnBlockLabel = procedure.getLabel("@return");
ControlFlowBlock returnBlock = graph.getBlock(returnBlockLabel);
VariableVersion returnVarFinal = null;
for (Statement statement : returnBlock.getStatements()) {
if (statement instanceof StatementReturn) {
StatementReturn statementReturn = (StatementReturn) statement;
RValue returnValue = statementReturn.getValue();
if (returnValue instanceof VariableVersion) {
returnVarFinal = (VariableVersion) returnValue;
if(!SymbolTypeBasic.VOID.equals(procedure.getReturnType())) {
// Find return variable final version
Label returnBlockLabel = procedure.getLabel("@return");
ControlFlowBlock returnBlock = graph.getBlock(returnBlockLabel);
VariableVersion returnVarFinal = null;
for (Statement statement : returnBlock.getStatements()) {
if (statement instanceof StatementReturn) {
StatementReturn statementReturn = (StatementReturn) statement;
RValue returnValue = statementReturn.getValue();
if (returnValue instanceof VariableVersion) {
returnVarFinal = (VariableVersion) returnValue;
}
}
}
if (returnVarFinal == null) {
throw new RuntimeException("Error! Cannot find final return variable for " + procedure.getFullName());
}
StatementAssignment returnAssignment = new StatementAssignment(origCall.getLValue(), returnVarFinal);
addStatementToCurrentBlock(returnAssignment);
}
if (returnVarFinal == null) {
throw new RuntimeException("Error! Cannot find final return variable for " + procedure.getFullName());
}
StatementAssignment returnAssignment = new StatementAssignment(origCall.getLValue(), returnVarFinal);
addStatementToCurrentBlock(returnAssignment);
return null;
}

View File

@ -59,6 +59,14 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
private boolean optimizePointerDereferenceIndexed(StatementAssignment assignment) {
PointerDereferenceIndexed pointerDereferenceIndexed = (PointerDereferenceIndexed) assignment.getLValue();
if(pointerDereferenceIndexed.getPointer() instanceof ConstantInteger && pointerDereferenceIndexed.getIndex() instanceof Constant) {
ConstantInteger ptrConstant = (ConstantInteger) pointerDereferenceIndexed.getPointer();
ConstantInteger idxConstant = (ConstantInteger) pointerDereferenceIndexed.getIndex();
int newPtr = ptrConstant.getNumber() + idxConstant.getNumber();
assignment.setLValue(new PointerDereferenceSimple(new ConstantInteger(newPtr)));
System.out.println("Consolidated assigned array index constant in assignment " + assignment.getLValue());
return true;
}
if(pointerDereferenceIndexed.getPointer() instanceof ConstantInteger && pointerDereferenceIndexed.getIndex() instanceof Variable) {
Variable variable = (Variable) pointerDereferenceIndexed.getIndex();
ConstantInteger consolidated = consolidateSubConstants(variable);
@ -74,13 +82,23 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
}
private boolean optimizeArrayDeref(StatementAssignment assignment) {
if (assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof ConstantInteger) {
ConstantInteger ptrConstant = (ConstantInteger) assignment.getRValue1();
ConstantInteger idxConstant = (ConstantInteger) assignment.getRValue2();
int newPtr = ptrConstant.getNumber() + idxConstant.getNumber();
assignment.setRValue1(null);
assignment.setOperator(new Operator("*"));
assignment.setRValue2(new ConstantInteger(newPtr));
System.out.println("Consolidated referenced array index constant in assignment " + assignment.getLValue());
return true;
}
if (assignment.getRValue1() instanceof ConstantInteger && assignment.getRValue2() instanceof Variable) {
Variable variable = (Variable) assignment.getRValue2();
ConstantInteger consolidated = consolidateSubConstants(variable);
if (consolidated != null) {
ConstantInteger ptrConstant = (ConstantInteger) assignment.getRValue1();
int newPtr = ptrConstant.getNumber() + consolidated.getNumber();
assignment.setRValue1(new ConstantInteger(newPtr));
assignment.setRValue1(new ConstantInteger(newPtr));
System.out.println("Consolidated referenced array index constant in assignment " + assignment.getLValue());
return true;
}
@ -124,7 +142,7 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
* @return The consolidated constant. Null if no sub-constants were found.
*/
private ConstantInteger consolidateSubConstants(Variable variable) {
if(usages.get(variable)>1) {
if(getUsages(variable) >1) {
System.out.println("Multiple usages for variable. Not optimizing sub-constant "+variable);
return null;
}
@ -197,4 +215,10 @@ public class Pass2ConstantAdditionElimination extends Pass2SsaOptimization {
return null;
}
private Integer getUsages(Variable variable) {
Integer useCount = usages.get(variable);
if(useCount==null) useCount = 0;
return useCount;
}
}

View File

@ -56,7 +56,9 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization {
assignment.getOperator(),
(Constant) assignment.getRValue1(),
(Constant) assignment.getRValue2());
constants.put(variable, constant);
if(constant!=null) {
constants.put(variable, constant);
}
}
}
return null;
@ -110,6 +112,10 @@ public class Pass2ConstantPropagation extends Pass2SsaOptimization {
return new ConstantDouble(getDouble(c1) / getDouble(c2));
}
}
case "*idx": {
// Cannot be directly propagated
return null;
}
default:
throw new RuntimeException("Unhandled Binary Operator " + operator.getOperator());
}

View File

@ -26,7 +26,7 @@ public class Pass3BlockSequencePlanner {
}
if(sequence.contains(block)) {
// already handled - move on
break;
continue;
}
sequence.add(block);
if(block.getCallSuccessor()!=null) {

View File

@ -17,34 +17,40 @@ public class Pass3RegisterAllocation {
public void allocate() {
RegisterAllocation allocation = new RegisterAllocation();
performAllocation(symbols, allocation);
allocation.allocate(symbols.getVariable("i#0"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("i#1"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("i#2"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("i#3"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("i#4"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("i#5"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("n1#1"), RegisterAllocation.getRegisterY());
allocation.allocate(symbols.getVariable("n1#2"), RegisterAllocation.getRegisterY());
allocation.allocate(symbols.getVariable("e#2"), new RegisterAllocation.RegisterZpByte(128));
allocation.allocate(symbols.getVariable("e#3"), new RegisterAllocation.RegisterZpByte(128));
allocation.allocate(symbols.getVariable("e#4"), new RegisterAllocation.RegisterZpByte(128));
allocation.allocate(symbols.getVariable("e#5"), new RegisterAllocation.RegisterZpByte(128));
allocation.allocate(symbols.getVariable("idx#2"), new RegisterAllocation.RegisterZpWord(129));
allocation.allocate(symbols.getVariable("idx#3"), new RegisterAllocation.RegisterZpWord(129));
allocation.allocate(symbols.getVariable("idx#4"), new RegisterAllocation.RegisterZpWord(129));
allocation.allocate(symbols.getVariable("idx#5"), new RegisterAllocation.RegisterZpWord(129));
allocation.allocate(symbols.getVariable("x#2"), new RegisterAllocation.RegisterZpByte(131));
allocation.allocate(symbols.getVariable("x#5"), new RegisterAllocation.RegisterZpByte(131));
allocation.allocate(symbols.getVariable("y#1"), new RegisterAllocation.RegisterZpByte(132));
allocation.allocate(symbols.getVariable("y#2"), new RegisterAllocation.RegisterZpByte(132));
allocation.allocate(symbols.getVariable("y#5"), new RegisterAllocation.RegisterZpByte(132));
allocation.allocate(symbols.getVariable("cursor#2"), new RegisterAllocation.RegisterZpPointerByte(133));
allocation.allocate(symbols.getVariable("cursor#3"), new RegisterAllocation.RegisterZpPointerByte(133));
allocation.allocate(symbols.getVariable("cursor#4"), new RegisterAllocation.RegisterZpPointerByte(133));
allocation.allocate(symbols.getVariable("cursor#5"), new RegisterAllocation.RegisterZpPointerByte(133));
allocation.allocate(symbols.getVariable("ptr#1"), new RegisterAllocation.RegisterZpPointerByte(135));
allocation.allocate(symbols.getVariable("ptr#2"), new RegisterAllocation.RegisterZpPointerByte(135));
allocation.allocate(symbols.getVariable("ptr#3"), new RegisterAllocation.RegisterZpPointerByte(135));
//allocation.allocate(symbols.getVariable("i#0"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#1"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#2"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#3"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#4"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#5"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#6"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("i#7"), RegisterAllocation.getRegisterX());
//allocation.allocate(symbols.getVariable("n1#1"), RegisterAllocation.getRegisterY());
//allocation.allocate(symbols.getVariable("n1#2"), RegisterAllocation.getRegisterY());
//allocation.allocate(symbols.getVariable("e#2"), new RegisterAllocation.RegisterZpByte(128));
//allocation.allocate(symbols.getVariable("e#3"), new RegisterAllocation.RegisterZpByte(128));
//allocation.allocate(symbols.getVariable("e#4"), new RegisterAllocation.RegisterZpByte(128));
//allocation.allocate(symbols.getVariable("e#5"), new RegisterAllocation.RegisterZpByte(128));
//allocation.allocate(symbols.getVariable("idx#2"), new RegisterAllocation.RegisterZpWord(129));
//allocation.allocate(symbols.getVariable("idx#3"), new RegisterAllocation.RegisterZpWord(129));
//allocation.allocate(symbols.getVariable("idx#4"), new RegisterAllocation.RegisterZpWord(129));
//allocation.allocate(symbols.getVariable("idx#5"), new RegisterAllocation.RegisterZpWord(129));
//allocation.allocate(symbols.getVariable("x#0"), new RegisterAllocation.RegisterYByte());
//allocation.allocate(symbols.getVariable("x#1"), new RegisterAllocation.RegisterYByte());
//allocation.allocate(symbols.getVariable("x#2"), new RegisterAllocation.RegisterYByte());
//allocation.allocate(symbols.getVariable("x#5"), new RegisterAllocation.RegisterZpByte(131));
//allocation.allocate(symbols.getVariable("y#0"), new RegisterAllocation.RegisterZpByte(132));
//allocation.allocate(symbols.getVariable("y#1"), new RegisterAllocation.RegisterZpByte(132));
//allocation.allocate(symbols.getVariable("y#2"), new RegisterAllocation.RegisterZpByte(132));
//allocation.allocate(symbols.getVariable("y#5"), new RegisterAllocation.RegisterZpByte(132));
//allocation.allocate(symbols.getVariable("cursor#2"), new RegisterAllocation.RegisterZpPointerByte(133));
//allocation.allocate(symbols.getVariable("cursor#3"), new RegisterAllocation.RegisterZpPointerByte(133));
//allocation.allocate(symbols.getVariable("cursor#4"), new RegisterAllocation.RegisterZpPointerByte(133));
//allocation.allocate(symbols.getVariable("cursor#5"), new RegisterAllocation.RegisterZpPointerByte(133));
//allocation.allocate(symbols.getVariable("ptr#1"), new RegisterAllocation.RegisterZpPointerByte(135));
//allocation.allocate(symbols.getVariable("ptr#2"), new RegisterAllocation.RegisterZpPointerByte(135));
//allocation.allocate(symbols.getVariable("ptr#3"), new RegisterAllocation.RegisterZpPointerByte(135));
//allocation.allocate(symbols.getVariable("v#1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("v#2"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("v#3"), new RegisterAllocation.RegisterAByte());
@ -56,14 +62,39 @@ public class Pass3RegisterAllocation {
//allocation.allocate(symbols.getVariable("$1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$3"), new RegisterAllocation.RegisterALUByte());
//allocation.allocate(symbols.getVariable("$4"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$5"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("$6"), new RegisterAllocation.RegisterALUByte());
//allocation.allocate(symbols.getVariable("$7"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("inc::a#2"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("bv#0"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("sum::b#0"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("inc::b#1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("sum::b#0"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("inc::b#1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("a#1"), new RegisterAllocation.RegisterAByte());
//allocation.allocate(symbols.getVariable("a#0"), new RegisterAllocation.RegisterAByte());
allocation.allocate(symbols.getVariable("plot::i#0"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("plot::i#1"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("plot::i#2"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("plot::i#3"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("plot::i#4"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("plot::x#0"), RegisterAllocation.getRegisterY());
allocation.allocate(symbols.getVariable("plot::x#1"), RegisterAllocation.getRegisterY());
allocation.allocate(symbols.getVariable("plot::x#2"), RegisterAllocation.getRegisterY());
allocation.allocate(symbols.getVariable("plot::y#0"), new RegisterAllocation.RegisterZpByte(100));
allocation.allocate(symbols.getVariable("plot::y#1"), new RegisterAllocation.RegisterZpByte(100));
allocation.allocate(symbols.getVariable("plot::y#2"), new RegisterAllocation.RegisterZpByte(100));
allocation.allocate(symbols.getVariable("plot::y#3"), new RegisterAllocation.RegisterZpByte(100));
allocation.allocate(symbols.getVariable("plot::y#4"), new RegisterAllocation.RegisterZpByte(100));
allocation.allocate(symbols.getVariable("plot::line#0"), new RegisterAllocation.RegisterZpPointerByte(101));
allocation.allocate(symbols.getVariable("plot::line#1"), new RegisterAllocation.RegisterZpPointerByte(101));
allocation.allocate(symbols.getVariable("plot::line#2"), new RegisterAllocation.RegisterZpPointerByte(101));
allocation.allocate(symbols.getVariable("plot::line#3"), new RegisterAllocation.RegisterZpPointerByte(101));
allocation.allocate(symbols.getVariable("plot::line#4"), new RegisterAllocation.RegisterZpPointerByte(101));
allocation.allocate(symbols.getVariable("plot::$3"), RegisterAllocation.getRegisterA());
allocation.allocate(symbols.getVariable("prepare::i#0"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("prepare::i#1"), RegisterAllocation.getRegisterX());
allocation.allocate(symbols.getVariable("prepare::i#2"), RegisterAllocation.getRegisterX());
symbols.setAllocation(allocation);
}

View File

@ -5,7 +5,7 @@ public class PointerDereferenceSimple implements PointerDereference {
private RValue pointer;
public PointerDereferenceSimple(Variable pointer) {
public PointerDereferenceSimple(RValue pointer) {
this.pointer = pointer;
}

View File

@ -29,6 +29,7 @@ public enum SymbolTypeBasic implements SymbolType {
case "word": return WORD;
case "string": return STRING;
case "boolean": return BOOLEAN;
case "void": return VOID;
}
return null;
}

View File

@ -13,7 +13,7 @@ import java.util.List;
/** Test my KickC Grammar */
public class Main {
public static void main(String[] args) throws IOException {
final String fileName = "src/dk/camelot64/kickc/test/callsum.kc";
final String fileName = "src/dk/camelot64/kickc/test/flipper-rex2.kc";
final CharStream input = CharStreams.fromFileName(fileName);
System.out.println(input.toString());
KickCLexer lexer = new KickCLexer(input);

View File

@ -0,0 +1,39 @@
byte[1000] SCREEN = $0400;
byte[16*16] buffer = $1000;
byte[16*16] buffer2 = $1100;
prepare();
do {
plot();
flip();
} while(true)
void prepare() {
// Prepare buffer
byte i=0;
do {
buffer[i] = i;
i=i+1;
} while (i!=0)
}
void flip() {
// Flip buffer
}
// Plot buffer on screen
void plot() {
byte* line = SCREEN+5*40+12;
byte y=0;
byte i=0;
do {
byte x=0;
do {
line[x] = buffer[i];
x=x+1;
i=i+1;
} while(x<16)
line = line+40;
y=y+1;
} while(y<16)
}