1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-01-15 01:33:11 +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: '__address' ;
ADDRESS_ZEROPAGE: '__zp' ; ADDRESS_ZEROPAGE: '__zp' ;
ADDRESS_MAINMEM: '__mem' ; ADDRESS_MAINMEM: '__mem' ;
FAR: '__far' ; BANK: '__bank' ;
NEAR: '__near' ;
FORM_SSA: '__ssa' ; FORM_SSA: '__ssa' ;
FORM_MA: '__ma' ; FORM_MA: '__ma' ;
INTRINSIC: '__intrinsic' ; INTRINSIC: '__intrinsic' ;

View File

@ -162,7 +162,7 @@ directive
| EXTERN #directiveExtern | EXTERN #directiveExtern
| EXPORT #directiveExport | EXPORT #directiveExport
| INLINE #directiveInline | 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 | 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

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 procedureName The full name of the procedure.
* @param program The program * @param program The program
* @return the fragment instance spec factory * @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); 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.getScope().getRef();
// ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope(); bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("c1", new ConstantInteger(bankFar));
bindings.bind("la1", new LabelRef(procedureName)); bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); 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 procedureName The full name of the procedure.
* @param program The program * @param program The program
* @return the fragment instance spec factory * @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); 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.getScope().getRef();
// ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope(); bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("c1", new ConstantInteger(bankFar));
bindings.bind("la1", new LabelRef(procedureName)); bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); 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 procedureName The full name of the procedure.
* @param program The program * @param program The program
* @return the fragment instance spec factory * @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); 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(); ScopeRef codeScope = program.getScope().getRef();
bindings.bind("c1", new ConstantInteger(bankFar)); bindings.bind("c1", new ConstantInteger(bank));
bindings.bind("la1", new LabelRef(procedureName)); bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); 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; final private String targetPlatform;
public enum PrepareExecuteFinalize { public enum PrepareExecuteFinalize {
@ -84,18 +85,19 @@ public interface AsmFragmentSignature {
Finalize Finalize
} }
final private PrepareExecuteFinalize far; final private PrepareExecuteFinalize fragment;
public CallFar(Long bankFar, String targetPlatform, PrepareExecuteFinalize far) { public CallBanked(String bankArea, Long bank, String targetPlatform, PrepareExecuteFinalize fragment) {
this.bankFar = bankFar; this.bankArea = bankArea;
this.bank = bank;
this.targetPlatform = targetPlatform; this.targetPlatform = targetPlatform;
this.far = far; this.fragment = fragment;
} }
@Override @Override
public String getName() { 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"); } public Inline() { super("inline"); }
} }
/** Function declared far. */ /** Function declared banked. */
static public class Far extends Directive { static public class Bank extends Directive {
private String farSegmentName; private String bankArea;
private Long farSegmentBank; private Long bank;
private String farProcedurePrepare;
private String farProcedureExecute;
private String farProcedureFinalize;
public Bank(String bankArea, Long bank) {
public Far(String farSegmentName, Long farSegmentBank, String farProcedurePrepare, String farProcedureExecute, String farProcedureFinalize) { super("bank" );
super("far" ); this.bankArea = bankArea;
this.farSegmentName = farSegmentName; this.bank = bank;
this.farSegmentBank = farSegmentBank;
this.farProcedurePrepare = farProcedurePrepare;
this.farProcedureExecute = farProcedureExecute;
this.farProcedureFinalize = farProcedureFinalize;
} }
public String getFarSegmentName() { public String getBankArea() {
return farSegmentName; return bankArea;
} }
public Long getFarSegmentBank() { public Long getBank() {
return farSegmentBank; return bank;
}
public String getFarProcedurePrepare() {
return farProcedurePrepare;
}
public String getFarProcedureExecute() {
return farProcedureExecute;
}
public String getFarProcedureFinalize() {
return farProcedureFinalize;
} }
} }

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; 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) */ /** 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; 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; private final Map<String, KickCParser.PragmaContext> pragmaCodeSegs;
public Program() { public Program() {

View File

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

View File

@ -28,15 +28,11 @@ public class StatementCallExecute extends StatementBase implements StatementCall
/** The calling convention to use. */ /** The calling convention to use. */
private Procedure.CallingConvention callingConvention; 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) { public StatementCallExecute(SymbolTypeProcedure procedureType, RValue procedure, Procedure.CallingConvention callingConvention, StatementSource source, List<Comment> comments) {
super(source, comments); super(source, comments);
this.procedureType = procedureType; this.procedureType = procedureType;
this.procedure = procedure; this.procedure = procedure;
this.callingConvention = callingConvention; this.callingConvention = callingConvention;
this.bankFar = bankFar;
} }
public SymbolTypeProcedure getProcedureType() { public SymbolTypeProcedure getProcedureType() {

View File

@ -1,7 +1,7 @@
package dk.camelot64.kickc.model.symbols; package dk.camelot64.kickc.model.symbols;
import dk.camelot64.kickc.model.Comment; 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.Program;
import dk.camelot64.kickc.model.statements.StatementSource; import dk.camelot64.kickc.model.statements.StatementSource;
import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolType;
@ -26,8 +26,6 @@ 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;
/** 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. */
@ -44,8 +42,8 @@ public class Procedure extends Scope {
private boolean isConstructor; private boolean isConstructor;
/** The source of the procedure definition. */ /** The source of the procedure definition. */
private StatementSource definitionSource; 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.*/ /** 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 FarSegment farSegment; private Bank bankLocation;
/** The names of all legal intrinsic procedures. */ /** The names of all legal intrinsic procedures. */
@ -56,12 +54,12 @@ public class Procedure extends Scope {
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4 Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4
); );
public FarSegment getFarSegment() { public Bank getBankLocation() {
return farSegment; return bankLocation;
} }
public void setFarSegment(FarSegment farSegment) { public void setBankLocation(Bank bankLocation) {
this.farSegment = farSegment; this.bankLocation = bankLocation;
} }
@ -100,11 +98,11 @@ public class Procedure extends Scope {
/** The calling convention used for this procedure. */ /** The calling convention used for this procedure. */
private CallingConvention callingConvention; 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); super(name, parentScope, dataSegment);
this.procedureType = procedureType; this.procedureType = procedureType;
this.declaredInline = false; this.declaredInline = false;
this.farSegment = farSegment; this.bankLocation = bankLocation;
this.interruptType = null; this.interruptType = null;
this.comments = new ArrayList<>(); this.comments = new ArrayList<>();
this.codeSegment = codeSegment; this.codeSegment = codeSegment;
@ -214,17 +212,24 @@ public class Procedure extends Scope {
this.declaredInline = declaredInline; this.declaredInline = declaredInline;
} }
public boolean isDeclaredFar() { public boolean isDeclaredBanked() {
return farSegment != null; return bankLocation != null;
} }
public Long getFarBank() { public Long getBank() {
if(farSegment!=null) if(bankLocation != null)
return farSegment.getFarBank(); return bankLocation.getBank();
else else
return 0L; return 0L;
} }
public String getBankArea() {
if(bankLocation != null)
return bankLocation.getBankArea();
else
return "";
}
public String getInterruptType() { public String getInterruptType() {
return interruptType; return interruptType;
} }
@ -285,8 +290,8 @@ public class Procedure extends Scope {
if(declaredIntrinsic) { if(declaredIntrinsic) {
res.append("__intrinsic "); res.append("__intrinsic ");
} }
if(declaredFar) { if(isDeclaredBanked()) {
res.append("__far(").append("bank").append(") "); res.append("__bank(").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(" ");
@ -326,7 +331,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 && isDeclaredBanked() == procedure.isDeclaredBanked() &&
declaredIntrinsic == procedure.declaredIntrinsic && declaredIntrinsic == procedure.declaredIntrinsic &&
isConstructor == procedure.isConstructor && isConstructor == procedure.isConstructor &&
Objects.equals(procedureType, procedure.procedureType) && 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"; public static final String SEGMENT_CODE_DEFAULT = "Code";
/** The default data segment. */ /** The default data segment. */
public static final String SEGMENT_DATA_DEFAULT = "Data"; public static final String SEGMENT_DATA_DEFAULT = "Data";
/** The default far segment. */ /** The default bank segment. */
public static final String SEGMENT_FAR_DEFAULT = ""; public static final Long SEGMENT_BANK_DEFAULT = -1L;
private String name; private String name;
private HashMap<String, Symbol> symbols; private HashMap<String, Symbol> symbols;

View File

@ -107,13 +107,13 @@ public class CParser {
*/ */
public static final String PRAGMA_RESOURCE = "resource"; 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. * The Program.

View File

@ -295,20 +295,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
case CParser.PRAGMA_DATA_SEG: case CParser.PRAGMA_DATA_SEG:
this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx)); this.currentDataSegment = pragmaParamName(pragmaParamSingle(ctx));
break; break;
case CParser.PRAGMA_FAR: case CParser.PRAGMA_BANK:
try { try {
final int size = ctx.getChildCount(); final int size = ctx.getChildCount();
if(size==7) { if(size==7) {
final String pragmaFarSegment = pragmaParamFarSegment(ctx.pragmaParam(0)); final String pragmaBankArea = pragmaParamBankArea(ctx.pragmaParam(0));
final Number pragmaFarBank = pragmaParamNumber(ctx.pragmaParam(1)); final Number pragmaBank = pragmaParamNumber(ctx.pragmaParam(1));
if (size > 7) { this.currentBank = new Bank(pragmaBankArea, pragmaBank.longValue());
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(), "", "", "");
}
} else { } else {
throw new CompileError("Expected at least 2 pragma parameters. Found '" + ctx.getText() + "'.", new StatementSource(ctx)); 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)); throw new CompileError("Illegal parameter " + ctx.getText(), new StatementSource(ctx));
} }
break; break;
case CParser.PRAGMA_NEAR: case CParser.PRAGMA_NOBANK:
this.currentFarSegment = null; // When the current far segment is null, any function that is far will be called as far. this.currentBank = null; // When the current far segment is null, any function that is far will be called as far.
break; break;
case CParser.PRAGMA_RESOURCE: case CParser.PRAGMA_RESOURCE:
String resourceFileName = pragmaParamString(pragmaParamSingle(ctx)); String resourceFileName = pragmaParamString(pragmaParamSingle(ctx));
@ -393,21 +386,22 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} }
/** /**
* Parse the FAR parameter of a #pragma * Parse the BANK AREA parameter of a #pragma
* If the parameter is not a FAR the compiler will fail out * If the parameter is not a BANK AREA the compiler will fail out
* *
* @param paramCtx The parameter to parse * @param paramCtx The parameter to parse
* @return The name * @return The name
*/ */
private String pragmaParamFarSegment(KickCParser.PragmaParamContext paramCtx) { private String pragmaParamBankArea(KickCParser.PragmaParamContext paramCtx) {
if(!(paramCtx instanceof KickCParser.PragmaParamNameContext)) if(!(paramCtx instanceof KickCParser.PragmaParamNameContext))
throw new CompileError("Expected a FAR 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 pragmaFarSegment = ((KickCParser.PragmaParamNameContext) paramCtx).NAME().getText(); final String pragmaBankArea = ((KickCParser.PragmaParamNameContext) paramCtx).NAME().getText();
if(this.program.getPragmaCodeSegs().get(pragmaFarSegment) != null) { // if(this.program.getPragmaCodeSegs().get(pragmaBankArea) != null) {
return pragmaFarSegment; // return pragmaBankArea;
} else { // } else {
throw new CompileError("Expected a previously declared CODE_SEG parameter. Found '" + paramCtx.getText() + "'.", new StatementSource(paramCtx.getParent())); // 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; private String currentDataSegment = Scope.SEGMENT_DATA_DEFAULT;
/** The current far segment. */ /** The current far segment. */
private FarSegment currentFarSegment; private Bank currentBank;
/** The current default interrupt type. */ /** The current default interrupt type. */
private String currentInterruptType; private String currentInterruptType;
@ -537,7 +531,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
*/ */
private Procedure declareProcedure(boolean defineProcedure, ParserRuleContext ctx, StatementSource statementSource) { 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); addDirectives(procedure, varDecl.getDeclDirectives(), statementSource);
// Check if the declaration matches any existing declaration! // Check if the declaration matches any existing declaration!
final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef()); final Symbol existingSymbol = program.getScope().getSymbol(procedure.getRef());
@ -1216,9 +1210,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) { } else if(directive instanceof Directive.Bank) {
FarSegment farSegment = new FarSegment(((Directive.Far) directive).getFarSegmentName(), ((Directive.Far) directive).getFarSegmentBank(), ((Directive.Far) directive).getFarProcedurePrepare(), ((Directive.Far) directive).getFarProcedureExecute(), ((Directive.Far) directive).getFarProcedureFinalize()); Bank bank = new Bank(((Directive.Bank) directive).getBankArea(), ((Directive.Bank) directive).getBank());
procedure.setFarSegment(farSegment); procedure.setBankLocation(bank);
} 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) {
@ -1263,32 +1257,20 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
} }
@Override @Override
public Object visitDirectiveFar(KickCParser.DirectiveFarContext ctx) { public Object visitDirectiveBank(KickCParser.DirectiveBankContext ctx) {
String farSegmentName = ""; String bankArea = "";
Long farSegmentBank = 0L; Long bank = -1L;
String farProcedurePrepare = null; if(this.currentBank != null) {
String farProcedureExecute = null; bankArea = this.currentBank.getBankArea();
String farProcedureFinalize = null; bank = this.currentBank.getBank();
if(this.currentFarSegment != null) {
farSegmentName = this.currentFarSegment.getFarSegment();
farSegmentBank = this.currentFarSegment.getFarBank();
farProcedurePrepare = this.currentFarSegment.getProcedurePrepare();
farProcedureExecute = this.currentFarSegment.getProcedureExecute();
farProcedureFinalize = this.currentFarSegment.getProcedureFinalize();
} }
if(ctx.getChildCount() >= 5) { if(ctx.getChildCount() >= 5) {
farSegmentName = ctx.getChild(2).getText(); bankArea = ctx.getChild(2).getText();
farSegmentBank = Long.valueOf(ctx.getChild(4).getText()); bank = Long.valueOf(ctx.getChild(4).getText());
} }
if(ctx.getChildCount() == 11) { return new Directive.Bank(bankArea, bank);
farProcedurePrepare = ctx.getChild(6).getText();
farProcedureExecute = ctx.getChild(8).getText();
farProcedureFinalize = ctx.getChild(10).getText();
}
return new Directive.Far(farSegmentName, farSegmentBank, farProcedurePrepare, farProcedureExecute, farProcedureFinalize);
} }
@Override @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. // 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. // 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.isDeclaredFar() && procedureFrom.getFarBank() != procedure.getFarBank()) { if(procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) {
// In this case, Generate ASM for a far call. // In this case, Generate ASM for a far call.
// The call is constructed in a prepare, execute and finalize compiler .asm fragments respectively. // 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 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]_execute.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]_finalize.asm fragment. // After the jsr, finalization of the call is defined in the far_call_[platform]_[bankarea]_finalize.asm fragment.
// TODO: rework to prepare, execute, finalize AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallPrepare(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExecute(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), 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);
} else { } else {
// Otherwise, Generate AM for a normal near call. // 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); 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())) {
// Note: I've chosen to keep this code duplication between phi and stack calling convention, for later maintenance flexibility, if any. // Same as PHI
// 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.isDeclaredBanked() && procedure.getBank() != procedureFrom.getBank()) {
if(procedure.isDeclaredFar() && procedure.getFarBank() != procedureFrom.getFarBank()) { AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
// In this case, Generate ASM for a far call. AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
// The call is constructed in a prepare, execute and finalize compiler .asm fragments respectively. AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
// 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);
} else { } else {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} }
@ -907,11 +897,11 @@ public class Pass4CodeGeneration {
Procedure procedure = getScope().getProcedure(call.getProcedure()); 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. Procedure procedureFrom = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality.
RValue procedureRVal = call.getProcedureRVal(); RValue procedureRVal = call.getProcedureRVal();
// Generate ASM for a call // Same as PHI
if(procedure.isDeclaredFar() && procedureFrom.getFarBank() != procedure.getFarBank()) { if(procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallPrepare(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExecute(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallFinalize(procedure.getFarSegment().getFarBank(), call.getProcedure().getFullName(), program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program);
} else { } else {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
} }

View File

@ -7,6 +7,6 @@ void main(void) {
} }
#pragma code_seg(stage) #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; return a+b;
} }

View File

@ -7,24 +7,8 @@ void main(void) {
} }
#pragma code_seg(stage) #pragma code_seg(stage)
#pragma far(stage, 1) #pragma bank(ram, 1)
char plus(char a, char b) { char plus(char a, char b) {
return a+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 code_seg(stage)
#pragma far(stage) #pragma bank(rubbish, 1)
char plus(char a, char b) { char plus(char a, char b) {
return a+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; char* const SCREEN = (char*)0x0400;
#pragma code_seg(stage) #pragma code_seg(stage)
#pragma far(stage, 20) #pragma bank(stage, 20)
char plus(char a, char b) { char plus(char a, char b) {
return a+b; return a+b;
} }
#pragma near #pragma nobank
void main(void) { void main(void) {
SCREEN[0] = plus('0', 7); SCREEN[0] = plus('0', 7);

View File

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

View File

@ -9,6 +9,6 @@ void main(void) {
#pragma calling(__stackcall) #pragma calling(__stackcall)
#pragma code_seg(test) #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; 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. // 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++; i++;
return a+b; return a+b;
} }

View File

@ -20,23 +20,23 @@ void main(void) {
#pragma code_seg(test3) #pragma code_seg(test3)
#pragma code_seg(Code) #pragma code_seg(Code)
void __far(test, 20) pval() { void __bank(ram, 20) pval() {
printval(); printval();
} }
void __far(test2, 21) ival() { void __bank(ram, 21) ival() {
incval(); incval();
} }
void __far(test, 20) printval() { void __bank(ram, 20) printval() {
SCREEN[0] = val; SCREEN[0] = val;
} }
void __far(test2, 21) incval() { void __bank(ram, 21) incval() {
val++; val++;
} }
#pragma near #pragma nobank
void printother() { void printother() {
for(char i:0..5) { 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 }; struct Point p = { i, i/2 };
return p; return p;
} }
void __far(2) print(struct Point p) { void __bank(ram,2) print(struct Point p) {
SCREEN[idx++] = p.x; SCREEN[idx++] = p.x;
SCREEN[idx++] = p.y; SCREEN[idx++] = p.y;
} }

View File

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