diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java index 8c493b3d6..91669533e 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java @@ -14,6 +14,7 @@ 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.Label; +import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.symbols.Symbol; import dk.camelot64.kickc.model.types.SymbolType; import dk.camelot64.kickc.model.types.SymbolTypeInference; @@ -44,19 +45,17 @@ final public class AsmFragmentInstanceSpecBuilder { /** * Create a fragment instance spec factory for a subroutine call * - * @param distance The string expressing the distance of the call: "near", "close", "far". + * @param callingDistance The class expressing the distance of the call: "near", "close", "far" plus bankArea and bank information calculated from the from and to procedure. * @param callingConvention The string expressing the calling convention supported by the fragment. - * @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 program The program * @return the fragment instance spec factory */ - public static AsmFragmentInstanceSpec callBanked(String distance, String callingConvention, String bankArea, Long bank, String procedureName, Program program) { + public static AsmFragmentInstanceSpec callBanked(Procedure.CallingDistance callingDistance, String callingConvention, String procedureName, Program program) { AsmFragmentBindings bindings = new AsmFragmentBindings(program); - AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(distance, callingConvention, bankArea, bank); + AsmFragmentSignature signature = new AsmFragmentSignature.CallBanked(callingDistance, callingConvention); ScopeRef codeScope = program.getScope().getRef(); - bindings.bind("c1", new ConstantInteger(bank)); + bindings.bind("c1", new ConstantInteger(callingDistance.getBank())); bindings.bind("la1", new LabelRef(procedureName)); return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); } 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 d13f75cb9..509680120 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.Procedure; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; @@ -75,21 +76,17 @@ public interface AsmFragmentSignature { */ class CallBanked implements AsmFragmentSignature { - final private String distance; + final private Procedure.CallingDistance callingDistance; final private String callingConvention; - final private String bankArea; - final private Long bank; - public CallBanked(String distance, String callingConvention, String bankArea, Long bank) { - this.distance = distance; + public CallBanked(Procedure.CallingDistance callingDistance, String callingConvention) { + this.callingDistance = callingDistance; this.callingConvention = callingConvention; - this.bankArea = bankArea; - this.bank = bank; } @Override public String getName() { - return "call_" + callingConvention.toLowerCase() + "_" + distance.toLowerCase() + ((bankArea.isEmpty()) ? "" : ("_" + bankArea.toLowerCase())); + return "call_" + callingConvention.toLowerCase() + "_" + callingDistance.getFragmentName().toLowerCase(); } } 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 40512af6b..d59dd6419 100644 --- a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java +++ b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java @@ -64,6 +64,89 @@ public class Procedure extends Scope { this.bankLocation = bankLocation; } + public enum CallingProximity { + NEAR("near"), + CLOSE("close"), + FAR("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 getBank() { + return bank; + } + + + public CallingDistance(Procedure from, Procedure to) { + if (((!from.isDeclaredBanked() && !to.isDeclaredBanked())) || + ((from.isDeclaredBanked() && !to.isDeclaredBanked())) || + ((from.isDeclaredBanked() && to.isDeclaredBanked()) && + (from.getBank() == to.getBank()) && + (from.getBankArea().contentEquals(to.getBankArea())) + ) + ) { + // near call - case #1, #3, #4 + this.proximity = CallingProximity.NEAR; + this.bankArea = ""; + this.bank = 0L; + } else { + if ((!from.isDeclaredBanked() && to.isDeclaredBanked()) || + ((from.isDeclaredBanked() && to.isDeclaredBanked()) && (!from.getBankArea().contentEquals(to.getBankArea()))) + ) { + // close call - case #2, #6 + this.proximity = CallingProximity.CLOSE; + this.bankArea = to.getBankArea(); + this.bank = to.getBank(); + } else { + // far call - case #5 + this.proximity = CallingProximity.FAR; + this.bankArea = to.getBankArea(); + this.bank = to.getBank(); + } + } + } + + 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 { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index ccea75395..dfcba31e5 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -906,56 +906,13 @@ public class Pass4CodeGeneration { genBlockPhiTransition(asm, block, callSuccessor, block.getScope()); } } - /* - 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: - near - case #1, #3, #4 - close - case #2, #6 - far - case #5 - */ - String fromBankArea = fromProcedure.getBankArea(); - String toBankArea = toProcedure.getBankArea(); - Boolean fromIsBanked = fromProcedure.isDeclaredBanked(); - Boolean toIsBanked = toProcedure.isDeclaredBanked(); - Long fromBank = fromProcedure.getBank(); - Long toBank = toProcedure.getBank(); - if( ((!fromIsBanked && !toIsBanked)) || - ((fromIsBanked && !toIsBanked)) || - ((fromIsBanked && toIsBanked) && (fromBank == toBank) && (fromBankArea.contentEquals(toBankArea))) - ) { - // near call - case #1, #3, #4 - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "near","phi", "", 0L, call.getProcedure().getFullName(), program), program); -// // Otherwise, Generate AM for a normal near call. -// asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); - } else { - if( (!fromIsBanked && toIsBanked) || - ((fromIsBanked && toIsBanked) && (!fromBankArea.contentEquals(toBankArea))) - ) { - // close call - case #2, #6 - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "close","phi", toBankArea, toBank, call.getProcedure().getFullName(), program), program); - } else { - // far call - case #5 - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "far","phi", toBankArea, toBank, call.getProcedure().getFullName(), program), program); - } - } + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(new Procedure.CallingDistance(fromProcedure, toProcedure),"phi", call.getProcedure().getFullName(), program), program); } else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) { - // Same as PHI - String fromBankArea = fromProcedure.getBankArea(); - String toBankArea = toProcedure.getBankArea(); - Boolean fromIsBanked = fromProcedure.isDeclaredBanked(); Boolean toIsBanked = toProcedure.isDeclaredBanked(); Long fromBank = fromProcedure.getBank(); Long toBank = toProcedure.getBank(); if(toIsBanked && fromBank != toBank) { throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked("far", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program); } else { asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); } @@ -967,20 +924,12 @@ public class Pass4CodeGeneration { ProgramScope scope = getScope(); Procedure toProcedure = scope.getProcedure(procedureRef); Procedure fromProcedure = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality. - String fromBankArea = fromProcedure.getBankArea(); - String toBankArea = toProcedure.getBankArea(); - Boolean fromIsBanked = fromProcedure.isDeclaredBanked(); - Boolean toIsBanked = toProcedure.isDeclaredBanked(); - Long fromBank = fromProcedure.getBank(); - Long toBank = toProcedure.getBank(); RValue procedureRVal = call.getProcedureRVal(); // Same as PHI if (toProcedure.isDeclaredBanked() && fromProcedure.getBank() != toProcedure.getBank()) { throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program)); -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "far", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program); } else { AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked( "near", "stack", toProcedure.getBankArea(), toProcedure.getBank(), call.getProcedure().getFullName(), program), program); } if (!(procedureRVal instanceof ProcedureRef)) { asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);