mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 18:29:54 +00:00
Refactored proximity.
This commit is contained in:
parent
2b1bc3c11d
commit
9f3ca81e6a
@ -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
|
||||
*
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,90 +65,35 @@ 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. */
|
||||
public enum CallingConvention {
|
||||
/** Parameters and return value handled through PHI-transitions. */
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user