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

- Now compiling the eight queens example with conio asm library.

- Added proper return value handling for __varcall functions.
- Added many fixes concerning start functions.
- Optimized asm library examples.
- Added a return value asm library example.
This commit is contained in:
Sven Van de Velde 2023-11-29 14:15:52 +01:00
parent 4012887479
commit 07cb0ba6fa
19 changed files with 1829 additions and 32 deletions

View File

@ -641,6 +641,9 @@ public class Program {
this.asmImports = asmImports;
}
/**
* 820/20 - Add a new library in the asm import list.
*/
public AsmLibrary addAsmImportLibrary(String asmImportLibraryName) {
Path asmImportResource = Paths.get(asmImportLibraryName + ".asm").toAbsolutePath();
AsmLibrary asmLibrary = new AsmLibrary(asmImportLibraryName, asmImportResource);
@ -649,6 +652,9 @@ public class Program {
return asmLibrary;
}
/**
* 820/20 - Add the procedure to a library.
*/
public void addAsmImportProcedures(AsmLibrary asmImportLibrary, Procedure.CallingConvention callingConvention, List<String> procedures) {
for(String procedureName : procedures) {
@ -656,7 +662,24 @@ public class Program {
}
}
public AsmLibrary isProcedureInAsmImport(String procedureName) {
/**
* 820/20 - Check if the procedure is in the asm import list.
*/
public boolean isProcedureAsmImport(String procedureName) {
Map<String, AsmLibrary> asmImports = this.getAsmImports();
for (String asmImportKey : asmImports.keySet()) {
AsmLibrary library = asmImports.get(asmImportKey);
if (library.hasProcedure(procedureName)) {
return true;
}
}
return false;
}
/**
* 820/20 - Get the asm import library of the procedure.
*/
public AsmLibrary getProcedureAsmImportLibrary(String procedureName) {
Map<String, AsmLibrary> asmImports = this.getAsmImports();
for (String asmImportKey : asmImports.keySet()) {
AsmLibrary library = asmImports.get(asmImportKey);
@ -664,7 +687,7 @@ public class Program {
return library;
}
}
return null;
return null;
}
public void setProcedureAsAsmImport(Procedure procedure, AsmLibrary asmImport) {

View File

@ -221,6 +221,11 @@ public class Procedure extends Scope {
return procedureType.getReturnType();
}
// 820/11 - Check if the variable is a return variable of the procedure.
public boolean isReturn(Variable returnvar) {
return findVariable(returnvar.getLocalName()) != null && returnvar.isVariable() && returnvar.getLocalName().contains("return");
}
public List<Variable> getParameters() {
ArrayList<Variable> parameters = new ArrayList<>();
for(String name : parameterNames) {

View File

@ -226,9 +226,13 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
throw new CompileError("main() has wrong number of parameters. It must have zero or 2 parameters.", mainProc.getDefinitionSource());
}
// For each imported library, call the __start procedure of the library.
// 820/17 - For each imported library, call the start procedure of the library.
for(AsmLibrary importedLibrary: program.getAsmImports().values()) {
startSequence.addStatement( new StatementCall(null, "__" + importedLibrary.getFullName() + "_start", new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
String procedureStartName = "__" + importedLibrary.getFullName() + "_start";
Procedure procedureStart = this.program.getScope().getProcedure(new ProcedureRef(procedureStartName));
if(procedureStart != null) {
startSequence.addStatement(new StatementCall(null, procedureStartName, new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
}
}
final Label startReturnLabel = startProcedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
@ -543,7 +547,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
String procedureName = varDecl.getVarName();
Procedure procDeclared = (Procedure)program.getScope().getSymbol(new SymbolRef(procedureName));
AsmLibrary asmImport = this.program.isProcedureInAsmImport(procedureName);
AsmLibrary asmImport = this.program.getProcedureAsmImportLibrary(procedureName);
// We skip the procedure definition if:
// - it is already defined in an asm library.
@ -620,7 +624,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
procedure = (Procedure) existingSymbol;
} else {
AsmLibrary asmImport = this.program.isProcedureInAsmImport(procedure.getFullName());
AsmLibrary asmImport = this.program.getProcedureAsmImportLibrary(procedure.getFullName());
if(asmImport != null)
this.program.setProcedureAsAsmImport(procedure, asmImport);
program.getScope().add(procedure);

View File

@ -61,6 +61,8 @@ public class Pass1CallVar extends Pass2SsaOptimization {
final LValue lValue = call.getlValue();
if(lValue!=null) {
Variable returnVar = procedure.getLocalVariable("return");
// 820/11 - Procedure return value of an asm library.
returnVar.setAsmLibrary(procedure.getAsmLibrary()); // This is key to bind the variable during assembler generation!
generateCallFinalize(lValue, returnVar, source, comments, stmtIt, statement);
}
stmtIt.remove();
@ -85,6 +87,7 @@ public class Pass1CallVar extends Pass2SsaOptimization {
for(int i = 0; i < parameterDefs.size(); i++) {
final RValue parameterVal = call.getParameters().get(i);
final Variable parameterDef = parameterDefs.get(i);
// 820/10 - Procedure parameters in an asm library.
parameterDef.setAsmLibrary(procedure.getAsmLibrary());
stmtIt.add(new StatementAssignment(parameterDef.getVariableRef(), parameterVal, false, source, comments));
comments = Comment.NO_COMMENTS;

View File

@ -88,7 +88,7 @@ public class Pass4CodeGeneration {
asm.startChunk(currentScope, null, "File Comments");
generateComments(asm, program.getMainFileComments());
// Create a namespace if the output of the compile is an .asm library instead of a program.
// 820/24 - Create a namespace if the output of the compile is an .asm library instead of a program.
if (program.getAsmLibrary() != null) {
asm.startChunk(currentScope, null, "Library");
asm.addNamespaceBegin(program.getAsmLibrary());
@ -190,17 +190,24 @@ public class Pass4CodeGeneration {
}
}
}
generateScopeEnding(asm, currentScope);
// 820/24 - Scope ending of the normal assembler and/or asm library export generation.
if (oldProcedure != null && !oldProcedure.isDeclaredExtern()) {
// The current block is in a different scope. End the old scope.
generateScopeEnding(asm, currentScope);
}
currentScope = ScopeRef.ROOT;
asm.startChunk(currentScope, null, "File Data");
addData(asm, ScopeRef.ROOT);
addAbsoluteAddressData(asm, ScopeRef.ROOT);
// 820/24 - Close the namespace of the asm library.
if (program.getAsmLibrary() != null) {
asm.addNamespaceEnd();
}
// In case of an asm library import, we generate the instructions to import the library.
// 820/25 - Import asm libraries.
// TODO: Solve the need for the #define __asm_import__, to solve the .segmentdef conflict.
for(String asmLibraryName : program.getAsmImports().keySet()) {
asm.addComment("Asm library " + asmLibraryName + ":", false);
@ -912,7 +919,7 @@ public class Pass4CodeGeneration {
}
final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
asm.addInstruction("jsr", CpuAddressingMode.ABS, toProcedure.getCallFullName(), false);
} else {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(toProcedure, callingDistance, program), program);
}

View File

@ -59,16 +59,24 @@ public class Pass4LiveRangeEquivalenceClassesFinalize extends Pass2Base {
EquivalenceClassAdder equivalenceClassAdder = new EquivalenceClassAdder(liveRangeEquivalenceClassSet);
equivalenceClassAdder.visitGraph(getGraph());
// Add any load/store variables with an initializer - and load/store struct variables
// TODO: SVEN - this needs to be carefully tested and reworked where necessary.
// The purpose here is to allocate variables that are not compiled but in libraries.
// And these need to be allocated to equivalence classes in order to coalesce.
for(Variable variable : getSymbols().getAllVariables(true)) {
if(variable.getScope() instanceof Procedure procedure) {
// check if export
// 820/10 - __varcall exported zeropages to be allocated in equivalence classes.
if(getProgram().isProcedureAsmExport((procedure.getFullName()))) {
List<Variable> params = procedure.getParameters();
if(params.contains(variable)) {
addToEquivalenceClassSet(variable.getVariableRef(), new ArrayList<>(), liveRangeEquivalenceClassSet);
}
}
// 820/11 - __varcall imported return values to be allocated in equivalence classes.
if(procedure.isAsmImportLibrary()) {
if(procedure.isReturn(variable)) {
addToEquivalenceClassSet(variable.getVariableRef(), new ArrayList<>(), liveRangeEquivalenceClassSet);
}
}
}
}

View File

@ -77,7 +77,7 @@ void conio_x16_init() {
}
// Returns a value if a key is pressed.
inline unsigned char kbhit(void)
unsigned char kbhit(void)
{
cbm_k_clrchn();
return cbm_k_getin();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
extern __phicall __asm_import(conio_var) void __conio_var_start();
extern __varcall __asm_import(conio_var) void conio_x16_init();
extern __varcall __asm_import(conio_var) void clrscr();
extern __varcall __asm_import(conio_var) void gotoxy(__zp($b) char x, __zp(2) char y);
extern __varcall __asm_import(conio_var) __zp(2) char wherex();
extern __varcall __asm_import(conio_var) __zp(2) char wherey();
extern __varcall __asm_import(conio_var) void screensize(__zp(6) char *x, __zp($e) char *y);
extern __varcall __asm_import(conio_var) __zp(2) char screensizex();
extern __varcall __asm_import(conio_var) __zp(2) char screensizey();
extern __varcall __asm_import(conio_var) void cputln();
extern __stackcall __asm_import(conio_var) void cputc(__zp(8) char c);
extern __varcall __asm_import(conio_var) void cputcxy(__zp($b) char x, __zp(2) char y, __zp(4) char c);
extern __varcall __asm_import(conio_var) void cputs(__zp($c) const char *s);
extern __varcall __asm_import(conio_var) void cputsxy(__zp($b) char x, __zp(2) char y, __zp($e) const char *s);
extern __varcall __asm_import(conio_var) __zp(2) char textcolor(__zp($b) char color);
extern __varcall __asm_import(conio_var) __zp(2) char bgcolor(__zp($b) char color);
extern __varcall __asm_import(conio_var) __zp($b) char bordercolor(__zp(3) char color);
extern __varcall __asm_import(conio_var) __zp($b) char kbhit();
extern __varcall __asm_import(conio_var) __zp($b) char cursor(__zp(2) char onoff);
extern __varcall __asm_import(conio_var) __zp(2) char scroll(__zp(5) char onoff);
extern __varcall __asm_import(conio_var) void screenlayer1();

View File

@ -75,7 +75,7 @@ __conio_var_start: {
// __conio_var_start::@1
// #pragma constructor_for(conio_x16_init, cputc, clrscr, cscroll)
// [4] callexecute conio_x16_init -- call_var_near
jsr conio_var.conio_x16_init
jsr conio_x16_init
// __conio_var_start::@return
// [5] return
rts
@ -91,25 +91,25 @@ conio_x16_init: {
.label conio_x16_init__7 = 5
// screenlayer1()
// [7] callexecute screenlayer1 -- call_var_near
jsr conio_var.screenlayer1
jsr screenlayer1
// textcolor(CONIO_TEXTCOLOR_DEFAULT)
// [8] textcolor::color = WHITE -- vbuz1=vbuc1
lda #WHITE
sta.z conio_var.textcolor.color
// [9] callexecute textcolor -- call_var_near
jsr conio_var.textcolor
jsr textcolor
// bgcolor(CONIO_BACKCOLOR_DEFAULT)
// [10] bgcolor::color = BLUE -- vbuz1=vbuc1
lda #BLUE
sta.z conio_var.bgcolor.color
// [11] callexecute bgcolor -- call_var_near
jsr conio_var.bgcolor
jsr bgcolor
// cursor(0)
// [12] cursor::onoff = 0 -- vbuz1=vbuc1
lda #0
sta.z conio_var.cursor.onoff
// [13] callexecute cursor -- call_var_near
jsr conio_var.cursor
jsr cursor
// cbm_k_plot_get()
// [14] call cbm_k_plot_get
jsr cbm_k_plot_get
@ -144,7 +144,7 @@ conio_x16_init: {
lda __conio+1
sta.z conio_var.gotoxy.y
// [26] callexecute gotoxy -- call_var_near
jsr conio_var.gotoxy
jsr gotoxy
// __conio.scroll[0] = 1
// [27] *((char *)&__conio+$f) = 1 -- _deref_pbuc1=vbuc2
lda #1
@ -346,7 +346,7 @@ cputsxy: {
// [61] gotoxy::x = cputsxy::x
// [62] gotoxy::y = cputsxy::y
// [63] callexecute gotoxy -- call_var_near
jsr conio_var.gotoxy
jsr gotoxy
// cputs(s)
// [64] cputs::s = cputsxy::s -- pbuz1=pbuz2
lda.z s
@ -354,7 +354,7 @@ cputsxy: {
lda.z s+1
sta.z conio_var.cputs.s+1
// [65] callexecute cputs -- call_var_near
jsr conio_var.cputs
jsr cputs
// cputsxy::@return
// }
// [66] return
@ -392,7 +392,7 @@ cputs: {
lda.z c
pha
// [73] callexecute cputc -- call_stack_near
jsr conio_var.cputc
jsr cputc
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
pla
jmp __b1
@ -409,13 +409,13 @@ cputcxy: {
// [75] gotoxy::x = cputcxy::x
// [76] gotoxy::y = cputcxy::y
// [77] callexecute gotoxy -- call_var_near
jsr conio_var.gotoxy
jsr gotoxy
// cputc(c)
// [78] stackpush(char) = cputcxy::c -- _stackpushbyte_=vbuz1
lda.z c
pha
// [79] callexecute cputc -- call_stack_near
jsr conio_var.cputc
jsr cputc
// sideeffect stackpullpadding(1) -- _stackpullpadding_1
pla
// cputcxy::@return
@ -557,7 +557,7 @@ cputc: {
__b6:
// cputln()
// [108] callexecute cputln -- call_var_near
jsr conio_var.cputln
jsr cputln
jmp __b7
// cputc::@5
__b5:
@ -587,14 +587,14 @@ cputc: {
__b8:
// cputln()
// [114] callexecute cputln -- call_var_near
jsr conio_var.cputln
jsr cputln
rts
// [115] phi from cputc to cputc::@1 [phi:cputc->cputc::@1]
// cputc::@1
__b1:
// cputln()
// [116] callexecute cputln -- call_var_near
jsr conio_var.cputln
jsr cputln
rts
}
// screensizey
@ -1243,7 +1243,7 @@ cscroll: {
// [218] gotoxy::y = 0 -- vbuz1=vbuc1
sta.z conio_var.gotoxy.y
// [219] callexecute gotoxy -- call_var_near
jsr conio_var.gotoxy
jsr gotoxy
// cscroll::@return
__breturn:
// }
@ -1264,7 +1264,7 @@ cscroll: {
lda __conio+7
sta.z conio_var.gotoxy.y
// [225] callexecute gotoxy -- call_var_near
jsr conio_var.gotoxy
jsr gotoxy
// clearline()
// [226] call clearline
jsr clearline

View File

@ -0,0 +1,71 @@
// Tests kbhit function call return value
// Print a bunch of different stuff using printf
// Instead of using conio.c and conio.h, this code imports a
// conio (.asm) library, already pre-compiled.
// The sequent #include of <conio.h> is ignored, as the functions are declared as external.
// In this way, any external library function, even when it is part of the standard C libraries,
// is ignored and not compiled when declared as external.
#pragma encoding(screencode_mixed)
#pragma var_model(zp)
#include "conio_var.h"
// Linkage
#pragma link("library.ld")
#include <conio.h>
#include <cx16-conio.h>
#include <printf.h>
void main() {
clrscr();
char c = 'e';
signed char sc = -12;
unsigned char uc = 34;
signed int si = -1234;
unsigned int ui = 5678;
signed long sl = -123456;
unsigned long ul = 567890;
gotoxy(10,2);
// char
printf("A char: %c\n", c);
gotoxy(10,4);
// pointer
printf("A pointer: %p\n", &c);
gotoxy(10,6);
// percent sign
printf("A percent: %%\n");
gotoxy(10,8);
// signed char
printf("A signed char: %hhd\n", sc);
gotoxy(10,10);
// unsigned char
printf("An unsigned char: %hhu\n", uc);
gotoxy(50,2);
// signed int
printf("A signed int: %d\n", si);
gotoxy(50,4);
// unsigned int
printf("An unsigned int: %u\n", ui);
gotoxy(50,6);
// signed long
printf("A signed long: %ld\n", sl);
gotoxy(50,8);
// unsigned long
printf("An unsigned long: %lu\n", ul);
}

View File

@ -18,9 +18,6 @@
#pragma zp_reserve(0x80..0xFF)
#pragma code_seg(CodeConIO)
#pragma data_seg(DataConIO)
//#include "conio-test.h"
#include <conio.h>

View File

@ -0,0 +1,6 @@
#if __asm_import__
#else
.segmentdef Code [start=%P]
.segmentdef Data [startAfter="CodeConIO"]
#endif

View File

@ -0,0 +1,19 @@
#pragma link("library.ld")
#pragma encoding(screencode_mixed)
#pragma var_model(zp)
#pragma asm_library("library_return")
#pragma asm_export("library_return", __varcall, return_1)
#pragma asm_export("library_return", __stackcall, return_2)
#pragma zp_reserve(0x80..0xFF)
char return_1(char num) {
return num+1;
}
char return_2(char num) {
return num+2;
}

View File

@ -0,0 +1,57 @@
// File Comments
// Library
.namespace library_return {
// Upstart
.cpu _65c02
#if __asm_import__
#else
.segmentdef Code [start=$80d]
.segmentdef Data [startAfter="CodeConIO"]
#endif
// Global Constants & labels
.const STACK_BASE = $103
.segment Code
// return_2
// __zp(2) char return_2(__zp(2) char num)
return_2: {
.const OFFSET_STACK_NUM = 0
.const OFFSET_STACK_RETURN_0 = 0
.label num = 2
.label return = 2
// [0] return_2::num#0 = stackidx(char,return_2::OFFSET_STACK_NUM) -- vbuz1=_stackidxbyte_vbuc1
tsx
lda STACK_BASE+OFFSET_STACK_NUM,x
sta.z num
// return num+2;
// [1] return_2::return#0 = return_2::num#0 + 2 -- vbuz1=vbuz1_plus_2
lda.z return
clc
adc #2
sta.z return
// return_2::@return
// }
// [2] stackidx(char,return_2::OFFSET_STACK_RETURN_0) = return_2::return#0 -- _stackidxbyte_vbuc1=vbuz1
tsx
sta STACK_BASE+OFFSET_STACK_RETURN_0,x
// [3] return
rts
}
// return_1
// __zp(2) char return_1(__zp(2) char num)
return_1: {
.label num = 2
.label return = 2
.label return_1__0 = 2
// num+1
// [4] return_1::$0 = return_1::num + 1 -- vbuz1=vbuz1_plus_1
inc.z return_1__0
// return num+1;
// [5] return_1::return = return_1::$0
// return_1::@return
// }
// [6] return
rts
}
// File Data
}

View File

@ -0,0 +1,2 @@
extern __varcall __asm_import(library_return) __zp(2) char return_1(__zp(2) char num);
extern __stackcall __asm_import(library_return) __zp(2) char return_2(__zp(2) char num);

View File

@ -14,7 +14,7 @@
#include "conio_var.h"
// Linkage
#pragma link("printf-library.ld")
#pragma link("library.ld")
#include <conio.h>
#include <cx16-conio.h>

View File

@ -0,0 +1,18 @@
// Tests a return value from a library function.
#pragma encoding(screencode_mixed)
#pragma var_model(zp)
#include "library_return.h"
// Linkage
#pragma link("library.ld")
__export char test = 0;
void main() {
test = return_1(10);
test = return_2(20);
}