diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java
index a3ca5bddc..30afba97c 100644
--- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java
+++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java
@@ -13,6 +13,7 @@ import dk.camelot64.kickc.model.operators.OperatorBinary;
import dk.camelot64.kickc.model.operators.OperatorUnary;
import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.*;
+import dk.camelot64.kickc.model.symbols.Bank;
import dk.camelot64.kickc.model.symbols.Label;
import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Symbol;
@@ -51,17 +52,15 @@ final public class AsmFragmentInstanceSpecBuilder {
* @param program The program
* @return the fragment instance spec factory
*/
- public static AsmFragmentInstanceSpec callBanked(Procedure.CallingDistance callingDistance, String callingConvention, String procedureName, Program program) {
+ public static AsmFragmentInstanceSpec callBanked(String callingConvention, Procedure.CallingProximity proximity, Bank toBank, String procedureName, Program program) {
AsmFragmentBindings bindings = new AsmFragmentBindings(program);
- AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(callingDistance, callingConvention);
+ AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(callingConvention, proximity, toBank);
ScopeRef codeScope = program.getScope().getRef();
- bindings.bind("c1", new ConstantInteger(callingDistance.getBankNumber()));
+ bindings.bind("c1", new ConstantInteger(toBank.bankNumber()));
bindings.bind("la1", new LabelRef(procedureName));
return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope);
}
-
-
/**
* Create a fragment instance spec factory for an interrupt routine entry
*
diff --git a/src/main/java/dk/camelot64/kickc/fragment/signature/AsmFragmentSignature.java b/src/main/java/dk/camelot64/kickc/fragment/signature/AsmFragmentSignature.java
index 509680120..4b37b89a5 100644
--- a/src/main/java/dk/camelot64/kickc/fragment/signature/AsmFragmentSignature.java
+++ b/src/main/java/dk/camelot64/kickc/fragment/signature/AsmFragmentSignature.java
@@ -2,6 +2,7 @@ package dk.camelot64.kickc.fragment.signature;
import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureLexer;
import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureParser;
+import dk.camelot64.kickc.model.symbols.Bank;
import dk.camelot64.kickc.model.symbols.Procedure;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
@@ -55,7 +56,7 @@ public interface AsmFragmentSignature {
}
/**
- * ASM fragment signature for a conditional jump if(A) goto B
.
+ * ASM fragment signature for a call
*/
class Call implements AsmFragmentSignature {
@@ -72,21 +73,25 @@ public interface AsmFragmentSignature {
}
/**
- * ASM fragment signature for a banked jsr if(A) goto B
.
+ * ASM fragment signature for a banked call
*/
class CallBanked implements AsmFragmentSignature {
- final private Procedure.CallingDistance callingDistance;
final private String callingConvention;
- public CallBanked(Procedure.CallingDistance callingDistance, String callingConvention) {
- this.callingDistance = callingDistance;
+ final private Procedure.CallingProximity proximity;
+
+ final private Bank toBank;
+
+ public CallBanked(String callingConvention, Procedure.CallingProximity proximity, Bank toBank) {
this.callingConvention = callingConvention;
+ this.proximity = proximity;
+ this.toBank = toBank;
}
@Override
public String getName() {
- return "call_" + callingConvention.toLowerCase() + "_" + callingDistance.getFragmentName().toLowerCase();
+ return "call_" + callingConvention.toLowerCase() + "_" + proximity.toString().toLowerCase() + (proximity.equals(Procedure.CallingProximity.NEAR)?"":("_"+toBank.bankArea()));
}
}
diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
index 40da8c1d2..4252fb9d6 100644
--- a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
+++ b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
@@ -65,88 +65,33 @@ public class Procedure extends Scope {
this.bank = bank;
}
+ /** The different distances between banked code, which will determine the type of call needed. */
public enum CallingProximity {
- NEAR("near"),
- CLOSE("close"),
- FAR("far");
+ /** No bank change is needed. Caller and callee are both in the same bank or in the common bank. */
+ NEAR,
+ /** A direct bank change is needed. Caller is in the common bank or a different banking area. */
+ CLOSE,
+ /** A trampoline bank change is needed. Caller and callee are different banks of the same banking area. */
+ FAR;
- public String getProximity() {
- return proximity;
- }
-
- private final String proximity;
-
- CallingProximity(String proximity) {
- this.proximity = proximity;
- }
- }
-
- /** The method for expressing the call distance to implement banking
- *
- * The following variations exist related to banked calls:
- * - #1 - unbanked to unbanked and no banking areas
- * - #2 - unbanked to banked to any bank area
- * - #3 - banked to unbanked from any bank area
- * - #4 - banked to same bank in same bank area
- * - #5 - banked to different bank in same bank area
- * - #6 - banked to any bank between different bank areas
- *
- * This brings us to the call types:
- * - CallingDistance.NEAR - case #1, #3, #4
- * - CallingDistance.CLOSE - case #2, #6
- * - CallingDistance.FAR - case #5
- */
- public static class CallingDistance {
-
- private CallingProximity proximity;
- private String bankArea;
- private Long bank;
-
- public CallingProximity getProximity() {
- return proximity;
- }
-
- public String getBankArea() {
- return bankArea;
- }
-
- public Long getBankNumber() {
- return bank;
- }
-
-
- public CallingDistance(Procedure from, Procedure to) {
- if (((!from.isBanked() && !to.isBanked())) ||
- ((from.isBanked() && !to.isBanked())) ||
- ((from.isBanked() && to.isBanked()) &&
- (from.getBankNumber() == to.getBankNumber()) &&
- (from.getBankArea().contentEquals(to.getBankArea()))
- )
- ) {
- // near call - case #1, #3, #4
- this.proximity = CallingProximity.NEAR;
- this.bankArea = "";
- this.bank = 0L;
+ public static CallingProximity forCall(Bank from, Bank to) {
+ if(to==null) {
+ // NEAR: call to the common bank
+ return NEAR;
+ } else if(to.equals(from)) {
+ // NEAR: call to the same bank in the same banking area
+ return NEAR;
+ } else if(from==null) {
+ // CLOSE: call from common bank to any bank
+ return CLOSE;
+ } else if(!from.bankArea().equals(to.bankArea())) {
+ // CLOSE: from one banking area to another
+ return CLOSE;
} else {
- if ((!from.isBanked() && to.isBanked()) ||
- ((from.isBanked() && to.isBanked()) && (!from.getBankArea().contentEquals(to.getBankArea())))
- ) {
- // close call - case #2, #6
- this.proximity = CallingProximity.CLOSE;
- this.bankArea = to.getBankArea();
- this.bank = to.getBankNumber();
- } else {
- // far call - case #5
- this.proximity = CallingProximity.FAR;
- this.bankArea = to.getBankArea();
- this.bank = to.getBankNumber();
- }
+ // FAR: banked to different bank in same bank area
+ return FAR;
}
}
-
- public String getFragmentName() {
- return this.proximity.getProximity() + (this.bankArea.isEmpty() ? "" : "_" + this.bankArea);
- }
}
/** The method for passing parameters and return value to the procedure. */
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
index 1aaaa8c49..2211d4fd1 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
@@ -891,7 +891,6 @@ public class Pass4CodeGeneration {
}
} else if (Procedure.CallingConvention.PHI_CALL.equals(toProcedure.getCallingConvention())) {
// Generate PHI transition
- boolean generatedPhis = false;
if (genCallPhiEntry) {
ControlFlowBlock callSuccessor = getGraph().getCallSuccessor(block);
if (callSuccessor != null && callSuccessor.hasPhiBlock()) {
@@ -900,18 +899,17 @@ public class Pass4CodeGeneration {
throw new InternalError("Error! JSR transition already generated. Must modify PhiTransitions code to ensure this does not happen.");
}
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
- generatedPhis = true;
}
}
- final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure);
- if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) {
+ final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else {
- AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(callingDistance,"phi", call.getProcedure().getFullName(), program), program);
+ AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked("phi", callingProximity, toProcedure.getBank(), call.getProcedure().getFullName(), program), program);
}
} else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
- final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure);
- if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) {
+ final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
@@ -924,8 +922,8 @@ public class Pass4CodeGeneration {
ProgramScope scope = getScope();
Procedure toProcedure = scope.getProcedure(procedureRef);
Procedure fromProcedure = block.getProcedure(this.program);
- final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure);
- if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) {
+ final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
} else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));