mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 03:32:23 +00:00
Implemented inline asm syntax and code generation. Now need to handle parameters.
This commit is contained in:
parent
86b1d0db73
commit
8d68d449c4
@ -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);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ public class AsmFragmentManager {
|
||||
signature.getProgram(),
|
||||
signature.getSignature(),
|
||||
signature.getCodeScope(),
|
||||
fragmentFile,
|
||||
fragmentFile.asmLines(),
|
||||
signature.getBindings());
|
||||
return fragment;
|
||||
}
|
||||
|
@ -0,0 +1,2 @@
|
||||
cmp #0
|
||||
beq {la1}
|
@ -0,0 +1,2 @@
|
||||
cpx #0
|
||||
beq {la1}
|
@ -0,0 +1,2 @@
|
||||
cpy #0
|
||||
beq {la1}
|
@ -0,0 +1 @@
|
||||
asl {zpby1}
|
@ -0,0 +1,2 @@
|
||||
lda {zpby1}
|
||||
beq {la1}
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
@ -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<>();
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
}
|
||||
|
25
src/main/java/dk/camelot64/kickc/test/inline-asm.kc
Normal file
25
src/main/java/dk/camelot64/kickc/test/inline-asm.kc
Normal 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 };
|
||||
}
|
64
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.asm
Normal file
64
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.asm
Normal 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
|
||||
}
|
46
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.cfg
Normal file
46
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.cfg
Normal 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
|
2541
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.log
Normal file
2541
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.log
Normal file
File diff suppressed because it is too large
Load Diff
42
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.sym
Normal file
42
src/main/java/dk/camelot64/kickc/test/ref/inline-asm.sym
Normal 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 ]
|
Loading…
Reference in New Issue
Block a user