diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 3fc36c85c..812cffe2a 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -278,7 +278,7 @@ public class Compiler { getLog().append(program.getGraph().toString(program)); } new Pass1ProcedureInline(program).execute(); - new Pass1ProcedureFar(program).execute(); // Implements far calls to procedures defined in a bank. + new Pass1ProcedureFar(program).execute(); // Implements far calls to procedures defined in a bank. See https://gitlab.com/Flight_Control/kickc/-/commits/far-call-isolated new PassNStatementIndices(program).step(); program.clearCallGraph(); new Pass1AssertNoRecursion(program).execute(); diff --git a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java index 66aace3b8..41e3a76e8 100644 --- a/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java +++ b/src/main/java/dk/camelot64/kickc/fragment/AsmFragmentInstanceSpecBuilder.java @@ -45,33 +45,35 @@ final public class AsmFragmentInstanceSpecBuilder { /** * Create a fragment instance spec factory for a far call entry * - * @param call The statement call - * @param program The program + * @param bankFar 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 farCallEntry(StatementCall call, Program program) { + public static AsmFragmentInstanceSpec farCallEntry(Long bankFar, String procedureName, Program program) { AsmFragmentBindings bindings = new AsmFragmentBindings(program); - AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(call.getBankFar(), program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Entry); + AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(bankFar, program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Entry); ScopeRef codeScope = program.getScope().getRef(); // ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope(); - bindings.bind("c1", new ConstantInteger(call.getBankFar())); - bindings.bind("la1", new LabelRef(call.getProcedure().getFullName())); + bindings.bind("c1", new ConstantInteger(bankFar)); + bindings.bind("la1", new LabelRef(procedureName)); return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); } /** * Create a fragment instance spec factory for a far call exit * - * @param call The statement call + * @param bankFar 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 farCallExit(StatementCall call, Program program) { + public static AsmFragmentInstanceSpec farCallExit(Long bankFar, String procedureName, Program program) { AsmFragmentBindings bindings = new AsmFragmentBindings(program); - AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(call.getBankFar(), program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Exit); - ScopeRef codeScope = program.getStatementInfos().getBlock(call).getScope(); - bindings.bind("la1", new LabelRef(codeScope.getFullName())); - bindings.bind("la2", new ConstantInteger(call.getBankFar())); + AsmFragmentSignature signature = new AsmFragmentSignature.CallFar(bankFar, program.getTargetPlatform().getName(), AsmFragmentSignature.CallFar.EntryExit.Exit); + ScopeRef codeScope = program.getScope().getRef(); + bindings.bind("c1", new ConstantInteger(bankFar)); + bindings.bind("la1", new LabelRef(procedureName)); return new AsmFragmentInstanceSpec(program, signature, bindings, codeScope); } diff --git a/src/main/java/dk/camelot64/kickc/model/statements/StatementCallExecute.java b/src/main/java/dk/camelot64/kickc/model/statements/StatementCallExecute.java index f1f54fe05..620491ecb 100644 --- a/src/main/java/dk/camelot64/kickc/model/statements/StatementCallExecute.java +++ b/src/main/java/dk/camelot64/kickc/model/statements/StatementCallExecute.java @@ -28,11 +28,15 @@ public class StatementCallExecute extends StatementBase implements StatementCall /** The calling convention to use. */ private Procedure.CallingConvention callingConvention; + /** This contains the far call parameters */ + private Long bankFar; + public StatementCallExecute(SymbolTypeProcedure procedureType, RValue procedure, Procedure.CallingConvention callingConvention, StatementSource source, List comments) { super(source, comments); this.procedureType = procedureType; this.procedure = procedure; this.callingConvention = callingConvention; + this.bankFar = bankFar; } public SymbolTypeProcedure getProcedureType() { diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 1ba4a73e4..ae20b378b 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -867,8 +867,8 @@ public class Pass4CodeGeneration { } if(procedure.isDeclaredFar()) { // Generate ASM for a call (in a bank or other) - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call, program), program); - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call, program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call.getBankFar(), call.getProcedure().getFullName(), program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call.getBankFar(), call.getProcedure().getFullName(), program), program); // asm.addInstruction("jsr far", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); } else { asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); @@ -876,17 +876,23 @@ public class Pass4CodeGeneration { } else if (Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) { if(procedure.isDeclaredFar()) { // Generate ASM for a far call (in a bank or other) - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call, program), program); - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call, program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(call.getBankFar(), call.getProcedure().getFullName(), program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(call.getBankFar(), call.getProcedure().getFullName(), program), program); } else { asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false); } } } else if (statement instanceof StatementCallExecute) { StatementCallExecute call = (StatementCallExecute) statement; + Procedure procedure = getScope().getProcedure(call.getProcedure()); RValue procedureRVal = call.getProcedureRVal(); // Generate ASM for a call - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); + if(procedure.isDeclaredFar()) { + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallEntry(procedure.getBankFar(), call.getProcedure().getFullName(), program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.farCallExit(procedure.getBankFar(), call.getProcedure().getFullName(), program), program); + } else { + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); + } if (!(procedureRVal instanceof ProcedureRef)) { asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); } diff --git a/src/test/kc/$workspacedir/target/procedure-callingconvention-phi-far-0.vs b/src/test/kc/$workspacedir/target/procedure-callingconvention-phi-far-0.vs new file mode 100644 index 000000000..243aa53b5 --- /dev/null +++ b/src/test/kc/$workspacedir/target/procedure-callingconvention-phi-far-0.vs @@ -0,0 +1,5 @@ +al C:400 .SCREEN +al C:80b .upstartEnd +al C:80d .main +al C:819 .plus +al C:37 .return diff --git a/src/test/kc/procedure-callingconvention-phi-far-1.c b/src/test/kc/procedure-callingconvention-phi-far-1.c new file mode 100644 index 000000000..6eda3a13d --- /dev/null +++ b/src/test/kc/procedure-callingconvention-phi-far-1.c @@ -0,0 +1,13 @@ +// Test a procedure with calling convention stack + +char* const SCREEN = (char*)0x0400; + +void main(void) { + SCREEN[0] = plus('0', 7); +} + +#pragma calling(__stackcall) + +char __far(1) plus(char a, char b) { + return a+b; +} \ No newline at end of file