mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-25 20:32:25 +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_ZEROPAGE: '__zp' ;
|
||||
ADDRESS_MAINMEM: '__mem' ;
|
||||
FAR: '__far' ;
|
||||
FORM_SSA: '__ssa' ;
|
||||
FORM_MA: '__ma' ;
|
||||
INTRINSIC: '__intrinsic' ;
|
||||
|
@ -161,6 +161,7 @@ directive
|
||||
| EXTERN #directiveExtern
|
||||
| EXPORT #directiveExport
|
||||
| INLINE #directiveInline
|
||||
| FAR PAR_BEGIN ( NUMBER ) PAR_END #directiveFar
|
||||
| INTRINSIC #directiveIntrinsic
|
||||
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
|
||||
| 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));
|
||||
}
|
||||
new Pass1ProcedureInline(program).execute();
|
||||
new Pass1ProcedureFar(program).execute(); // Implements far calls to procedures defined in a bank.
|
||||
new PassNStatementIndices(program).step();
|
||||
program.clearCallGraph();
|
||||
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.parser.KickCParser;
|
||||
import dk.camelot64.kickc.parser.KickCParserBaseVisitor;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import org.antlr.v4.runtime.tree.TerminalNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -250,9 +251,13 @@ public class AsmFragmentInstance {
|
||||
|
||||
@Override
|
||||
public Object visitAsmBytes(KickCParser.AsmBytesContext ctx) {
|
||||
List<KickCParser.AsmExprContext> asmExpr = ctx.asmExpr();
|
||||
ArrayList<String> values = new ArrayList<>();
|
||||
for(int i = 1; i < ctx.getChildCount(); i = i + 2) {
|
||||
values.add(ctx.getChild(i).getText());
|
||||
for(int i = 0; i < asmExpr.size(); i++) {
|
||||
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);
|
||||
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.SymbolTypeInference;
|
||||
import dk.camelot64.kickc.model.values.*;
|
||||
import kickass.pass.values.StringValue;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -143,6 +143,7 @@ public class AsmFragmentTemplate {
|
||||
if(signature.contains("c6")) bindings.put("c6", new ConstantInteger(360L));
|
||||
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("c1", new ConstantInteger(400L));
|
||||
AsmFragmentInstance fragmentInstance =
|
||||
new AsmFragmentInstance(new Program(), signature, ScopeRef.ROOT, this, bindings);
|
||||
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>.
|
||||
*/
|
||||
|
@ -43,6 +43,18 @@ public class Directive {
|
||||
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. */
|
||||
public static class Intrinsic extends Directive {
|
||||
public Intrinsic() { super("intrinsic"); }
|
||||
|
@ -28,6 +28,8 @@ public class StatementCall extends StatementBase implements StatementLValue, Sta
|
||||
private List<RValue> parameters;
|
||||
/** This is the initial assignment of the lValue. */
|
||||
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) {
|
||||
super(source, comments);
|
||||
@ -64,6 +66,12 @@ public class StatementCall extends StatementBase implements StatementLValue, Sta
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public void setBankFar(Long bankFar) {
|
||||
this.bankFar = bankFar;
|
||||
}
|
||||
|
||||
public Long getBankFar() { return this.bankFar; }
|
||||
|
||||
public int getNumParameters() {
|
||||
return parameters.size();
|
||||
}
|
||||
|
@ -25,6 +25,10 @@ public class Procedure extends Scope {
|
||||
private boolean variableLengthParameterList;
|
||||
/** true if the procedure is declared inline. */
|
||||
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. */
|
||||
private boolean declaredIntrinsic;
|
||||
/** 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. */
|
||||
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. */
|
||||
PHI_CALL("__phicall"),
|
||||
/** Parameters and return value over the stack. */
|
||||
@ -89,6 +95,8 @@ public class Procedure extends Scope {
|
||||
super(name, parentScope, dataSegment);
|
||||
this.procedureType = procedureType;
|
||||
this.declaredInline = false;
|
||||
this.declaredFar = false;
|
||||
this.bankFar = 0L;
|
||||
this.interruptType = null;
|
||||
this.comments = new ArrayList<>();
|
||||
this.codeSegment = codeSegment;
|
||||
@ -198,6 +206,20 @@ public class Procedure extends Scope {
|
||||
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() {
|
||||
return interruptType;
|
||||
}
|
||||
@ -258,6 +280,9 @@ public class Procedure extends Scope {
|
||||
if(declaredIntrinsic) {
|
||||
res.append("__intrinsic ");
|
||||
}
|
||||
if(declaredFar) {
|
||||
res.append("__far(").append("bank").append(") ");
|
||||
}
|
||||
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
|
||||
res.append(getCallingConvention().getName()).append(" ");
|
||||
}
|
||||
@ -296,6 +321,7 @@ public class Procedure extends Scope {
|
||||
Procedure procedure = (Procedure) o;
|
||||
return variableLengthParameterList == procedure.variableLengthParameterList &&
|
||||
declaredInline == procedure.declaredInline &&
|
||||
declaredFar == procedure.declaredFar &&
|
||||
declaredIntrinsic == procedure.declaredIntrinsic &&
|
||||
isConstructor == procedure.isConstructor &&
|
||||
Objects.equals(procedureType, procedure.procedureType) &&
|
||||
|
@ -1170,6 +1170,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
if(directive instanceof Directive.Inline) {
|
||||
procedure.setDeclaredInline(true);
|
||||
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) {
|
||||
procedure.setCallingConvention(((Directive.CallingConvention) directive).callingConvention);
|
||||
} else if(directive instanceof Directive.Interrupt) {
|
||||
@ -1213,6 +1216,17 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
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
|
||||
public Object visitDirectiveIntrinsic(KickCParser.DirectiveIntrinsicContext ctx) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
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())) {
|
||||
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) {
|
||||
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…
Reference in New Issue
Block a user