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

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.OperatorUnary;
import dk.camelot64.kickc.model.operators.Operators; import dk.camelot64.kickc.model.operators.Operators;
import dk.camelot64.kickc.model.statements.*; 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.Label;
import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Procedure;
import dk.camelot64.kickc.model.symbols.Symbol; import dk.camelot64.kickc.model.symbols.Symbol;
@ -51,17 +52,15 @@ final public class AsmFragmentInstanceSpecBuilder {
* @param program The program * @param program The program
* @return the fragment instance spec factory * @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); 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(); 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)); 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 an interrupt routine entry * 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.AsmFragmentSignatureLexer;
import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureParser; import dk.camelot64.kickc.asm.fragment.signature.AsmFragmentSignatureParser;
import dk.camelot64.kickc.model.symbols.Bank;
import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Procedure;
import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams; 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 { 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 { class CallBanked implements AsmFragmentSignature {
final private Procedure.CallingDistance callingDistance;
final private String callingConvention; final private String callingConvention;
public CallBanked(Procedure.CallingDistance callingDistance, String callingConvention) { final private Procedure.CallingProximity proximity;
this.callingDistance = callingDistance;
final private Bank toBank;
public CallBanked(String callingConvention, Procedure.CallingProximity proximity, Bank toBank) {
this.callingConvention = callingConvention; this.callingConvention = callingConvention;
this.proximity = proximity;
this.toBank = toBank;
} }
@Override @Override
public String getName() { 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; this.bank = bank;
} }
/** The different distances between banked code, which will determine the type of call needed. */
public enum CallingProximity { public enum CallingProximity {
NEAR("near"), /** No bank change is needed. Caller and callee are both in the same bank or in the common bank. */
CLOSE("close"), NEAR,
FAR("far"); /** 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() { public static CallingProximity forCall(Bank from, Bank to) {
return proximity; if(to==null) {
} // NEAR: call to the common bank
return NEAR;
private final String proximity; } else if(to.equals(from)) {
// NEAR: call to the same bank in the same banking area
CallingProximity(String proximity) { return NEAR;
this.proximity = proximity; } else if(from==null) {
} // CLOSE: call from common bank to any bank
} return CLOSE;
} else if(!from.bankArea().equals(to.bankArea())) {
/** The method for expressing the call distance to implement banking // CLOSE: from one banking area to another
* return CLOSE;
* 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;
} else { } else {
if ((!from.isBanked() && to.isBanked()) || // FAR: banked to different bank in same bank area
((from.isBanked() && to.isBanked()) && (!from.getBankArea().contentEquals(to.getBankArea()))) return FAR;
) {
// 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();
}
} }
} }
public String getFragmentName() {
return this.proximity.getProximity() + (this.bankArea.isEmpty() ? "" : "_" + this.bankArea);
}
} }
/** The method for passing parameters and return value to the procedure. */ /** 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())) { } else if (Procedure.CallingConvention.PHI_CALL.equals(toProcedure.getCallingConvention())) {
// Generate PHI transition // Generate PHI transition
boolean generatedPhis = false;
if (genCallPhiEntry) { if (genCallPhiEntry) {
ControlFlowBlock callSuccessor = getGraph().getCallSuccessor(block); ControlFlowBlock callSuccessor = getGraph().getCallSuccessor(block);
if (callSuccessor != null && callSuccessor.hasPhiBlock()) { 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."); throw new InternalError("Error! JSR transition already generated. Must modify PhiTransitions code to ensure this does not happen.");
} }
genBlockPhiTransition(asm, block, callSuccessor, block.getScope()); genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
generatedPhis = true;
} }
} }
final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure); final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) { if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else { } 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())) { } else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure); final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) { if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
} else { } else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
@ -924,8 +922,8 @@ public class Pass4CodeGeneration {
ProgramScope scope = getScope(); ProgramScope scope = getScope();
Procedure toProcedure = scope.getProcedure(procedureRef); Procedure toProcedure = scope.getProcedure(procedureRef);
Procedure fromProcedure = block.getProcedure(this.program); Procedure fromProcedure = block.getProcedure(this.program);
final Procedure.CallingDistance callingDistance = new Procedure.CallingDistance(fromProcedure, toProcedure); final Procedure.CallingProximity callingProximity = Procedure.CallingProximity.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Procedure.CallingProximity.NEAR.equals(callingDistance.getProximity())) { if(Procedure.CallingProximity.NEAR.equals(callingProximity)) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
} else { } else {
throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));