mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-10-11 12:23:45 +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.
|
* The fragment template ASM code.
|
||||||
*/
|
*/
|
||||||
private KickCParser.AsmFileContext fragmentFile;
|
private KickCParser.AsmLinesContext fragmentFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Binding of named values in the fragment to values (constants, variables, ...) .
|
* Binding of named values in the fragment to values (constants, variables, ...) .
|
||||||
@ -42,7 +42,7 @@ public class AsmFragment {
|
|||||||
Program program,
|
Program program,
|
||||||
String name,
|
String name,
|
||||||
ScopeRef codeScopeRef,
|
ScopeRef codeScopeRef,
|
||||||
KickCParser.AsmFileContext fragmentFile,
|
KickCParser.AsmLinesContext fragmentFile,
|
||||||
Map<String, Value> bindings) {
|
Map<String, Value> bindings) {
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
@ -246,7 +246,7 @@ public class AsmFragment {
|
|||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(KickCParser.AsmFileContext context) {
|
public void generate(KickCParser.AsmLinesContext context) {
|
||||||
this.visit(context);
|
this.visit(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public class AsmFragmentManager {
|
|||||||
signature.getProgram(),
|
signature.getProgram(),
|
||||||
signature.getSignature(),
|
signature.getSignature(),
|
||||||
signature.getCodeScope(),
|
signature.getCodeScope(),
|
||||||
fragmentFile,
|
fragmentFile.asmLines(),
|
||||||
signature.getBindings());
|
signature.getBindings());
|
||||||
return fragment;
|
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
|
@Override
|
||||||
public Object visitAsm(StatementAsm asm) {
|
public Object visitAsm(StatementAsm asm) {
|
||||||
return new StatementAsm(asm.getAsmFragment());
|
return new StatementAsm(asm.getAsmLines());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
package dk.camelot64.kickc.model;
|
package dk.camelot64.kickc.model;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.parser.KickCParser;
|
||||||
|
|
||||||
/** Inline ASM code */
|
/** Inline ASM code */
|
||||||
public class StatementAsm extends StatementBase {
|
public class StatementAsm extends StatementBase {
|
||||||
|
|
||||||
/** ASM Fragment code. */
|
/** ASM Fragment code. */
|
||||||
private String asmFragment;
|
private KickCParser.AsmLinesContext asmLines;
|
||||||
|
|
||||||
public StatementAsm(String asmFragment) {
|
public StatementAsm(KickCParser.AsmLinesContext asmLines) {
|
||||||
super(null);
|
super(null);
|
||||||
this.asmFragment = asmFragment;
|
this.asmLines = asmLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString(Program program) {
|
public String toString(Program program) {
|
||||||
return "asm { "+asmFragment+" }";
|
return "asm { "+asmLines.getText()+" }";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAsmFragment() {
|
public KickCParser.AsmLinesContext getAsmLines() {
|
||||||
return asmFragment;
|
return asmLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -154,7 +154,6 @@ fragment NAME_START : [a-zA-Z_];
|
|||||||
fragment NAME_CHAR : [a-zA-Z0-9_];
|
fragment NAME_CHAR : [a-zA-Z0-9_];
|
||||||
ASMREL: '!' [+-]* ;
|
ASMREL: '!' [+-]* ;
|
||||||
|
|
||||||
|
|
||||||
WS : [ \t\r\n]+ -> skip ;
|
WS : [ \t\r\n]+ -> skip ;
|
||||||
COMMENT_LINE : '//' ~[\r\n]* -> skip ;
|
COMMENT_LINE : '//' ~[\r\n]* -> skip ;
|
||||||
COMMENT_BLOCK : '/*' .*? '*/' -> skip;
|
COMMENT_BLOCK : '/*' .*? '*/' -> skip;
|
@ -297,6 +297,12 @@ public class Pass1GenerateStatementSequence extends KickCBaseVisitor<Object> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitStmtAsm(KickCParser.StmtAsmContext ctx) {
|
||||||
|
sequence.addStatement(new StatementAsm(ctx.asmLines()));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
|
public List<Variable> visitParameterListDecl(KickCParser.ParameterListDeclContext ctx) {
|
||||||
ArrayList<Variable> parameterDecls = new ArrayList<>();
|
ArrayList<Variable> parameterDecls = new ArrayList<>();
|
||||||
|
@ -257,10 +257,8 @@ public class Pass4CodeGeneration {
|
|||||||
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
asm.addInstruction("rts", AsmAddressingMode.NON, null, false);
|
||||||
} else if (statement instanceof StatementAsm) {
|
} else if (statement instanceof StatementAsm) {
|
||||||
StatementAsm statementAsm = (StatementAsm) statement;
|
StatementAsm statementAsm = (StatementAsm) statement;
|
||||||
String name = "inline";
|
|
||||||
KickCParser.AsmFileContext inlineAsm = AsmFragmentManager.parseFragment(CharStreams.fromString(statementAsm.getAsmFragment()), name);
|
|
||||||
HashMap<String, Value> bindings = new HashMap<>();
|
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);
|
asmFragment.generate(asm);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Statement not supported " + statement);
|
throw new RuntimeException("Statement not supported " + statement);
|
||||||
|
@ -28,6 +28,10 @@ public class TestPrograms extends TestCase {
|
|||||||
compileAndCompare("bitmap-bresenham");
|
compileAndCompare("bitmap-bresenham");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testInlineAsm() throws IOException, URISyntaxException {
|
||||||
|
compileAndCompare("inline-asm");
|
||||||
|
}
|
||||||
|
|
||||||
public void testBitmapPlotter() throws IOException, URISyntaxException {
|
public void testBitmapPlotter() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("bitmap-plotter");
|
compileAndCompare("bitmap-plotter");
|
||||||
}
|
}
|
||||||
@ -40,7 +44,6 @@ public class TestPrograms extends TestCase {
|
|||||||
compileAndCompare("callconstparam");
|
compileAndCompare("callconstparam");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testScrollClobber() throws IOException, URISyntaxException {
|
public void testScrollClobber() throws IOException, URISyntaxException {
|
||||||
compileAndCompare("scroll-clobber");
|
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