Refactored proximity.

This commit is contained in:
jespergravgaard 2023-04-23 20:37:37 +02:00
parent 2b1bc3c11d
commit 9f3ca81e6a
4 changed files with 44 additions and 97 deletions

View File

@ -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
*

View File

@ -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 <code>if(A) goto B</code>.
* ASM fragment signature for a call
*/
class Call implements AsmFragmentSignature {
@ -72,21 +73,25 @@ public interface AsmFragmentSignature {
}
/**
* ASM fragment signature for a banked jsr <code>if(A) goto B</code>.
* 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()));
}
}

View File

@ -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. */

View File

@ -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));