mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-02-18 01:30:56 +00:00
far calls
This commit is contained in:
parent
152832fd4e
commit
828e38a8b3
487
gen/KickCLexer.interp
Normal file
487
gen/KickCLexer.interp
Normal file
File diff suppressed because one or more lines are too long
1596
gen/KickCLexer.java
Normal file
1596
gen/KickCLexer.java
Normal file
File diff suppressed because it is too large
Load Diff
225
gen/KickCLexer.tokens
Normal file
225
gen/KickCLexer.tokens
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
TYPEDEFNAME=1
|
||||||
|
CURLY_BEGIN=2
|
||||||
|
CURLY_END=3
|
||||||
|
BRACKET_BEGIN=4
|
||||||
|
BRACKET_END=5
|
||||||
|
PAR_BEGIN=6
|
||||||
|
PAR_END=7
|
||||||
|
SEMICOLON=8
|
||||||
|
COLON=9
|
||||||
|
COMMA=10
|
||||||
|
RANGE=11
|
||||||
|
PARAM_LIST=12
|
||||||
|
CONDITION=13
|
||||||
|
DOT=14
|
||||||
|
ARROW=15
|
||||||
|
PLUS=16
|
||||||
|
MINUS=17
|
||||||
|
ASTERISK=18
|
||||||
|
DIVIDE=19
|
||||||
|
MODULO=20
|
||||||
|
INC=21
|
||||||
|
DEC=22
|
||||||
|
AND=23
|
||||||
|
BIT_NOT=24
|
||||||
|
BIT_XOR=25
|
||||||
|
BIT_OR=26
|
||||||
|
SHIFT_LEFT=27
|
||||||
|
SHIFT_RIGHT=28
|
||||||
|
EQUAL=29
|
||||||
|
NOT_EQUAL=30
|
||||||
|
LESS_THAN=31
|
||||||
|
LESS_THAN_EQUAL=32
|
||||||
|
GREATER_THAN_EQUAL=33
|
||||||
|
GREATER_THAN=34
|
||||||
|
LOGIC_AND=35
|
||||||
|
LOGIC_OR=36
|
||||||
|
ASSIGN=37
|
||||||
|
ASSIGN_COMPOUND=38
|
||||||
|
TYPEDEF=39
|
||||||
|
CONST=40
|
||||||
|
EXTERN=41
|
||||||
|
EXPORT=42
|
||||||
|
ALIGN=43
|
||||||
|
INLINE=44
|
||||||
|
VOLATILE=45
|
||||||
|
STATIC=46
|
||||||
|
INTERRUPT=47
|
||||||
|
REGISTER=48
|
||||||
|
LOCAL_RESERVE=49
|
||||||
|
ADDRESS=50
|
||||||
|
ADDRESS_ZEROPAGE=51
|
||||||
|
ADDRESS_MAINMEM=52
|
||||||
|
FAR=53
|
||||||
|
FORM_SSA=54
|
||||||
|
FORM_MA=55
|
||||||
|
INTRINSIC=56
|
||||||
|
CALLINGCONVENTION=57
|
||||||
|
IF=58
|
||||||
|
ELSE=59
|
||||||
|
WHILE=60
|
||||||
|
DO=61
|
||||||
|
FOR=62
|
||||||
|
SWITCH=63
|
||||||
|
RETURN=64
|
||||||
|
BREAK=65
|
||||||
|
CONTINUE=66
|
||||||
|
GOTO=67
|
||||||
|
ASM=68
|
||||||
|
DEFAULT=69
|
||||||
|
CASE=70
|
||||||
|
STRUCT=71
|
||||||
|
UNION=72
|
||||||
|
ENUM=73
|
||||||
|
SIZEOF=74
|
||||||
|
TYPEID=75
|
||||||
|
DEFINED=76
|
||||||
|
KICKASM=77
|
||||||
|
LOGIC_NOT=78
|
||||||
|
SIMPLETYPE=79
|
||||||
|
BOOLEAN=80
|
||||||
|
KICKASM_BODY=81
|
||||||
|
IMPORT=82
|
||||||
|
INCLUDE=83
|
||||||
|
PRAGMA=84
|
||||||
|
DEFINE=85
|
||||||
|
DEFINE_CONTINUE=86
|
||||||
|
UNDEF=87
|
||||||
|
IFDEF=88
|
||||||
|
IFNDEF=89
|
||||||
|
IFIF=90
|
||||||
|
ELIF=91
|
||||||
|
IFELSE=92
|
||||||
|
ENDIF=93
|
||||||
|
ERROR=94
|
||||||
|
TOKEN_STRINGIZE=95
|
||||||
|
TOKEN_MERGE=96
|
||||||
|
NUMBER=97
|
||||||
|
NUMFLOAT=98
|
||||||
|
BINFLOAT=99
|
||||||
|
DECFLOAT=100
|
||||||
|
HEXFLOAT=101
|
||||||
|
NUMINT=102
|
||||||
|
BININTEGER=103
|
||||||
|
DECINTEGER=104
|
||||||
|
HEXINTEGER=105
|
||||||
|
NAME=106
|
||||||
|
STRING=107
|
||||||
|
CHAR=108
|
||||||
|
WS=109
|
||||||
|
COMMENT_LINE=110
|
||||||
|
COMMENT_BLOCK=111
|
||||||
|
ASM_BYTE=112
|
||||||
|
ASM_MNEMONIC=113
|
||||||
|
ASM_IMM=114
|
||||||
|
ASM_COLON=115
|
||||||
|
ASM_COMMA=116
|
||||||
|
ASM_PAR_BEGIN=117
|
||||||
|
ASM_PAR_END=118
|
||||||
|
ASM_BRACKET_BEGIN=119
|
||||||
|
ASM_BRACKET_END=120
|
||||||
|
ASM_DOT=121
|
||||||
|
ASM_SHIFT_LEFT=122
|
||||||
|
ASM_SHIFT_RIGHT=123
|
||||||
|
ASM_PLUS=124
|
||||||
|
ASM_MINUS=125
|
||||||
|
ASM_LESS_THAN=126
|
||||||
|
ASM_GREATER_THAN=127
|
||||||
|
ASM_MULTIPLY=128
|
||||||
|
ASM_DIVIDE=129
|
||||||
|
ASM_CURLY_BEGIN=130
|
||||||
|
ASM_CURLY_END=131
|
||||||
|
ASM_NUMBER=132
|
||||||
|
ASM_NUMFLOAT=133
|
||||||
|
ASM_BINFLOAT=134
|
||||||
|
ASM_DECFLOAT=135
|
||||||
|
ASM_HEXFLOAT=136
|
||||||
|
ASM_NUMINT=137
|
||||||
|
ASM_BININTEGER=138
|
||||||
|
ASM_DECINTEGER=139
|
||||||
|
ASM_HEXINTEGER=140
|
||||||
|
ASM_CHAR=141
|
||||||
|
ASM_MULTI_REL=142
|
||||||
|
ASM_MULTI_NAME=143
|
||||||
|
ASM_NAME=144
|
||||||
|
ASM_TAG=145
|
||||||
|
ASM_WS=146
|
||||||
|
ASM_COMMENT_LINE=147
|
||||||
|
ASM_COMMENT_BLOCK=148
|
||||||
|
IMPORT_SYSTEMFILE=149
|
||||||
|
IMPORT_LOCALFILE=150
|
||||||
|
IMPORT_WS=151
|
||||||
|
IMPORT_COMMENT_LINE=152
|
||||||
|
IMPORT_COMMENT_BLOCK=153
|
||||||
|
';'=8
|
||||||
|
'..'=11
|
||||||
|
'...'=12
|
||||||
|
'?'=13
|
||||||
|
'->'=15
|
||||||
|
'%'=20
|
||||||
|
'++'=21
|
||||||
|
'--'=22
|
||||||
|
'&'=23
|
||||||
|
'~'=24
|
||||||
|
'^'=25
|
||||||
|
'|'=26
|
||||||
|
'=='=29
|
||||||
|
'!='=30
|
||||||
|
'<='=32
|
||||||
|
'>='=33
|
||||||
|
'&&'=35
|
||||||
|
'||'=36
|
||||||
|
'='=37
|
||||||
|
'typedef'=39
|
||||||
|
'const'=40
|
||||||
|
'extern'=41
|
||||||
|
'__export'=42
|
||||||
|
'__align'=43
|
||||||
|
'inline'=44
|
||||||
|
'volatile'=45
|
||||||
|
'static'=46
|
||||||
|
'__interrupt'=47
|
||||||
|
'register'=48
|
||||||
|
'__zp_reserve'=49
|
||||||
|
'__address'=50
|
||||||
|
'__zp'=51
|
||||||
|
'__mem'=52
|
||||||
|
'__far'=53
|
||||||
|
'__ssa'=54
|
||||||
|
'__ma'=55
|
||||||
|
'__intrinsic'=56
|
||||||
|
'if'=58
|
||||||
|
'else'=59
|
||||||
|
'while'=60
|
||||||
|
'do'=61
|
||||||
|
'for'=62
|
||||||
|
'switch'=63
|
||||||
|
'return'=64
|
||||||
|
'break'=65
|
||||||
|
'continue'=66
|
||||||
|
'goto'=67
|
||||||
|
'asm'=68
|
||||||
|
'default'=69
|
||||||
|
'case'=70
|
||||||
|
'struct'=71
|
||||||
|
'union'=72
|
||||||
|
'enum'=73
|
||||||
|
'sizeof'=74
|
||||||
|
'typeid'=75
|
||||||
|
'defined'=76
|
||||||
|
'kickasm'=77
|
||||||
|
'!'=78
|
||||||
|
'#import'=82
|
||||||
|
'#include'=83
|
||||||
|
'#pragma'=84
|
||||||
|
'#define'=85
|
||||||
|
'#undef'=87
|
||||||
|
'#ifdef'=88
|
||||||
|
'#ifndef'=89
|
||||||
|
'#if'=90
|
||||||
|
'#elif'=91
|
||||||
|
'#else'=92
|
||||||
|
'#endif'=93
|
||||||
|
'#error'=94
|
||||||
|
'.byte'=112
|
||||||
|
'#'=114
|
@ -75,6 +75,7 @@ LOCAL_RESERVE: '__zp_reserve' ;
|
|||||||
ADDRESS: '__address' ;
|
ADDRESS: '__address' ;
|
||||||
ADDRESS_ZEROPAGE: '__zp' ;
|
ADDRESS_ZEROPAGE: '__zp' ;
|
||||||
ADDRESS_MAINMEM: '__mem' ;
|
ADDRESS_MAINMEM: '__mem' ;
|
||||||
|
FAR: '__far' ;
|
||||||
FORM_SSA: '__ssa' ;
|
FORM_SSA: '__ssa' ;
|
||||||
FORM_MA: '__ma' ;
|
FORM_MA: '__ma' ;
|
||||||
INTRINSIC: '__intrinsic' ;
|
INTRINSIC: '__intrinsic' ;
|
||||||
|
@ -161,6 +161,7 @@ directive
|
|||||||
| EXTERN #directiveExtern
|
| EXTERN #directiveExtern
|
||||||
| EXPORT #directiveExport
|
| EXPORT #directiveExport
|
||||||
| INLINE #directiveInline
|
| INLINE #directiveInline
|
||||||
|
| FAR PAR_BEGIN ( NUMBER ) PAR_END #directiveFar
|
||||||
| INTRINSIC #directiveIntrinsic
|
| INTRINSIC #directiveIntrinsic
|
||||||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||||
| LOCAL_RESERVE PAR_BEGIN pragmaParam ( COMMA pragmaParam )* PAR_END #directiveReserveZp
|
| LOCAL_RESERVE PAR_BEGIN pragmaParam ( COMMA pragmaParam )* PAR_END #directiveReserveZp
|
||||||
|
4
src/main/fragment/mos6502-common/call_far_cx16_entry.asm
Normal file
4
src/main/fragment/mos6502-common/call_far_cx16_entry.asm
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
jsr $FF6E // https://github.com/commanderx16/x16-docs/blob/master/X16%20Reference%20-%2004%20-%20KERNAL.md#function-name-jsrfar
|
||||||
|
.byte <{la1}
|
||||||
|
.byte >{la1}
|
||||||
|
.byte {c1}
|
@ -278,6 +278,7 @@ public class Compiler {
|
|||||||
getLog().append(program.getGraph().toString(program));
|
getLog().append(program.getGraph().toString(program));
|
||||||
}
|
}
|
||||||
new Pass1ProcedureInline(program).execute();
|
new Pass1ProcedureInline(program).execute();
|
||||||
|
new Pass1ProcedureFar(program).execute(); // Implements far calls to procedures defined in a bank.
|
||||||
new PassNStatementIndices(program).step();
|
new PassNStatementIndices(program).step();
|
||||||
program.clearCallGraph();
|
program.clearCallGraph();
|
||||||
new Pass1AssertNoRecursion(program).execute();
|
new Pass1AssertNoRecursion(program).execute();
|
||||||
|
@ -12,6 +12,7 @@ import dk.camelot64.kickc.model.types.SymbolType;
|
|||||||
import dk.camelot64.kickc.model.values.*;
|
import dk.camelot64.kickc.model.values.*;
|
||||||
import dk.camelot64.kickc.parser.KickCParser;
|
import dk.camelot64.kickc.parser.KickCParser;
|
||||||
import dk.camelot64.kickc.parser.KickCParserBaseVisitor;
|
import dk.camelot64.kickc.parser.KickCParserBaseVisitor;
|
||||||
|
import org.antlr.v4.runtime.tree.ParseTree;
|
||||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -250,9 +251,13 @@ public class AsmFragmentInstance {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitAsmBytes(KickCParser.AsmBytesContext ctx) {
|
public Object visitAsmBytes(KickCParser.AsmBytesContext ctx) {
|
||||||
|
List<KickCParser.AsmExprContext> asmExpr = ctx.asmExpr();
|
||||||
ArrayList<String> values = new ArrayList<>();
|
ArrayList<String> values = new ArrayList<>();
|
||||||
for(int i = 1; i < ctx.getChildCount(); i = i + 2) {
|
for(int i = 0; i < asmExpr.size(); i++) {
|
||||||
values.add(ctx.getChild(i).getText());
|
if(asmExpr.get(i) != null) {
|
||||||
|
AsmParameter par = (AsmParameter)this.visit(asmExpr.get(i));
|
||||||
|
values.add(par.getParam());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AsmDataNumeric data = new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values);
|
AsmDataNumeric data = new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values);
|
||||||
handleTags(data, ctx.ASM_TAG());
|
handleTags(data, ctx.ASM_TAG());
|
||||||
|
@ -18,6 +18,7 @@ import dk.camelot64.kickc.model.symbols.Symbol;
|
|||||||
import dk.camelot64.kickc.model.types.SymbolType;
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
import dk.camelot64.kickc.model.types.SymbolTypeInference;
|
||||||
import dk.camelot64.kickc.model.values.*;
|
import dk.camelot64.kickc.model.values.*;
|
||||||
|
import kickass.pass.values.StringValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an ASM Fragment specification for a statement in the control flow graph.
|
* Creates an ASM Fragment specification for a statement in the control flow graph.
|
||||||
@ -41,6 +42,40 @@ final public class AsmFragmentInstanceSpecBuilder {
|
|||||||
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
|
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fragment instance spec factory for a far call entry
|
||||||
|
*
|
||||||
|
* @param call The statement call
|
||||||
|
* @param program The program
|
||||||
|
* @return the fragment instance spec factory
|
||||||
|
*/
|
||||||
|
public static AsmFragmentInstanceSpec farCallEntry(StatementCall call, Program program) {
|
||||||
|
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
|
||||||
|
AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(call.getBankFar(), program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Entry);
|
||||||
|
ScopeRef codeScope = program.getScope().getRef();
|
||||||
|
// ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope();
|
||||||
|
bindings.bind("c1", new ConstantInteger(call.getBankFar()));
|
||||||
|
bindings.bind("la1", new LabelRef(call.getProcedure().getFullName()));
|
||||||
|
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fragment instance spec factory for a far call exit
|
||||||
|
*
|
||||||
|
* @param call The statement call
|
||||||
|
* @param program The program
|
||||||
|
* @return the fragment instance spec factory
|
||||||
|
*/
|
||||||
|
public static AsmFragmentInstanceSpec farCallExit(StatementCall call, Program program) {
|
||||||
|
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
|
||||||
|
AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(call.getBankFar(), program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Exit);
|
||||||
|
ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope();
|
||||||
|
bindings.bind("la1", new LabelRef(codeScope.getFullName()));
|
||||||
|
bindings.bind("la2", new ConstantInteger(call.getBankFar()));
|
||||||
|
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a fragment instance spec factory for an interrupt routine entry
|
* Create a fragment instance spec factory for an interrupt routine entry
|
||||||
*
|
*
|
||||||
|
@ -143,6 +143,7 @@ public class AsmFragmentTemplate {
|
|||||||
if(signature.contains("c6")) bindings.put("c6", new ConstantInteger(360L));
|
if(signature.contains("c6")) bindings.put("c6", new ConstantInteger(360L));
|
||||||
if(signature.contains("la1")) bindings.put("la1", new Label("@1", scope, true));
|
if(signature.contains("la1")) bindings.put("la1", new Label("@1", scope, true));
|
||||||
if(signature.startsWith("call_")) bindings.put("la1", new Label("@1", scope, true));
|
if(signature.startsWith("call_")) bindings.put("la1", new Label("@1", scope, true));
|
||||||
|
if(signature.startsWith("call_")) bindings.put("c1", new ConstantInteger(400L));
|
||||||
AsmFragmentInstance fragmentInstance =
|
AsmFragmentInstance fragmentInstance =
|
||||||
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
|
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
|
||||||
AsmProgram asm = new AsmProgram(targetCpu);
|
AsmProgram asm = new AsmProgram(targetCpu);
|
||||||
|
@ -70,6 +70,34 @@ public interface AsmFragmentSignature {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASM fragment signature for a far jsr <code>if(A) goto B</code>.
|
||||||
|
*/
|
||||||
|
class CallFar implements AsmFragmentSignature {
|
||||||
|
|
||||||
|
final private Long bankFar;
|
||||||
|
final private String targetPlatform;
|
||||||
|
|
||||||
|
public enum EntryExit {
|
||||||
|
Exit,
|
||||||
|
Entry
|
||||||
|
}
|
||||||
|
|
||||||
|
final private CallFar.EntryExit entryExit;
|
||||||
|
|
||||||
|
|
||||||
|
public CallFar(Long bankFar, String targetPlatform, CallFar.EntryExit entryExit) {
|
||||||
|
this.bankFar = bankFar;
|
||||||
|
this.targetPlatform = targetPlatform;
|
||||||
|
this.entryExit = entryExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "call_far" + "_" + targetPlatform + "_" + entryExit.name().toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>.
|
* ASM fragment signature for a conditional jump <code>if(A) goto B</code>.
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +43,18 @@ public class Directive {
|
|||||||
public Inline() { super("inline"); }
|
public Inline() { super("inline"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Function declared far. */
|
||||||
|
static public class Far extends Directive {
|
||||||
|
|
||||||
|
public Long bankFar;
|
||||||
|
|
||||||
|
public Far(Long bankFar) {
|
||||||
|
super("__far");
|
||||||
|
this.bankFar = bankFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/** Function declared intrinsic. */
|
/** Function declared intrinsic. */
|
||||||
public static class Intrinsic extends Directive {
|
public static class Intrinsic extends Directive {
|
||||||
public Intrinsic() { super("intrinsic"); }
|
public Intrinsic() { super("intrinsic"); }
|
||||||
|
@ -28,6 +28,8 @@ public class StatementCall extends StatementBase implements StatementLValue, Sta
|
|||||||
private List<RValue> parameters;
|
private List<RValue> parameters;
|
||||||
/** This is the initial assignment of the lValue. */
|
/** This is the initial assignment of the lValue. */
|
||||||
private boolean initialAssignment;
|
private boolean initialAssignment;
|
||||||
|
/** This contains the far call parameters */
|
||||||
|
private Long bankFar;
|
||||||
|
|
||||||
public StatementCall(LValue lValue, String procedureName, List<RValue> parameters, StatementSource source, List<Comment> comments) {
|
public StatementCall(LValue lValue, String procedureName, List<RValue> parameters, StatementSource source, List<Comment> comments) {
|
||||||
super(source, comments);
|
super(source, comments);
|
||||||
@ -64,6 +66,12 @@ public class StatementCall extends StatementBase implements StatementLValue, Sta
|
|||||||
this.parameters = parameters;
|
this.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBankFar(Long bankFar) {
|
||||||
|
this.bankFar = bankFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBankFar() { return this.bankFar; }
|
||||||
|
|
||||||
public int getNumParameters() {
|
public int getNumParameters() {
|
||||||
return parameters.size();
|
return parameters.size();
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,10 @@ public class Procedure extends Scope {
|
|||||||
private boolean variableLengthParameterList;
|
private boolean variableLengthParameterList;
|
||||||
/** true if the procedure is declared inline. */
|
/** true if the procedure is declared inline. */
|
||||||
private boolean declaredInline;
|
private boolean declaredInline;
|
||||||
|
/** true if the procedure is declared far. */
|
||||||
|
private boolean declaredFar;
|
||||||
|
/** contains the far bank. */
|
||||||
|
private Long bankFar;
|
||||||
/** True if the procedure is declared intrinsic. */
|
/** True if the procedure is declared intrinsic. */
|
||||||
private boolean declaredIntrinsic;
|
private boolean declaredIntrinsic;
|
||||||
/** The type of interrupt that the procedure serves. Null for all procedures not serving an interrupt. */
|
/** The type of interrupt that the procedure serves. Null for all procedures not serving an interrupt. */
|
||||||
@ -52,6 +56,8 @@ public class Procedure extends Scope {
|
|||||||
|
|
||||||
/** The method for passing parameters and return value to the procedure. */
|
/** The method for passing parameters and return value to the procedure. */
|
||||||
public enum CallingConvention {
|
public enum CallingConvention {
|
||||||
|
/** Far call in a cx16 bank using the https://github.com/commanderx16/x16-docs/blob/master/X16%20Reference%20-%2004%20-%20KERNAL.md#function-name-jsrfar routine*/
|
||||||
|
FAR_CALL("__far"),
|
||||||
/** Parameters and return value handled through PHI-transitions. */
|
/** Parameters and return value handled through PHI-transitions. */
|
||||||
PHI_CALL("__phicall"),
|
PHI_CALL("__phicall"),
|
||||||
/** Parameters and return value over the stack. */
|
/** Parameters and return value over the stack. */
|
||||||
@ -89,6 +95,8 @@ public class Procedure extends Scope {
|
|||||||
super(name, parentScope, dataSegment);
|
super(name, parentScope, dataSegment);
|
||||||
this.procedureType = procedureType;
|
this.procedureType = procedureType;
|
||||||
this.declaredInline = false;
|
this.declaredInline = false;
|
||||||
|
this.declaredFar = false;
|
||||||
|
this.bankFar = 0L;
|
||||||
this.interruptType = null;
|
this.interruptType = null;
|
||||||
this.comments = new ArrayList<>();
|
this.comments = new ArrayList<>();
|
||||||
this.codeSegment = codeSegment;
|
this.codeSegment = codeSegment;
|
||||||
@ -198,6 +206,20 @@ public class Procedure extends Scope {
|
|||||||
this.declaredInline = declaredInline;
|
this.declaredInline = declaredInline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isDeclaredFar() {
|
||||||
|
return declaredFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeclaredFar(boolean declaredFar) {
|
||||||
|
this.declaredFar = declaredFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getBankFar() { return this.bankFar; }
|
||||||
|
|
||||||
|
public void setBankFar(Long bankFar) {
|
||||||
|
this.bankFar = bankFar;
|
||||||
|
}
|
||||||
|
|
||||||
public String getInterruptType() {
|
public String getInterruptType() {
|
||||||
return interruptType;
|
return interruptType;
|
||||||
}
|
}
|
||||||
@ -258,6 +280,9 @@ public class Procedure extends Scope {
|
|||||||
if(declaredIntrinsic) {
|
if(declaredIntrinsic) {
|
||||||
res.append("__intrinsic ");
|
res.append("__intrinsic ");
|
||||||
}
|
}
|
||||||
|
if(declaredFar) {
|
||||||
|
res.append("__far(").append("bank").append(") ");
|
||||||
|
}
|
||||||
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
|
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
|
||||||
res.append(getCallingConvention().getName()).append(" ");
|
res.append(getCallingConvention().getName()).append(" ");
|
||||||
}
|
}
|
||||||
@ -296,6 +321,7 @@ public class Procedure extends Scope {
|
|||||||
Procedure procedure = (Procedure) o;
|
Procedure procedure = (Procedure) o;
|
||||||
return variableLengthParameterList == procedure.variableLengthParameterList &&
|
return variableLengthParameterList == procedure.variableLengthParameterList &&
|
||||||
declaredInline == procedure.declaredInline &&
|
declaredInline == procedure.declaredInline &&
|
||||||
|
declaredFar == procedure.declaredFar &&
|
||||||
declaredIntrinsic == procedure.declaredIntrinsic &&
|
declaredIntrinsic == procedure.declaredIntrinsic &&
|
||||||
isConstructor == procedure.isConstructor &&
|
isConstructor == procedure.isConstructor &&
|
||||||
Objects.equals(procedureType, procedure.procedureType) &&
|
Objects.equals(procedureType, procedure.procedureType) &&
|
||||||
|
@ -1170,6 +1170,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
if(directive instanceof Directive.Inline) {
|
if(directive instanceof Directive.Inline) {
|
||||||
procedure.setDeclaredInline(true);
|
procedure.setDeclaredInline(true);
|
||||||
procedure.setCallingConvention(Procedure.CallingConvention.PHI_CALL);
|
procedure.setCallingConvention(Procedure.CallingConvention.PHI_CALL);
|
||||||
|
} else if(directive instanceof Directive.Far) {
|
||||||
|
procedure.setDeclaredFar(true);
|
||||||
|
procedure.setBankFar(((Directive.Far) directive).bankFar);
|
||||||
} else if(directive instanceof Directive.CallingConvention) {
|
} else if(directive instanceof Directive.CallingConvention) {
|
||||||
procedure.setCallingConvention(((Directive.CallingConvention) directive).callingConvention);
|
procedure.setCallingConvention(((Directive.CallingConvention) directive).callingConvention);
|
||||||
} else if(directive instanceof Directive.Interrupt) {
|
} else if(directive instanceof Directive.Interrupt) {
|
||||||
@ -1213,6 +1216,17 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
return new Directive.Inline();
|
return new Directive.Inline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitDirectiveFar(KickCParser.DirectiveFarContext ctx) {
|
||||||
|
Long bankFar;
|
||||||
|
if(ctx.getChildCount() > 1) {
|
||||||
|
bankFar = Long.valueOf(ctx.getChild(2).getText());
|
||||||
|
} else {
|
||||||
|
bankFar = 0L;
|
||||||
|
}
|
||||||
|
return new Directive.Far(bankFar);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) {
|
public Object visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) {
|
||||||
return new Directive.Intrinsic();
|
return new Directive.Intrinsic();
|
||||||
|
@ -0,0 +1,71 @@
|
|||||||
|
package dk.camelot64.kickc.passes;
|
||||||
|
|
||||||
|
import dk.camelot64.kickc.model.InternalError;
|
||||||
|
import dk.camelot64.kickc.model.*;
|
||||||
|
import dk.camelot64.kickc.model.iterator.ProgramValue;
|
||||||
|
import dk.camelot64.kickc.model.iterator.ProgramValueHandler;
|
||||||
|
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
|
||||||
|
import dk.camelot64.kickc.model.statements.*;
|
||||||
|
import dk.camelot64.kickc.model.symbols.*;
|
||||||
|
import dk.camelot64.kickc.model.types.SymbolType;
|
||||||
|
import dk.camelot64.kickc.model.values.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
/** Pass that modifies a control flow graph to far call any procedures declared as far */
|
||||||
|
public class Pass1ProcedureFar extends Pass1Base {
|
||||||
|
|
||||||
|
public Pass1ProcedureFar(Program program) {
|
||||||
|
super(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean step() {
|
||||||
|
List<ControlFlowBlock> allBlocks = getGraph().getAllBlocks();
|
||||||
|
ListIterator<ControlFlowBlock> blocksIt = allBlocks.listIterator();
|
||||||
|
while(blocksIt.hasNext()) {
|
||||||
|
ControlFlowBlock block = blocksIt.next();
|
||||||
|
List<Statement> blockStatements = block.getStatements();
|
||||||
|
ListIterator<Statement> statementsIt = blockStatements.listIterator();
|
||||||
|
while(statementsIt.hasNext()) {
|
||||||
|
Statement statement = statementsIt.next();
|
||||||
|
if(statement instanceof StatementCall) {
|
||||||
|
StatementCall call = (StatementCall) statement;
|
||||||
|
ProcedureRef procedureRef = call.getProcedure();
|
||||||
|
Procedure procedure = getScope().getProcedure(procedureRef);
|
||||||
|
if(procedure.isDeclaredFar()) {
|
||||||
|
if(procedure.getInterruptType()!=null) {
|
||||||
|
throw new CompileError("Error! Interrupts cannot be far called. "+procedure.getRef().toString());
|
||||||
|
}
|
||||||
|
farProcedureCall(call, procedure, statementsIt, block, blocksIt);
|
||||||
|
// Exit and restart
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inline a specific call to a procedure.
|
||||||
|
*
|
||||||
|
* @param call The call to the far procedure
|
||||||
|
* @param procedure The procedure being called
|
||||||
|
* @param statementsIt The statement iterator pointing to the call statement
|
||||||
|
* @param block The block containing the call
|
||||||
|
* @param blocksIt The block iterator pointing to the block containing the call
|
||||||
|
*/
|
||||||
|
private void farProcedureCall(StatementCall call, Procedure procedure, ListIterator<Statement> statementsIt, ControlFlowBlock block, ListIterator<ControlFlowBlock> blocksIt) {
|
||||||
|
Scope callScope = getScope().getScope(block.getScope());
|
||||||
|
// Here we add to the call the properties to build a far call depending on the platform.
|
||||||
|
// The all properties have been entered in the __far() directive in the source code.
|
||||||
|
// These properties are then used in pass4 of the compiler, to build the platform dependent fragment to execute the far call.
|
||||||
|
|
||||||
|
call.setBankFar(procedure.getBankFar());
|
||||||
|
getLog().append("Far call " + call.toString(getProgram(), false));
|
||||||
|
}
|
||||||
|
}
|
@ -865,9 +865,22 @@ public class Pass4CodeGeneration {
|
|||||||
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
|
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
if(procedure.isDeclaredFar()) {
|
||||||
|
// Generate ASM for a call (in a bank or other)
|
||||||
|
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call, program), program);
|
||||||
|
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call, program), program);
|
||||||
|
// asm.addInstruction("jsr far", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||||
|
} else {
|
||||||
|
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||||
|
}
|
||||||
} else if (Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
|
} else if (Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
|
||||||
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
if(procedure.isDeclaredFar()) {
|
||||||
|
// Generate ASM for a far call (in a bank or other)
|
||||||
|
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call, program), program);
|
||||||
|
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call, program), program);
|
||||||
|
} else {
|
||||||
|
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (statement instanceof StatementCallExecute) {
|
} else if (statement instanceof StatementCallExecute) {
|
||||||
StatementCallExecute call = (StatementCallExecute) statement;
|
StatementCallExecute call = (StatementCallExecute) statement;
|
||||||
|
11
src/test/kc/procedure-callingconvention-phi-far-0.c
Normal file
11
src/test/kc/procedure-callingconvention-phi-far-0.c
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Test a procedure with calling convention stack
|
||||||
|
|
||||||
|
char* const SCREEN = (char*)0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = plus('0', 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
char __far(1) plus(char a, char b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
11
src/test/kc/procedure-callingconvention-stack-far-0.c
Normal file
11
src/test/kc/procedure-callingconvention-stack-far-0.c
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Test a procedure with calling convention stack
|
||||||
|
|
||||||
|
char* const SCREEN = (char*)0x0400;
|
||||||
|
|
||||||
|
void main(void) {
|
||||||
|
SCREEN[0] = plus('0', 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
char __far(1) __stackcall plus(char a, char b) {
|
||||||
|
return a+b;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user