From a52b5dc4a949ba1ab22aa38bcd3bf08960879948 Mon Sep 17 00:00:00 2001 From: Sven Van de Velde Date: Mon, 10 Apr 2023 07:22:06 +0200 Subject: [PATCH] Banking progress (cherry picked from commit d0abf45529c34e14ed3ce43b9be3a140f78bc4a9) --- .../kickc/passes/Pass4CodeGeneration.java | 45 +++-- .../kc/examples/cx16/banking/cx16-banking-0.c | 55 ++++++ .../kc/examples/cx16/banking/cx16-banking-0.h | 20 +++ .../examples/cx16/banking/cx16-banking-0.ld | 12 ++ .../kc/examples/cx16/banking/cx16-banking-1.c | 168 ++++++++++++++++++ .../banking/cx16-banking-recursive-near.c | 38 ++++ 6 files changed, 321 insertions(+), 17 deletions(-) create mode 100644 src/test/kc/examples/cx16/banking/cx16-banking-0.c create mode 100644 src/test/kc/examples/cx16/banking/cx16-banking-0.h create mode 100644 src/test/kc/examples/cx16/banking/cx16-banking-0.ld create mode 100644 src/test/kc/examples/cx16/banking/cx16-banking-1.c create mode 100644 src/test/kc/examples/cx16/banking/cx16-banking-recursive-near.c diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java index 07fa70e5f..4e435ea98 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java @@ -925,28 +925,39 @@ public class Pass4CodeGeneration { } } else if (statement instanceof StatementCallExecute) { // TODO: This part seems never to be executed! Old code? - StatementCallExecute call = (StatementCallExecute) statement; - RValue procedureRVal = call.getProcedureRVal(); - // Generate ASM for a call - AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); - if (!(procedureRVal instanceof ProcedureRef)) { - asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); - } // StatementCallExecute call = (StatementCallExecute) statement; -// Procedure procedure = getScope().getProcedure(call.getProcedure()); -// Procedure procedureFrom = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality. // RValue procedureRVal = call.getProcedureRVal(); -// // Same as PHI -// if(procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) { -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program); -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program); -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program); -// } else { -// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); -// } +// // Generate ASM for a call +// AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); // if (!(procedureRVal instanceof ProcedureRef)) { // asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); // } + StatementCallExecute call = (StatementCallExecute) statement; + ProcedureRef procedureRef = call.getProcedure(); + if(procedureRef != null) { + ProgramScope scope = getScope(); + Procedure procedure = scope.getProcedure(procedureRef); + Procedure procedureFrom = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality. + RValue procedureRVal = call.getProcedureRVal(); + // Same as PHI + if (procedure.isDeclaredBanked() && procedureFrom.getBank() != procedure.getBank()) { + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallPrepare(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallExecute(procedure.getBankArea(), procedure.getBank(), call.getProcedure().getFullName(), program), program); + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.bankCallFinalize(procedure.getBankArea(), procedure.getBank(), 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); + } + } else { + RValue procedureRVal = call.getProcedureRVal(); + // Generate ASM for a call + AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program); + if (!(procedureRVal instanceof ProcedureRef)) { + asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL); + } + } } else if (statement instanceof StatementExprSideEffect) { AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.exprSideEffect((StatementExprSideEffect) statement, program), program); } else if (statement instanceof StatementReturn) { diff --git a/src/test/kc/examples/cx16/banking/cx16-banking-0.c b/src/test/kc/examples/cx16/banking/cx16-banking-0.c new file mode 100644 index 000000000..bab4d90a5 --- /dev/null +++ b/src/test/kc/examples/cx16/banking/cx16-banking-0.c @@ -0,0 +1,55 @@ +/** + * @file cx16-banking-1.c + * @author your name (you@domain.com) + * @brief This program demonstrates a simple example of a banked call. + * @version 0.1 + * @date 2023-04-05 + * + * @copyright Copyright (c) 2023 + * + */ + +// The linker specification of the different segments. +#pragma link("cx16-banking-1.ld") +#pragma var_model(mem) + +#include +#include +#include +#include + +#include "cx16-banking-0.h" + + +// The target computer platform is the Commander X16, +// which implements banking in ram between 0xA0000 and 0xBFFF, +// and in ram between 0xC000 and 0xFFFF. +#pragma target(cx16) + +char* const SCREEN = (char*)0x0400; + +#pragma code_seg(Bank1) // The sequent functions will be addressed specified by segment bank1 in the linker. +#pragma bank(ram, 1) // The sequent functions will be banked using call method ram in bank number 1. + +char __stackcall plus(char a, char b) { + return a+b; +} + +#pragma code_seg(Code) // The sequent functions will be addressed in the default main memory location (segment Code). +#pragma nobank(dummy) // The sequent functions will consider no banking calculations anymore. + +void load_bank(char bank, char *file) { + bank_set_bram(bank); + cbm_k_setnam(file); + cbm_k_setlfs(1,8,2); + cbm_k_load((char*)0xA000, 0); + cbm_k_close(1); +} + +void main(void) { + + load_bank(1, "BANK1.BIN"); + + SCREEN[0] = plus('0', 7); +} + diff --git a/src/test/kc/examples/cx16/banking/cx16-banking-0.h b/src/test/kc/examples/cx16/banking/cx16-banking-0.h new file mode 100644 index 000000000..a52f107cb --- /dev/null +++ b/src/test/kc/examples/cx16/banking/cx16-banking-0.h @@ -0,0 +1,20 @@ + + +// Function declarations +// char add_a(char a); +// char add_b(char a); +// char add_c(char a); +// char add_d(char a); +// char add_e(char a); +// char add_f(char a); + +// char add_m(char a); + +// char mul_a(char m); +// char mul_b(char m); +// char mul_c(char m); +// char mul_d(char m); +// char mul_e(char m); +// char mul_f(char m); + +// char mul_m(char m); diff --git a/src/test/kc/examples/cx16/banking/cx16-banking-0.ld b/src/test/kc/examples/cx16/banking/cx16-banking-0.ld new file mode 100644 index 000000000..c0dedea43 --- /dev/null +++ b/src/test/kc/examples/cx16/banking/cx16-banking-0.ld @@ -0,0 +1,12 @@ +.file [name="%O", type="prg", segments="Program"] +.file [name="BANK1.BIN", type="bin", segments="Bank1"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=%P] +.segmentdef Data [startAfter="Code"] +.segmentdef Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100] +.segment Basic +:BasicUpstart(%E) +.segment Code +.segment Data + diff --git a/src/test/kc/examples/cx16/banking/cx16-banking-1.c b/src/test/kc/examples/cx16/banking/cx16-banking-1.c new file mode 100644 index 000000000..b95afbcef --- /dev/null +++ b/src/test/kc/examples/cx16/banking/cx16-banking-1.c @@ -0,0 +1,168 @@ +/** + * @file cx16-banking-1.c + * @author your name (you@domain.com) + * @brief This program demonstrates a simple example of a banked call. + * @version 0.1 + * @date 2023-04-05 + * + * @copyright Copyright (c) 2023 + * + */ + +// The linker specification of the different segments. +#pragma link("cx16-banking-1.ld") +#pragma var_model(mem) + +#include +#include +#include +#include + +#include "cx16-banking-1.h" + + +// The target computer platform is the Commander X16, +// which implements banking in ram between 0xA0000 and 0xBFFF, +// and in ram between 0xC000 and 0xFFFF. +#pragma target(cx16) + + +#pragma code_seg(Bank1) // The sequent functions will be addressed specified by segment bank1 in the linker. +#pragma bank(ram, 1) // The sequent functions will be banked using call method ram in bank number 1. + + +// Functional code + +char add_a(char a) { + printf("add_a(%02x:%04p), ",bank_get_bram(), (void*)&add_a); + return a+1; +} + +char add_c(char a) { + printf("add_c(%02x:%04p), ",bank_get_bram(),(void*)&add_c); + return add_a(a)+1; // Non banked call in ram bank 1. +} + +char add_d(char a) { + printf("add_d(%02x:%04p), ",bank_get_bram(),(void*)&add_d); + return mul_a(a)+1; // Banked call fram ram bank 1 to ram bank 2. +} + +char add_e(char a) { + printf("add_e(%02x:%04p), ",bank_get_bram(),(void*)&add_e); + return mul_b(a)+1; // Banked call fram ram bank 1 to ram bank 2. +} + +char add_f(char a) { + printf("add_f(%02x:%04p), ",bank_get_bram(),(void*)&add_f); + return add_m(a)+1; // Non banked call fram ram bank 1 to main memory. +} + + +#pragma code_seg(Bank2) // The sequent functions will be addressed specified by segment bank2 in the linker. +#pragma bank(ram, 2) // The sequent functions will be banked using call method ram in bank number 2. + +char mul_a(char m) { + printf("mul_a(%02x:%04p), ",bank_get_bram(),(void*)&mul_a); + return m * 2; +} + +char mul_c(char m) { + printf("mul_c(%02x:%04p), ",bank_get_bram(),(void*)&mul_c); + return add_a(m)*2; // Banked call fram ram bank 2 to ram bank 1. +} + +char mul_d(char m) { + printf("mul_d(%02x:%04p), ",bank_get_bram(),(void*)&mul_d); + return mul_a(m)*2; // Non banked call in ram bank 2. +} + +char mul_e(char a) { + printf("mul_e(%02x:%04p), ",bank_get_bram(),(void*)&mul_e); + return mul_b(a)*2; // Non Banked call in ram bank 2. +} + +char mul_f(char m) { + printf("mul_f(%02x:%04p), ",bank_get_bram(),(void*)&mul_f); + return add_m(m)*2; // Non banked call fram ram bank 2 to main memory. +} + + +#pragma code_seg(Code) // The sequent functions will be addressed in the default main memory location (segment Code). +#pragma nobank(dummy) // The sequent functions will consider no banking calculations anymore. + +// The __bank directive declares this function to be banked using call method ram in bank number 1 of banked ram. +char __bank(ram, 1) add_b(char a) { + printf("add_b(%02x:%04p), ",bank_get_bram(),(void*)&add_b); + return a+1; +} + +// The __bank directive declares this function to be banked using call method ram in bank number 2 of banked ram. +char __bank(ram, 2) mul_b(char m) { + printf("mul_b(%02x:%04p), ",bank_get_bram(),(void*)&mul_b); + return m*2; +} + +// Allocated in main memory. +char add_m(char a) { + printf("add_m(%02x:%04p), ",bank_get_bram(),(void*)&add_m); + return add_e(a)+1; // Banked call to ram in bank 1 fram main memory. +} + +// Allocated in main memory. +char mul_m(char m) { + printf("mul_m(%02x:%04p), ",bank_get_bram(),(void*)&mul_m); + return mul_e(m)*2; // Banked call to ram in bank 2 fram main memory. +} + + +// Practically this means that the main() function is placed in main memory ... + +void load_bank(char bank, char *file) { + bank_set_bram(bank); + cbm_k_setnam(file); + cbm_k_setlfs(1,8,2); + cbm_k_load((char*)0xA000, 0); + cbm_k_close(1); +} + +void main(void) { + + clrscr(); + cx16_k_screen_set_charset(1,0); + + load_bank(1, "BANK1.BIN"); + load_bank(2, "BANK2.BIN"); + + bank_set_bram(0); + + asm{.byte $db} + __export char result = add_a(1); + printf("result = %u\n", result); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_b(1)); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_c(1)); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_d(1)); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_e(1)); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_f(1)); // Banked call to ram in bank 1 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_a(1)); // Banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_b(1)); // Banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_c(1)); // Banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_d(1)); // Banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_e(1)); // banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_f(1)); // banked call to ram in bank 2 fram main memory. + // asm{.byte $db} + // printf("result = %u\n", add_m(1)); // Near call in main memory fram main memory. + // asm{.byte $db} + // printf("result = %u\n", mul_m(1)); // Near call in main memory fram main memory. + } diff --git a/src/test/kc/examples/cx16/banking/cx16-banking-recursive-near.c b/src/test/kc/examples/cx16/banking/cx16-banking-recursive-near.c new file mode 100644 index 000000000..e1987ae9d --- /dev/null +++ b/src/test/kc/examples/cx16/banking/cx16-banking-recursive-near.c @@ -0,0 +1,38 @@ +/** + * @file cx16-banking-1.c + * @author your name (you@domain.com) + * @brief This program demonstrates a simple example of a banked call. + * @version 0.1 + * @date 2023-04-05 + * + * @copyright Copyright (c) 2023 + * + */ + +// The linker specification of the different segments. +#pragma var_model(mem) + +#include +#include +#include +#include + +// The target computer platform is the Commander X16, +// which implements banking in ram between 0xA0000 and 0xBFFF, +// and in ram between 0xC000 and 0xFFFF. +#pragma target(cx16) + +char __stackcall plus(char a, char b) { + if (a > 0) { + return a + plus(a - b, b); + } else { + return 0; + } +} + +void main(void) { + + char result = plus(4, 1); + printf("result = %u\n", result); +} +