1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2024-06-03 07:29:37 +00:00

Merge commit 'db49ca6aabe96f0ca9ec355f33a4fadf33324f93' into far-call-isolated

This commit is contained in:
Flight_Control 2023-03-26 09:52:14 +02:00
commit 19b8de78a4
36 changed files with 191 additions and 375 deletions

View File

@ -75,8 +75,7 @@ LOCAL_RESERVE: '__zp_reserve' ;
ADDRESS: '__address' ;
ADDRESS_ZEROPAGE: '__zp' ;
ADDRESS_MAINMEM: '__mem' ;
FAR: '__far' ;
NEAR: '__near' ;
BANK: '__bank' ;
FORM_SSA: '__ssa' ;
FORM_MA: '__ma' ;
INTRINSIC: '__intrinsic' ;

View File

@ -162,7 +162,7 @@ directive
| EXTERN #directiveExtern
| EXPORT #directiveExport
| INLINE #directiveInline
| FAR PAR_BEGIN NAME COMMA NUMBER (COMMA NAME COMMA NAME COMMA NAME)? PAR_END #directiveFar
| BANK PAR_BEGIN NAME COMMA NUMBER (COMMA NAME COMMA NAME COMMA NAME)? PAR_END #directiveBank
| INTRINSIC #directiveIntrinsic
| INTERRUPT ( PAR_BEGIN NAME PAR_END )? #directiveInterrupt
| LOCAL_RESERVE PAR_BEGIN pragmaParam ( COMMA pragmaParam )* PAR_END #directiveReserveZp

View File

@ -1,4 +0,0 @@
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}

View File

@ -0,0 +1,4 @@
jsr $FFE6
.byte <{la1}
.byte >{la1}
.byte {c1}

View File

@ -0,0 +1,4 @@
jsr $FFE6
.byte <{la1}
.byte >{la1}
.byte {c1}

View File

@ -42,54 +42,55 @@ final public class AsmFragmentInstanceSpecBuilder {
}
/**
* Create a fragment instance spec factory for a far call prepare
* Create a fragment instance spec factory for a bank call prepare
*
* @param bankFar The bank where the procedure is to be called.
* @param bankArea The bank area where the procedure is to be called.
* @param bank The bank where the procedure is to be called.
* @param procedureName The full name of the procedure.
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpec farCallPrepare(Long bankFar, String procedureName, Program program) {
public static AsmFragmentInstanceSpec bankCallPrepare(String bankArea, Long bank, String procedureName, Program program) {
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(bankFar, program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.PrepareExecuteFinalize.Prepare);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(bankArea, bank, program.getTargetPlatform().getName(), AsmFragmentSignature.CallBanked.PrepareExecuteFinalize.Prepare);
ScopeRef codeScope = program.getScope().getRef();
// ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope();
bindings.bind("c1", new ConstantInteger(bankFar));
bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
/**
* Create a fragment instance spec factory for a far call execute
* Create a fragment instance spec factory for a bank call execute
*
* @param bankFar The bank where the procedure is to be called.
* @param bankArea The bank area where the procedure is to be called.
* @param bank The bank where the procedure is to be called.
* @param procedureName The full name of the procedure.
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpec farCallExecute(Long bankFar, String procedureName, Program program) {
public static AsmFragmentInstanceSpec bankCallExecute(String bankArea, Long bank, String procedureName, Program program) {
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(bankFar, program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.PrepareExecuteFinalize.Execute);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(bankArea, bank, program.getTargetPlatform().getName(), AsmFragmentSignature.CallBanked.PrepareExecuteFinalize.Execute);
ScopeRef codeScope = program.getScope().getRef();
// ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope();
bindings.bind("c1", new ConstantInteger(bankFar));
bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
/**
* Create a fragment instance spec factory for a far call finalize
* Create a fragment instance spec factory for a bank call finalize
*
* @param bankFar The bank where the procedure is to be called.
* @param bankArea The bank area where the procedure is to be called.
* @param bank The bank where the procedure is to be called.
* @param procedureName The full name of the procedure.
* @param program The program
* @return the fragment instance spec factory
*/
public static AsmFragmentInstanceSpec farCallFinalize(Long bankFar, String procedureName, Program program) {
public static AsmFragmentInstanceSpec bankCallFinalize(String bankArea, Long bank, String procedureName, Program program) {
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(bankFar, program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.PrepareExecuteFinalize.Finalize);
AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(bankArea, bank, program.getTargetPlatform().getName(), AsmFragmentSignature.CallBanked.PrepareExecuteFinalize.Finalize);
ScopeRef codeScope = program.getScope().getRef();
bindings.bind("c1", new ConstantInteger(bankFar));
bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}

View File

@ -71,11 +71,12 @@ public interface AsmFragmentSignature {
}
/**
* ASM fragment signature for a far jsr <code>if(A) goto B</code>.
* ASM fragment signature for a banked jsr <code>if(A) goto B</code>.
*/
class CallFar implements AsmFragmentSignature {
class CallBanked implements AsmFragmentSignature {
final private Long bankFar;
final private String bankArea;
final private Long bank;
final private String targetPlatform;
public enum PrepareExecuteFinalize {
@ -84,18 +85,19 @@ public interface AsmFragmentSignature {
Finalize
}
final private PrepareExecuteFinalize far;
final private PrepareExecuteFinalize fragment;
public CallFar(Long bankFar, String targetPlatform, PrepareExecuteFinalize far) {
this.bankFar = bankFar;
public CallBanked(String bankArea, Long bank, String targetPlatform, PrepareExecuteFinalize fragment) {
this.bankArea = bankArea;
this.bank = bank;
this.targetPlatform = targetPlatform;
this.far = far;
this.fragment = fragment;
}
@Override
public String getName() {
return "call_far" + "_" + targetPlatform + "_" + far.name().toLowerCase();
return "call_far" + "_" + targetPlatform.toLowerCase() + "_" + bankArea.toLowerCase() + "_" + fragment.name().toLowerCase();
}
}

View File

@ -0,0 +1,25 @@
package dk.camelot64.kickc.model;
/** A Bank segment. */
public class Bank {
private final String bankArea;
private Long bank;
public Bank(String bankArea, Long bank) {
this.bankArea = bankArea;
this.bank = bank;
}
public String getBankArea() {
return bankArea;
}
public Long getBank() {
return bank;
}
public void setBank(Long bank) {
this.bank = bank;
}
}

View File

@ -43,43 +43,24 @@ public class Directive {
public Inline() { super("inline"); }
}
/** Function declared far. */
static public class Far extends Directive {
/** Function declared banked. */
static public class Bank extends Directive {
private String farSegmentName;
private Long farSegmentBank;
private String farProcedurePrepare;
private String farProcedureExecute;
private String farProcedureFinalize;
private String bankArea;
private Long bank;
public Far(String farSegmentName, Long farSegmentBank, String farProcedurePrepare, String farProcedureExecute, String farProcedureFinalize) {
super("far" );
this.farSegmentName = farSegmentName;
this.farSegmentBank = farSegmentBank;
this.farProcedurePrepare = farProcedurePrepare;
this.farProcedureExecute = farProcedureExecute;
this.farProcedureFinalize = farProcedureFinalize;
public Bank(String bankArea, Long bank) {
super("bank" );
this.bankArea = bankArea;
this.bank = bank;
}
public String getFarSegmentName() {
return farSegmentName;
public String getBankArea() {
return bankArea;
}
public Long getFarSegmentBank() {
return farSegmentBank;
}
public String getFarProcedurePrepare() {
return farProcedurePrepare;
}
public String getFarProcedureExecute() {
return farProcedureExecute;
}
public String getFarProcedureFinalize() {
return farProcedureFinalize;
public Long getBank() {
return bank;
}
}

View File

@ -1,43 +0,0 @@
package dk.camelot64.kickc.model;
/** A far segment. */
public class FarSegment {
private final String farSegment;
private Long farBank;
private final String procedurePrepare;
private final String procedureExecute;
private final String procedureFinalize;
public FarSegment(String name, Long bank, String procedurePrepare, String procedureExecute, String procedureFinalize) {
this.farSegment = name;
this.farBank = bank;
this.procedurePrepare = procedurePrepare;
this.procedureExecute = procedureExecute;
this.procedureFinalize = procedureFinalize;
}
public String getFarSegment() {
return farSegment;
}
public Long getFarBank() {
return farBank;
}
public void setFarBank(Long farBank) {
this.farBank = farBank;
}
public String getProcedurePrepare() {
return procedurePrepare;
}
public String getProcedureExecute() {
return procedureExecute;
}
public String getProcedureFinalize() {
return procedureFinalize;
}
}

View File

@ -105,7 +105,7 @@ public class Program {
private NaturalLoopSet loopSet;
/** The register weight of all variables describing how much the variable would theoretically gain from being in a register. PASS 3-5 (CACHED ON-DEMAND) */
private VariableRegisterWeights variableRegisterWeights;
/** All #pragma code segments. Collected during parsing. These are used by the far() pragmas to validate if the code segment exists during compilation.*/
/** All #pragma code segments. Collected during parsing. These are used by the bank() pragmas to validate if the code segment exists during compilation.*/
private final Map<String, KickCParser.PragmaContext> pragmaCodeSegs;
public Program() {

View File

@ -28,8 +28,6 @@ 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);
@ -66,12 +64,6 @@ 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();
}

View File

@ -28,15 +28,11 @@ public class StatementCallExecute extends StatementBase implements StatementCall
/** The calling convention to use. */
private Procedure.CallingConvention callingConvention;
/** This contains the far call parameters */
private Long bankFar;
public StatementCallExecute(SymbolTypeProcedure procedureType, RValue procedure, Procedure.CallingConvention callingConvention, StatementSource source, List<Comment> comments) {
super(source, comments);
this.procedureType = procedureType;
this.procedure = procedure;
this.callingConvention = callingConvention;
this.bankFar = bankFar;
}
public SymbolTypeProcedure getProcedureType() {

View File

@ -1,7 +1,7 @@
package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.Comment;
import dk.camelot64.kickc.model.FarSegment;
import dk.camelot64.kickc.model.Bank;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.types.SymbolType;
@ -26,8 +26,6 @@ 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;
/** 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. */
@ -44,8 +42,8 @@ public class Procedure extends Scope {
private boolean isConstructor;
/** The source of the procedure definition. */
private StatementSource definitionSource;
/** The far segment information. Collected during parsing. These are used to compare with the current currentFarSegment to decide a near or a far call, and to keep inline calling routines.*/
private FarSegment farSegment;
/** The bank segment information. Collected during parsing. These are used to compare with the current currentBank to decide a near or a far call, and to keep inline calling routines.*/
private Bank bankLocation;
/** The names of all legal intrinsic procedures. */
@ -56,12 +54,12 @@ public class Procedure extends Scope {
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4
);
public FarSegment getFarSegment() {
return farSegment;
public Bank getBankLocation() {
return bankLocation;
}
public void setFarSegment(FarSegment farSegment) {
this.farSegment = farSegment;
public void setBankLocation(Bank bankLocation) {
this.bankLocation = bankLocation;
}
@ -100,11 +98,11 @@ public class Procedure extends Scope {
/** The calling convention used for this procedure. */
private CallingConvention callingConvention;
public Procedure(String name, SymbolTypeProcedure procedureType, Scope parentScope, String codeSegment, String dataSegment, CallingConvention callingConvention, FarSegment farSegment) {
public Procedure(String name, SymbolTypeProcedure procedureType, Scope parentScope, String codeSegment, String dataSegment, CallingConvention callingConvention, Bank bankLocation) {
super(name, parentScope, dataSegment);
this.procedureType = procedureType;
this.declaredInline = false;
this.farSegment = farSegment;
this.bankLocation = bankLocation;
this.interruptType = null;
this.comments = new ArrayList<>();
this.codeSegment = codeSegment;
@ -214,17 +212,24 @@ public class Procedure extends Scope {
this.declaredInline = declaredInline;
}
public boolean isDeclaredFar() {
return farSegment != null;
public boolean isDeclaredBanked() {
return bankLocation != null;
}
public Long getFarBank() {
if(farSegment!=null)
return farSegment.getFarBank();
public Long getBank() {
if(bankLocation != null)
return bankLocation.getBank();
else
return 0L;
}
public String getBankArea() {
if(bankLocation != null)
return bankLocation.getBankArea();
else
return "";
}
public String getInterruptType() {
return interruptType;
}
@ -285,8 +290,8 @@ public class Procedure extends Scope {
if(declaredIntrinsic) {
res.append("__intrinsic ");
}
if(declaredFar) {
res.append("__far(").append("bank").append(") ");
if(isDeclaredBanked()) {
res.append("__bank(").append("bank").append(") ");
}
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
res.append(getCallingConvention().getName()).append(" ");
@ -326,7 +331,7 @@ public class Procedure extends Scope {
Procedure procedure = (Procedure) o;
return variableLengthParameterList == procedure.variableLengthParameterList &&
declaredInline == procedure.declaredInline &&
declaredFar == procedure.declaredFar &&
isDeclaredBanked() == procedure.isDeclaredBanked() &&
declaredIntrinsic == procedure.declaredIntrinsic &&
isConstructor == procedure.isConstructor &&
Objects.equals(procedureType, procedure.procedureType) &&

View File

@ -16,8 +16,8 @@ public abstract class Scope implements Symbol {
public static final String SEGMENT_CODE_DEFAULT = "Code";
/** The default data segment. */
public static final String SEGMENT_DATA_DEFAULT = "Data";
/** The default far segment. */
public static final String SEGMENT_FAR_DEFAULT = "";
/** The default bank segment. */
public static final Long SEGMENT_BANK_DEFAULT = -1L;
private String name;
private HashMap<String, Symbol> symbols;

View File

@ -107,13 +107,13 @@ public class CParser {
*/
public static final String PRAGMA_RESOURCE = "resource";
/**
* #pragma far(...) specifies the scope of the sequent functions to be far. Segments are defined in the linker file.
* #pragma bank(...) specifies the scope of the sequent functions to be located in a bank using a specific banking area.
*/
public static final String PRAGMA_FAR = "far";
public static final String PRAGMA_BANK = "bank";
/**
* #pragma near specifies the scope of the sequent functions to be near. Segments are defined in the linker file.
* #pragma nobank specifies the scope of the sequent functions to be near. Segments are defined in the linker file.
*/
public static final String PRAGMA_NEAR = "near";
public static final String PRAGMA_NOBANK = "nobank";
/**
* The Program.

View File

@ -295,20 +295,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
case CParser.PRAGMA_DATA_SEG:
this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx));
break;
case CParser.PRAGMA_FAR:
case CParser.PRAGMA_BANK:
try {
final int size = ctx.getChildCount();
if(size==7) {
final String pragmaFarSegment = pragmaParamFarSegment(ctx.pragmaParam(0));
final Number pragmaFarBank = pragmaParamNumber(ctx.pragmaParam(1));
if (size > 7) {
final String call_prepare = pragmaParamName(ctx.pragmaParam(2));
final String call_execute = pragmaParamName(ctx.pragmaParam(3));
final String call_finalize = pragmaParamName(ctx.pragmaParam(4));
this.currentFarSegment = new FarSegment(pragmaFarSegment, pragmaFarBank.longValue(), call_prepare, call_execute, call_finalize);
} else {
this.currentFarSegment = new FarSegment(pragmaFarSegment, pragmaFarBank.longValue(), "", "", "");
}
final String pragmaBankArea = pragmaParamBankArea(ctx.pragmaParam(0));
final Number pragmaBank = pragmaParamNumber(ctx.pragmaParam(1));
this.currentBank = new Bank(pragmaBankArea, pragmaBank.longValue());
} else {
throw new CompileError("Expected at least 2 pragma parameters. Found '" + ctx.getText() + "'.", new StatementSource(ctx));
}
@ -316,8 +309,8 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
throw new CompileError("Illegal parameter " + ctx.getText(), new StatementSource(ctx));
}
break;
case CParser.PRAGMA_NEAR:
this.currentFarSegment = null; // When the current far segment is null, any function that is far will be called as far.
case CParser.PRAGMA_NOBANK:
this.currentBank = null; // When the current far segment is null, any function that is far will be called as far.
break;
case CParser.PRAGMA_RESOURCE:
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
@ -393,21 +386,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
/**
* Parse the FAR parameter of a #pragma
* If the parameter is not a FAR the compiler will fail out
* Parse the BANK AREA parameter of a #pragma
* If the parameter is not a BANK AREA the compiler will fail out
*
* @param paramCtx The parameter to parse
* @return The name
*/
private String pragmaParamFarSegment(KickCParser.PragmaParamContext paramCtx) {
private String pragmaParamBankArea(KickCParser.PragmaParamContext paramCtx) {
if(!(paramCtx instanceof KickCParser.PragmaParamNameContext))
throw new CompileError("Expected a FAR parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
final String pragmaFarSegment = ((KickCParser.PragmaParamNameContext) paramCtx).NAME().getText();
if(this.program.getPragmaCodeSegs().get(pragmaFarSegment) != null) {
return pragmaFarSegment;
} else {
throw new CompileError("Expected a previously declared CODE_SEG parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
}
throw new CompileError("Expected a BANK AREA parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
final String pragmaBankArea = ((KickCParser.PragmaParamNameContext) paramCtx).NAME().getText();
// if(this.program.getPragmaCodeSegs().get(pragmaBankArea) != null) {
// return pragmaBankArea;
// } else {
// throw new CompileError("Expected a previously declared CODE_SEG parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent()));
// }
return pragmaBankArea;
}
@ -480,7 +474,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
/** The current far segment. */
private FarSegment currentFarSegment;
private Bank currentBank;
/** The current default interrupt type. */
private String currentInterruptType;
@ -537,7 +531,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
*/
private Procedure declareProcedure(boolean defineProcedure, ParserRuleContext ctx, StatementSource statementSource) {
Procedure procedure = new Procedure(varDecl.getVarName(), (SymbolTypeProcedure) varDecl.getEffectiveType(), program.getScope(), currentCodeSegment, currentDataSegment, currentCallingConvention, currentFarSegment);
Procedure procedure = new Procedure(varDecl.getVarName(), (SymbolTypeProcedure) varDecl.getEffectiveType(), program.getScope(), currentCodeSegment, currentDataSegment, currentCallingConvention, currentBank);
addDirectives(procedure, varDecl.getDeclDirectives(), statementSource);
// Check if the declaration matches any existing declaration!
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
@ -1216,9 +1210,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) {
FarSegment farSegment = new FarSegment(((Directive.Far) directive).getFarSegmentName(), ((Directive.Far) directive).getFarSegmentBank(), ((Directive.Far) directive).getFarProcedurePrepare(), ((Directive.Far) directive).getFarProcedureExecute(), ((Directive.Far) directive).getFarProcedureFinalize());
procedure.setFarSegment(farSegment);
} else if(directive instanceof Directive.Bank) {
Bank bank = new Bank(((Directive.Bank) directive).getBankArea(), ((Directive.Bank) directive).getBank());
procedure.setBankLocation(bank);
} else if(directive instanceof Directive.CallingConvention) {
procedure.setCallingConvention(((Directive.CallingConvention) directive).callingConvention);
} else if(directive instanceof Directive.Interrupt) {
@ -1263,32 +1257,20 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
}
@Override
public Object visitDirectiveFar(KickCParser.DirectiveFarContext ctx) {
String farSegmentName = "";
Long farSegmentBank = 0L;
String farProcedurePrepare = null;
String farProcedureExecute = null;
String farProcedureFinalize = null;
if(this.currentFarSegment != null) {
farSegmentName = this.currentFarSegment.getFarSegment();
farSegmentBank = this.currentFarSegment.getFarBank();
farProcedurePrepare = this.currentFarSegment.getProcedurePrepare();
farProcedureExecute = this.currentFarSegment.getProcedureExecute();
farProcedureFinalize = this.currentFarSegment.getProcedureFinalize();
public Object visitDirectiveBank(KickCParser.DirectiveBankContext ctx) {
String bankArea = "";
Long bank = -1L;
if(this.currentBank != null) {
bankArea = this.currentBank.getBankArea();
bank = this.currentBank.getBank();
}
if(ctx.getChildCount() >= 5) {
farSegmentName = ctx.getChild(2).getText();
farSegmentBank = Long.valueOf(ctx.getChild(4).getText());
bankArea = ctx.getChild(2).getText();
bank = Long.valueOf(ctx.getChild(4).getText());
}
if(ctx.getChildCount() == 11) {
farProcedurePrepare = ctx.getChild(6).getText();
farProcedureExecute = ctx.getChild(8).getText();
farProcedureFinalize = ctx.getChild(10).getText();
}
return new Directive.Far(farSegmentName, farSegmentBank, farProcedurePrepare, farProcedureExecute, farProcedureFinalize);
return new Directive.Bank(bankArea, bank);
}
@Override

View File

@ -1,71 +0,0 @@
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);
// Continue
// return true;
}
}
}
}
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));
}
}

View File

@ -867,36 +867,26 @@ public class Pass4CodeGeneration {
}
}
// Note: I've chosen to keep this code duplication between phi and stack calling convention, for later maintenance flexibility, if any.
// We check if the procedure is declared as far, and if the calling procedure is not in the same bank as the procedure called.
if(procedure.isDeclaredFar() && procedureFrom.getFarBank() != procedure.getFarBank()) {
// We check if the procedure is declared as banked, and if the calling procedure is not in the same bank as the procedure called.
if(procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) {
// In this case, Generate ASM for a far call.
// The call is constructed in a prepare, execute and finalize compiler .asm fragments respectively.
// The bank and other preparations are set in the far_call_[platform]_prepare.asm fragment.
// The actual jsr statement is embedded in the far_call_[platform]_execute.asm fragment.
// After the jsr, finalization of the call is defined in the far_call_[platform]_finalize.asm fragment.
// TODO: rework to prepare, execute, finalize
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallPrepare(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExecute(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallFinalize(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
// asm.addInstruction("jsr far", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
// The bank and other preparations are set in the call_far_[platform]_[bankarea]_prepare.asm fragment.
// The actual jsr statement is embedded in the far_call_[platform]_[bankarea]_execute.asm fragment.
// After the jsr, finalization of the call is defined in the far_call_[platform]_[bankarea]_finalize.asm fragment.
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
} else {
// Otherwise, Generate AM for a normal near call.
// In case of a far call, we assume the bank does not need to be changed.
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
}
} else if (Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
// Note: I've chosen to keep this code duplication between phi and stack calling convention, for later maintenance flexibility, if any.
// We check if the procedure is declared as far, and if the calling procedure is not in the same bank as the procedure called.
if(procedure.isDeclaredFar() && procedure.getFarBank() != procedureFrom.getFarBank()) {
// In this case, Generate ASM for a far call.
// The call is constructed in a prepare, execute and finalize compiler .asm fragments respectively.
// The bank and other preparations are set in the far_call_[platform]_prepare.asm fragment.
// The actual jsr statement is embedded in the far_call_[platform]_execute.asm fragment.
// After the jsr, finalization of the call is defined in the far_call_[platform]_finalize.asm fragment.
// TODO: rework to prepare, execute, finalize
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallPrepare(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExecute(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallFinalize(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
// Same as PHI
if(procedure.isDeclaredBanked() && procedure.getBank() != procedureFrom.getBank()) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
} else {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
}
@ -907,11 +897,11 @@ public class Pass4CodeGeneration {
Procedure procedure = getScope().getProcedure(call.getProcedure());
Procedure procedureFrom = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality.
RValue procedureRVal = call.getProcedureRVal();
// Generate ASM for a call
if(procedure.isDeclaredFar() && procedureFrom.getFarBank() != procedure.getFarBank()) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallPrepare(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExecute(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallFinalize(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program);
// Same as PHI
if(procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
} else {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
}

View File

@ -7,6 +7,6 @@ void main(void) {
}
#pragma code_seg(stage)
char __far(stage,2) plus(char a, char b) {
char __bank(ram,2) plus(char a, char b) {
return a+b;
}

View File

@ -7,24 +7,8 @@ void main(void) {
}
#pragma code_seg(stage)
#pragma far(stage, 1)
#pragma bank(ram, 1)
char plus(char a, char b) {
return a+b;
}
void stage_entry() {
asm {
lda 0
pha
lda #1
sta 0
}
}
void stage_exit() {
asm {
pla
sta 0
}
}

View File

@ -7,24 +7,9 @@ void main(void) {
}
#pragma code_seg(stage)
#pragma far(stage)
#pragma bank(rubbish, 1)
char plus(char a, char b) {
return a+b;
}
void stage_entry() {
asm {
lda 0
pha
lda #1
sta 0
}
}
void stage_exit() {
asm {
pla
sta 0
}
}

View File

@ -0,0 +1,14 @@
// Test a far call procedure with a calling convention sp
char* const SCREEN = (char*)0x0400;
void main(void) {
SCREEN[0] = plus('0', 7);
}
#pragma code_seg(stage)
#pragma bank(stage, 2)
char plus(char a, char b) {
return a+b;
}

View File

@ -3,13 +3,13 @@
char* const SCREEN = (char*)0x0400;
#pragma code_seg(stage)
#pragma far(stage, 20)
#pragma bank(stage, 20)
char plus(char a, char b) {
return a+b;
}
#pragma near
#pragma nobank
void main(void) {
SCREEN[0] = plus('0', 7);

View File

@ -3,7 +3,7 @@
char* const SCREEN = (char*)0x0400;
#pragma code_seg(bank_1)
#pragma far(bank_1, 1)
#pragma bank(ram, 1)
char func_bank1_a(char a, char b) {
return a+b;
@ -20,7 +20,7 @@ char func_bank1_d(char a, char b) {
}
#pragma code_seg(bank_2)
#pragma far(bank_2, 2)
#pragma bank(ram, 2)
char func_bank2_a(char a, char b) {
return a+b;
@ -47,17 +47,17 @@ char func_bank2_f(char a, char b) {
return func_bank1_b(a,b);
}
#pragma near
#pragma nobank
char __far(bank_1, 1) func_bank1_b(char a, char b) {
char __bank(ram, 1) func_bank1_b(char a, char b) {
return a+b;
}
char __far(bank_2, 2) func_bank2_b(char a, char b) {
char __bank(ram, 2) func_bank2_b(char a, char b) {
return a+b;
}
#pragma near
#pragma nobank
char func_bank1_e(char a, char b) {
// this should be a far call, because the call is to bank 1.

View File

@ -1,30 +0,0 @@
// Test a far call procedure with a calling convention sp
char* const SCREEN = (char*)0x0400;
void main(void) {
SCREEN[0] = plus('0', 7);
}
#pragma code_seg(stage)
#pragma far(rubbish, 1, stage_prepare, stage_execution, stage_exit)
char plus(char a, char b) {
return a+b;
}
void stage_entry() {
asm {
lda 0
pha
lda #1
sta 0
}
}
void stage_exit() {
asm {
pla
sta 0
}
}

View File

@ -7,6 +7,6 @@ void main(void) {
}
#pragma code_seg(test)
char __far(test, 2) __stackcall plus(char a, char b) {
char __bank(ram, 2) __stackcall plus(char a, char b) {
return a+b;
}

View File

@ -9,6 +9,6 @@ void main(void) {
#pragma calling(__stackcall)
#pragma code_seg(test)
char __far(test,20) plus(char a, char b) {
char __bank(ram,20) plus(char a, char b) {
return a+b;
}

View File

@ -14,7 +14,7 @@ void main(void) {
}
// this should give a pragma error during compile, as test is not declared yet.
char __far(test, 20) __stackcall plus(char a, char b) {
char __bank(ram, 20) __stackcall plus(char a, char b) {
i++;
return a+b;
}

View File

@ -20,23 +20,23 @@ void main(void) {
#pragma code_seg(test3)
#pragma code_seg(Code)
void __far(test, 20) pval() {
void __bank(ram, 20) pval() {
printval();
}
void __far(test2, 21) ival() {
void __bank(ram, 21) ival() {
incval();
}
void __far(test, 20) printval() {
void __bank(ram, 20) printval() {
SCREEN[0] = val;
}
void __far(test2, 21) incval() {
void __bank(ram, 21) incval() {
val++;
}
#pragma near
#pragma nobank
void printother() {
for(char i:0..5) {

View File

@ -19,12 +19,12 @@ void main(void) {
}
}
struct Point __far(1) get(char i) {
struct Point __bank(ram,1) get(char i) {
struct Point p = { i, i/2 };
return p;
}
void __far(2) print(struct Point p) {
void __bank(ram,2) print(struct Point p) {
SCREEN[idx++] = p.x;
SCREEN[idx++] = p.y;
}

View File

@ -7,7 +7,7 @@ void main(void) {
*SCREEN = pow2(6);
}
char __stackcall __far(1) pow2(char n) {
char __stackcall __bank(ram,1) pow2(char n) {
if (n == 0)
return 1;
else {