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

Implemented sinus generator for logo scroller. Added missing fragments and fixed issue when removing an unused block also made some variables unused.

This commit is contained in:
Jesper Gravgaard 2018-07-08 23:58:43 +02:00
parent 2c0299ee09
commit 5e9b15477a
9 changed files with 133 additions and 7 deletions

View File

@ -1,17 +1,17 @@
package dk.camelot64.kickc.asm;
/** Inlined KickAssembler code.
* If no cycles/byte size is specified it defaults to 100/100.
* */
* If no cycles/byte size is specified it defaults to 256/256.
*/
public class AsmInlineKickAsm implements AsmLine {
private String kickAsmCode;
private int index;
private int bytes = 100;
private int bytes = 256;
private double cycles = 100;
private double cycles = 256;
public AsmInlineKickAsm(String kickAsmCode) {
this.kickAsmCode= kickAsmCode;

View File

@ -0,0 +1,4 @@
asl {z1}
rol {z1}+1
rol {z1}+2
rol {z1}+3

View File

@ -0,0 +1,12 @@
lda {z2}
asl
sta {z1}
lda {z2}+1
rol
sta {z1}+1
lda {z2}+2
rol
sta {z1}+2
lda {z2}+3
rol
sta {z1}+3

View File

@ -0,0 +1,4 @@
lda {z2}+2
sta {z1}
lda {z2}+3
sta {z1}+1

View File

@ -0,0 +1,7 @@
lda {z1}
sec
sbc #<{c1}
sta {z2}
lda {z1}+1
sbc #>{c1}
sta {z2}+1

View File

@ -570,7 +570,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
@Override
public Object visitExprAssignment(KickCParser.ExprAssignmentContext ctx) {
LValue lValue = (LValue) visit(ctx.expr(0));
Object val = visit(ctx.expr(0));
LValue lValue = (LValue) val;
if(lValue instanceof VariableRef && ((VariableRef) lValue).isIntermediate()) {
// Encountered an intermediate variable. This must be turned into a proper LValue later. Put it into a marker to signify that
lValue = new LvalueIntermediate((VariableRef) lValue);

View File

@ -3,10 +3,15 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.CompileLog;
import dk.camelot64.kickc.model.ControlFlowBlock;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.Statement;
import dk.camelot64.kickc.model.statements.StatementAssignment;
import dk.camelot64.kickc.model.statements.StatementPhiBlock;
import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Variable;
import dk.camelot64.kickc.model.values.LValue;
import dk.camelot64.kickc.model.values.LabelRef;
import dk.camelot64.kickc.model.values.SymbolRef;
import dk.camelot64.kickc.model.values.VariableRef;
import java.util.LinkedHashSet;
import java.util.ListIterator;
@ -26,9 +31,18 @@ public class Pass2EliminateUnusedBlocks extends Pass2SsaOptimization {
Set<LabelRef> unusedBlocks = new LinkedHashSet<>();
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
if(!referencedBlocks.contains(block.getLabel())) {
unusedBlocks.add(block.getLabel());
for(Statement stmt : block.getStatements()) {
if(stmt instanceof StatementAssignment) {
StatementAssignment assignment = (StatementAssignment) stmt;
LValue lValue = assignment.getlValue();
if(lValue instanceof VariableRef) {
getLog().append("Eliminating variable " + lValue.toString(getProgram()) + " and from unused block " + block.getLabel());
Variable variable = getScope().getVariable((VariableRef) lValue);
variable.getScope().remove(variable);
}
}
}
}
}
for(LabelRef unusedBlock : unusedBlocks) {

View File

@ -45,6 +45,11 @@ public class TestPrograms {
AsmFragmentTemplateUsages.logUsages(log, false, false, false, false, false, false);
}
@Test
public void testScrollLogo() throws IOException, URISyntaxException {
compileAndCompare("scrolllogo");
}
@Test
public void testShowLogo() throws IOException, URISyntaxException {
compileAndCompare("showlogo");

View File

@ -0,0 +1,79 @@
import "c64.kc"
import "sinus.kc"
byte* SCREEN = $400;
byte* LOGO = $2000;
const word XSIN_SIZE = 512;
signed word[512] align($100) xsin;
void main() {
*BORDERCOL = WHITE;
*BGCOL = *BGCOL2 = DARK_GREY;
*BGCOL3 = BLACK;
*D018 = toD018(SCREEN, LOGO);
*D016 = VIC_MCM | VIC_CSEL;
fill(SCREEN, 1000, BLACK);
fill(COLS, 1000, WHITE|8);
for(byte ch: 0..239) {
SCREEN[ch] = ch;
}
sin16s_gen2(xsin, XSIN_SIZE, -320, 320);
loop();
}
// Generate signed word sinus table - with values in the range min-max.
// sintab - the table to generate into
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
void sin16s_gen2(signed word* sintab, word wavelength, signed word min, signed word max) {
signed word ampl = max-min;
signed word offs = min + ampl>>1; // ampl is always positive so shifting left does not alter the sign
// u[4.28] step = PI*2/wavelength
dword step = div32u16u(PI2_u4f28, wavelength); // u[4.28]
// Iterate over the table
dword x = 0; // u[4.28]
for( word i=0; i<wavelength; i++) {
signed dword ssin = mul16s(sin16s(x), ampl); // The signed sin() only has values [-1/2 ; 1/2] there ampl*sin has the right amplitude
*sintab = offs + (signed word)>ssin;
sintab = sintab + 2;
x = x + step;
}
}
word xsin_idx = 0;
void loop() {
while(true) {
while(*RASTER!=$ff) {}
signed word xpos = *(xsin+xsin_idx>>1);
SCREEN[0] = <xpos;
SCREEN[1] = >xpos;
xsin_idx += 2;
if(xsin_idx==XSIN_SIZE) {
xsin_idx = 0;
}
}
}
// Fill some memory with a value
void fill(byte* start, word size, byte val) {
byte* end = start + size;
for(byte* addr = start; addr!=end; addr++) {
*addr = val;
}
}
kickasm(resources "logo.png" ) {{
.label pc_restore = *
.pc = $2000
logo:
.var logoPic = LoadPicture("logo.png", List().add($444444, $808080, $000000, $ffffff))
.for (var y=0; y<6 ; y++)
.for (var x=0;x<40; x++)
.for(var cp=0; cp<8; cp++)
.byte logoPic.getMulticolorByte(x,cp+y*8)
.pc = pc_restore
}}