mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-27 19:50:10 +00:00
Working on interrupts
This commit is contained in:
parent
18473295c9
commit
0763a63a66
@ -121,6 +121,7 @@ public class Compiler {
|
||||
new Pass1AssertNoLValueIntermediate(program).execute();
|
||||
new Pass1AddTypePromotions(program).execute();
|
||||
new Pass1AssertNoRecursion(program).execute();
|
||||
new Pass1AssertInterrupts(program).execute();
|
||||
|
||||
getLog().append("INITIAL CONTROL FLOW GRAPH");
|
||||
getLog().append(program.getGraph().toString(program));
|
||||
|
@ -16,11 +16,13 @@ public class Procedure extends Scope {
|
||||
private final SymbolType returnType;
|
||||
private List<String> parameterNames;
|
||||
private boolean declaredInline;
|
||||
private boolean declaredInterrupt;
|
||||
|
||||
public Procedure(String name, SymbolType returnType, Scope parentScope) {
|
||||
super(name, parentScope);
|
||||
this.returnType = returnType;
|
||||
this.declaredInline = false;
|
||||
this.declaredInterrupt = false;
|
||||
}
|
||||
|
||||
public List<String> getParameterNames() {
|
||||
@ -73,6 +75,18 @@ public class Procedure extends Scope {
|
||||
return declaredInline;
|
||||
}
|
||||
|
||||
public void setDeclaredInline(boolean declaredInline) {
|
||||
this.declaredInline = declaredInline;
|
||||
}
|
||||
|
||||
public boolean isDeclaredInterrupt() {
|
||||
return declaredInterrupt;
|
||||
}
|
||||
|
||||
public void setDeclaredInterrupt(boolean declaredInterrupt) {
|
||||
this.declaredInterrupt = declaredInterrupt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(null);
|
||||
@ -84,6 +98,9 @@ public class Procedure extends Scope {
|
||||
if(declaredInline) {
|
||||
res.append("inline ");
|
||||
}
|
||||
if(declaredInterrupt) {
|
||||
res.append("interrupt ");
|
||||
}
|
||||
res.append("(" + getType().getTypeName() + ") ");
|
||||
res.append(getFullName());
|
||||
res.append("(");
|
||||
@ -123,8 +140,4 @@ public class Procedure extends Scope {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setDeclaredInline(boolean declaredInline) {
|
||||
this.declaredInline = declaredInline;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -348,6 +348,8 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
StatementSource source = new StatementSource(directivesCtx.get(0));
|
||||
if(directive instanceof DirectiveInline) {
|
||||
procedure.setDeclaredInline(true);
|
||||
} else if(directive instanceof DirectiveInterrupt) {
|
||||
procedure.setDeclaredInterrupt(true);
|
||||
} else {
|
||||
throw new CompileError("Unsupported function directive " + directive, source);
|
||||
}
|
||||
@ -364,6 +366,11 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
return new DirectiveInline();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitDirectiveInterrupt(KickCParser.DirectiveInterruptContext ctx) {
|
||||
return new DirectiveInterrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Directive visitDirectiveAlign(KickCParser.DirectiveAlignContext ctx) {
|
||||
Number alignment = NumberParser.parseLiteral(ctx.NUMBER().getText());
|
||||
@ -831,6 +838,10 @@ public class Pass0GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
||||
private static class DirectiveInline implements Directive {
|
||||
}
|
||||
|
||||
/** Function declared interrupt. */
|
||||
private static class DirectiveInterrupt implements Directive {
|
||||
}
|
||||
|
||||
/** Variable memory alignment. */
|
||||
private static class DirectiveAlign implements Directive {
|
||||
private int alignment;
|
||||
|
@ -0,0 +1,40 @@
|
||||
package dk.camelot64.kickc.passes;
|
||||
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
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.StatementCall;
|
||||
import dk.camelot64.kickc.model.symbols.Procedure;
|
||||
import dk.camelot64.kickc.model.values.ProcedureRef;
|
||||
|
||||
/** Asserts that interrupts are never called and are not declared inline */
|
||||
public class Pass1AssertInterrupts extends Pass1Base {
|
||||
|
||||
public Pass1AssertInterrupts(Program program) {
|
||||
super(program);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean step() {
|
||||
for(ControlFlowBlock block : getGraph().getAllBlocks()) {
|
||||
for(Statement statement : block.getStatements()) {
|
||||
if(statement instanceof StatementCall) {
|
||||
ProcedureRef procedureRef = ((StatementCall) statement).getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(procedure.isDeclaredInterrupt()) {
|
||||
throw new CompileError("Error! Interrupts cannot be called.", statement.getSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
for(Procedure procedure : getScope().getAllProcedures(true)) {
|
||||
if(procedure.isDeclaredInline() && procedure.isDeclaredInterrupt()) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. " + procedure.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -37,6 +37,9 @@ public class Pass1ProcedureInline extends Pass1Base {
|
||||
ProcedureRef procedureRef = call.getProcedure();
|
||||
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||
if(procedure.isDeclaredInline()) {
|
||||
if(procedure.isDeclaredInterrupt()) {
|
||||
throw new CompileError("Error! Interrupts cannot be inlined. "+procedure.getRef().toString());
|
||||
}
|
||||
Scope callScope = getScope().getScope(block.getScope());
|
||||
// Remove call
|
||||
statementsIt.remove();
|
||||
|
@ -881,6 +881,15 @@ public class TestPrograms {
|
||||
assertError("no-mod-runtime", "Runtime modulo not supported");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoInlineInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-inlineinterrupt", "Interrupts cannot be inlined");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCalledInterrupt() throws IOException, URISyntaxException {
|
||||
assertError("no-calledinterrupt", "Interrupts cannot be called.");
|
||||
}
|
||||
|
||||
private void assertError(String kcFile, String expectError) throws IOException, URISyntaxException {
|
||||
try {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// A flexible sprite multiplexer routine for 24 sprites.
|
||||
// A flexible sprite multiplexer routine for 32 sprites.
|
||||
// Usage:
|
||||
// - Once:
|
||||
// - plexInit(screen): Initialize the data structures and set the screen address
|
||||
@ -9,8 +9,8 @@
|
||||
// - plexFreeNextYpos() Returns the Y-position where the next sprite is available to be shown (ie. the next pos where the next sprite is no longer in use showing something else).
|
||||
// - plexShowNextYpos() Returns the Y-position of the next sprite to show.
|
||||
//
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 24 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites (PLEX_COUNT)
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
|
||||
|
||||
import "c64"
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
// Test that inline interrupts not allowed
|
||||
|
||||
byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
SCREEN[0]++;
|
||||
irq();
|
||||
}
|
||||
|
||||
interrupt void irq() {
|
||||
SCREEN[1]++;
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
// Test that inline interrupts not allowed
|
||||
|
||||
byte* SCREEN = $400;
|
||||
|
||||
void main() {
|
||||
SCREEN[0]++;
|
||||
}
|
||||
|
||||
inline interrupt void irq() {
|
||||
SCREEN[1]++;
|
||||
}
|
@ -3,8 +3,8 @@ import "c64"
|
||||
import "multiplexer"
|
||||
|
||||
// Location of screen & sprites
|
||||
byte* SPRITE = $2000;
|
||||
byte* SCREEN = $400;
|
||||
byte* SPRITE = $2000;
|
||||
byte* YSIN = $2100;
|
||||
|
||||
kickasm(pc YSIN) {{
|
||||
|
@ -194,7 +194,7 @@ inline void vicSelectGfxBank(byte* gfx) {
|
||||
|
||||
Importing multiplexer
|
||||
PARSING src/test/java/dk/camelot64/kickc/test/kc/multiplexer.kc
|
||||
// A flexible sprite multiplexer routine for 24 sprites.
|
||||
// A flexible sprite multiplexer routine for 32 sprites.
|
||||
// Usage:
|
||||
// - Once:
|
||||
// - plexInit(screen): Initialize the data structures and set the screen address
|
||||
@ -205,8 +205,8 @@ PARSING src/test/java/dk/camelot64/kickc/test/kc/multiplexer.kc
|
||||
// - plexFreeNextYpos() Returns the Y-position where the next sprite is available to be shown (ie. the next pos where the next sprite is no longer in use showing something else).
|
||||
// - plexShowNextYpos() Returns the Y-position of the next sprite to show.
|
||||
//
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 24 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites (PLEX_COUNT)
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
|
||||
|
||||
import "c64"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user