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

Implemented inline asm syntax and code generation. Now need to handle parameters.

This commit is contained in:
jespergravgaard 2017-11-05 03:01:32 +01:00
parent 86b1d0db73
commit 8d68d449c4
18 changed files with 2752 additions and 16 deletions

View File

@ -26,7 +26,7 @@ public class AsmFragment {
/**
* The fragment template ASM code.
*/
private KickCParser.AsmFileContext fragmentFile;
private KickCParser.AsmLinesContext fragmentFile;
/**
* Binding of named values in the fragment to values (constants, variables, ...) .
@ -42,7 +42,7 @@ public class AsmFragment {
Program program,
String name,
ScopeRef codeScopeRef,
KickCParser.AsmFileContext fragmentFile,
KickCParser.AsmLinesContext fragmentFile,
Map<String, Value> bindings) {
this.program = program;
this.name = name;
@ -246,7 +246,7 @@ public class AsmFragment {
return program;
}
public void generate(KickCParser.AsmFileContext context) {
public void generate(KickCParser.AsmLinesContext context) {
this.visit(context);
}

View File

@ -33,7 +33,7 @@ public class AsmFragmentManager {
signature.getProgram(),
signature.getSignature(),
signature.getCodeScope(),
fragmentFile,
fragmentFile.asmLines(),
signature.getBindings());
return fragment;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -185,6 +185,6 @@ public class ControlFlowGraphCopyVisitor extends ControlFlowGraphBaseVisitor<Obj
@Override
public Object visitAsm(StatementAsm asm) {
return new StatementAsm(asm.getAsmFragment());
return new StatementAsm(asm.getAsmLines());
}
}

View File

@ -1,22 +1,25 @@
package dk.camelot64.kickc.model;
import dk.camelot64.kickc.parser.KickCParser;
/** Inline ASM code */
public class StatementAsm extends StatementBase {
/** ASM Fragment code. */
private String asmFragment;
private KickCParser.AsmLinesContext asmLines;
public StatementAsm(String asmFragment) {
public StatementAsm(KickCParser.AsmLinesContext asmLines) {
super(null);
this.asmFragment = asmFragment;
this.asmLines = asmLines;
}
@Override
public String toString(Program program) {
return "asm { "+asmFragment+" }";
return "asm { "+asmLines.getText()+" }";
}
public String getAsmFragment() {
return asmFragment;
public KickCParser.AsmLinesContext getAsmLines() {
return asmLines;
}
}

View File

@ -154,7 +154,6 @@ fragment NAME_START : [a-zA-Z_];
fragment NAME_CHAR : [a-zA-Z0-9_];
ASMREL: '!' [+-]* ;
WS : [ \t\r\n]+ -> skip ;
COMMENT_LINE : '//' ~[\r\n]* -> skip ;
COMMENT_BLOCK : '/*' .*? '*/' -> skip;

View File

@ -297,6 +297,12 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
return null;
}
@Override
public Object visitStmtAsm(KickCParser.StmtAsmContext ctx) {
sequence.addStatement(new StatementAsm(ctx.asmLines()));
return null;
}
@Override
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
ArrayList<Variable> parameterDecls = new ArrayList<>();

View File

@ -257,10 +257,8 @@ public class Pass4CodeGeneration {
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
} else if (statement instanceof StatementAsm) {
StatementAsm statementAsm = (StatementAsm) statement;
String name = "inline";
KickCParser.AsmFileContext inlineAsm = AsmFragmentManager.parseFragment(CharStreams.fromString(statementAsm.getAsmFragment()), name);
HashMap<String, Value> bindings = new HashMap<>();
AsmFragment asmFragment = new AsmFragment(program, name, block.getScope(), inlineAsm, bindings);
AsmFragment asmFragment = new AsmFragment(program, "inline", block.getScope(), statementAsm.getAsmLines(), bindings);
asmFragment.generate(asm);
} else {
throw new RuntimeException("Statement not supported " + statement);

View File

@ -28,6 +28,10 @@ public class TestPrograms extends TestCase {
compileAndCompare("bitmap-bresenham");
}
public void testInlineAsm() throws IOException, URISyntaxException {
compileAndCompare("inline-asm");
}
public void testBitmapPlotter() throws IOException, URISyntaxException {
compileAndCompare("bitmap-plotter");
}
@ -40,7 +44,6 @@ public class TestPrograms extends TestCase {
compileAndCompare("callconstparam");
}
public void testScrollClobber() throws IOException, URISyntaxException {
compileAndCompare("scroll-clobber");
}

View File

@ -0,0 +1,25 @@
byte* PROCPORT = $01;
byte* CHARGEN = $d000;
byte* SCREEN = $0400;
void main() {
asm { sei };
byte* CHAR_A = CHARGEN+8;
*PROCPORT = $32;
byte* sc = SCREEN;
for(byte y:0..7) {
byte bits = CHAR_A[y];
for(byte x:0..7) {
if((bits & $80) != 0) {
*sc = '*';
} else {
*sc = '.';
}
sc++;
bits = bits<<1;
}
sc = sc+32;
}
*PROCPORT = $37;
asm { cli };
}

View File

@ -0,0 +1,64 @@
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
.const PROCPORT = 1
.const CHARGEN = $d000
.const SCREEN = $400
jsr main
main: {
.const CHAR_A = CHARGEN+8
.label bits = 3
.label sc = 4
.label y = 2
sei
lda #$32
sta PROCPORT
lda #<SCREEN
sta sc
lda #>SCREEN
sta sc+1
lda #0
sta y
b1:
ldx y
lda CHAR_A,x
sta bits
ldx #0
b2:
lda bits
and #$80
cmp #0
beq b3
ldy #0
lda #'*'
sta (sc),y
b4:
inc sc
bne !+
inc sc+1
!:
asl bits
inx
cpx #8
bne b2
lda sc
clc
adc #$20
sta sc
bcc !+
inc sc+1
!:
inc y
lda y
cmp #8
bne b1
lda #$37
sta PROCPORT
cli
rts
b3:
ldy #0
lda #'.'
sta (sc),y
jmp b4
}

View File

@ -0,0 +1,46 @@
@begin: scope:[] from
to:@1
@1: scope:[] from @begin
[0] call main param-assignment [ ]
to:@end
@end: scope:[] from @1
main: scope:[main] from @1
asm { sei }
[2] *((const byte*) PROCPORT#0) ← (byte) 50 [ ]
to:main::@1
main::@1: scope:[main] from main main::@7
[3] (byte*) main::sc#8 ← phi( main/(const byte*) SCREEN#0 main::@7/(byte*) main::sc#2 ) [ main::y#2 main::sc#8 ]
[3] (byte) main::y#2 ← phi( main/(byte) 0 main::@7/(byte) main::y#1 ) [ main::y#2 main::sc#8 ]
[4] (byte) main::bits#0 ← (const byte*) main::CHAR_A#0 *idx (byte) main::y#2 [ main::y#2 main::sc#8 main::bits#0 ]
to:main::@2
main::@2: scope:[main] from main::@1 main::@4
[5] (byte) main::x#2 ← phi( main::@1/(byte) 0 main::@4/(byte) main::x#1 ) [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
[5] (byte*) main::sc#3 ← phi( main::@1/(byte*) main::sc#8 main::@4/(byte*) main::sc#1 ) [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
[5] (byte) main::bits#2 ← phi( main::@1/(byte) main::bits#0 main::@4/(byte) main::bits#1 ) [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
[6] (byte~) main::$2 ← (byte) main::bits#2 & (byte) 128 [ main::y#2 main::bits#2 main::sc#3 main::x#2 main::$2 ]
[7] if((byte~) main::$2==(byte) 0) goto main::@3 [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
to:main::@5
main::@5: scope:[main] from main::@2
[8] *((byte*) main::sc#3) ← (byte) '*' [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
to:main::@4
main::@4: scope:[main] from main::@3 main::@5
[9] (byte*) main::sc#1 ← ++ (byte*) main::sc#3 [ main::y#2 main::bits#2 main::x#2 main::sc#1 ]
[10] (byte) main::bits#1 ← (byte) main::bits#2 << (byte) 1 [ main::y#2 main::x#2 main::bits#1 main::sc#1 ]
[11] (byte) main::x#1 ← ++ (byte) main::x#2 [ main::y#2 main::bits#1 main::sc#1 main::x#1 ]
[12] if((byte) main::x#1!=(byte) 8) goto main::@2 [ main::y#2 main::bits#1 main::sc#1 main::x#1 ]
to:main::@7
main::@7: scope:[main] from main::@4
[13] (byte*) main::sc#2 ← (byte*) main::sc#1 + (byte) 32 [ main::y#2 main::sc#2 ]
[14] (byte) main::y#1 ← ++ (byte) main::y#2 [ main::y#1 main::sc#2 ]
[15] if((byte) main::y#1!=(byte) 8) goto main::@1 [ main::y#1 main::sc#2 ]
to:main::@8
main::@8: scope:[main] from main::@7
[16] *((const byte*) PROCPORT#0) ← (byte) 55 [ ]
asm { cli }
to:main::@return
main::@return: scope:[main] from main::@8
[18] return [ ]
to:@return
main::@3: scope:[main] from main::@2
[19] *((byte*) main::sc#3) ← (byte) '.' [ main::y#2 main::bits#2 main::sc#3 main::x#2 ]
to:main::@4

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,42 @@
(label) @1
(label) @begin
(label) @end
(byte*) CHARGEN
(const byte*) CHARGEN#0 CHARGEN = (word) 53248
(byte*) PROCPORT
(const byte*) PROCPORT#0 PROCPORT = (byte) 1
(byte*) SCREEN
(const byte*) SCREEN#0 SCREEN = (word) 1024
(void()) main()
(byte~) main::$2 reg byte a 202.0
(label) main::@1
(label) main::@2
(label) main::@3
(label) main::@4
(label) main::@5
(label) main::@7
(label) main::@8
(label) main::@return
(byte*) main::CHAR_A
(const byte*) main::CHAR_A#0 CHAR_A = (const byte*) CHARGEN#0+(byte) 8
(byte) main::bits
(byte) main::bits#0 bits zp ZP_BYTE:3 22.0
(byte) main::bits#1 bits zp ZP_BYTE:3 67.33333333333333
(byte) main::bits#2 bits zp ZP_BYTE:3 52.33333333333333
(byte*) main::sc
(byte*) main::sc#1 sc zp ZP_PTR_BYTE:4 53.25
(byte*) main::sc#2 sc zp ZP_PTR_BYTE:4 7.333333333333333
(byte*) main::sc#3 sc zp ZP_PTR_BYTE:4 83.0
(byte*) main::sc#8 sc zp ZP_PTR_BYTE:4 11.0
(byte) main::x
(byte) main::x#1 reg byte x 151.5
(byte) main::x#2 reg byte x 28.857142857142858
(byte) main::y
(byte) main::y#1 y zp ZP_BYTE:2 16.5
(byte) main::y#2 y zp ZP_BYTE:2 2.75
zp ZP_BYTE:2 [ main::y#2 main::y#1 ]
zp ZP_BYTE:3 [ main::bits#2 main::bits#0 main::bits#1 ]
zp ZP_PTR_BYTE:4 [ main::sc#3 main::sc#8 main::sc#2 main::sc#1 ]
reg byte x [ main::x#2 main::x#1 ]
reg byte a [ main::$2 ]