From 5b7bec66e8bc9873520700fbca5336538c9455fa Mon Sep 17 00:00:00 2001 From: jespergravgaard Date: Sat, 25 Sep 2021 22:04:47 +0200 Subject: [PATCH] Added #pragma resource() for resource files resource files not referenced in inline KickAsm (for instance in the linker file). Closes #664 --- .../dk/camelot64/kickc/parser/CParser.java | 1 + .../Pass0GenerateStatementSequence.java | 35 ++- .../kickc/test/TestProgramsFast.java | 5 + src/test/kc/inline-kasm-resource-2.c | 22 ++ src/test/ref/inline-kasm-resource-2.asm | 37 +++ src/test/ref/inline-kasm-resource-2.cfg | 11 + src/test/ref/inline-kasm-resource-2.log | 229 ++++++++++++++++++ src/test/ref/inline-kasm-resource-2.sym | 11 + 8 files changed, 340 insertions(+), 11 deletions(-) create mode 100644 src/test/kc/inline-kasm-resource-2.c create mode 100644 src/test/ref/inline-kasm-resource-2.asm create mode 100644 src/test/ref/inline-kasm-resource-2.cfg create mode 100644 src/test/ref/inline-kasm-resource-2.log create mode 100644 src/test/ref/inline-kasm-resource-2.sym diff --git a/src/main/java/dk/camelot64/kickc/parser/CParser.java b/src/main/java/dk/camelot64/kickc/parser/CParser.java index f23dadd2f..45a7be2bf 100644 --- a/src/main/java/dk/camelot64/kickc/parser/CParser.java +++ b/src/main/java/dk/camelot64/kickc/parser/CParser.java @@ -45,6 +45,7 @@ public class CParser { public static final String PRAGMA_CONSTRUCTOR_FOR = "constructor_for"; public static final String PRAGMA_INTERRUPT = "interrupt"; public static final String PRAGMA_STRUCT_MODEL = "struct_model"; + public static final String PRAGMA_RESOURCE = "resource"; /** The Program. */ private Program program; diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java index 53f67d9f4..50a51154a 100644 --- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java +++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java @@ -294,6 +294,10 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor()); - if(resourceFile == null) - throw new CompileError("File not found " + resourceName); - if(!program.getAsmResourceFiles().contains(resourceFile.toPath())) - program.addAsmResourceFile(resourceFile.toPath()); - if(program.getLog().isVerboseParse()) { - program.getLog().append("Added resource " + resourceFile.getPath().replace('\\', '/')); - } + String resourceFileName = resource.getText(); + resourceFileName = resourceFileName.substring(1, resourceFileName.length() - 1); + addResourceFile(ctx, resourceFileName); return null; } throw new CompileError("Unknown ASM directive '"+ctx.NAME().getText()+"'", new StatementSource(ctx)); } + /** + * Add a resource to the program. + * @param ctx The parser context used for finding the folder containing the current source line. + * @param resourceFileName The file name of the resource file. + */ + private void addResourceFile(ParserRuleContext ctx, String resourceFileName) { + Path currentPath = cParser.getSourceFolderPath(ctx); + File resourceFile = SourceLoader.loadFile(resourceFileName, currentPath, new ArrayList<>()); + if(resourceFile == null) + throw new CompileError("File not found " + resourceFileName); + if(!program.getAsmResourceFiles().contains(resourceFile.toPath())) + program.addAsmResourceFile(resourceFile.toPath()); + if(program.getLog().isVerboseParse()) { + program.getLog().append("Added resource " + resourceFile.getPath().replace('\\', '/')); + } + } + /** Information about a declared parameter. */ static class ParameterDecl { final public String name; diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java index 7d1227c46..ed5d659c2 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java +++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java @@ -3672,6 +3672,11 @@ public class TestProgramsFast extends TestPrograms { compileAndCompare("inline-kasm-data.c"); } + @Test + public void testInlineKasmResource2() throws IOException { + compileAndCompare("inline-kasm-resource-2.c"); + } + @Test public void testInlineKasmResource() throws IOException { compileAndCompare("inline-kasm-resource.c"); diff --git a/src/test/kc/inline-kasm-resource-2.c b/src/test/kc/inline-kasm-resource-2.c new file mode 100644 index 000000000..8b89459bf --- /dev/null +++ b/src/test/kc/inline-kasm-resource-2.c @@ -0,0 +1,22 @@ +// Example of inline kickasm resource data - using #pramga resource() + +#pragma resource("balloon.png") + +__address(0x0c00) byte SPRITE[] = kickasm {{ + .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) +}}; + +char* const SCREEN= (char*)0x400; +char* const SPRITES_ENABLE = (char*)0xd015; +char* const SPRITES_XPOS = (char*)0xd000; +char* const SPRITES_YPOS = (char*)0xd001; + +void main() { + *(SCREEN+0x3f8) = (char)((unsigned int)SPRITE/$40); + *SPRITES_ENABLE = 1; + *SPRITES_XPOS = 100; + *SPRITES_YPOS = 100; +} diff --git a/src/test/ref/inline-kasm-resource-2.asm b/src/test/ref/inline-kasm-resource-2.asm new file mode 100644 index 000000000..bb39253d8 --- /dev/null +++ b/src/test/ref/inline-kasm-resource-2.asm @@ -0,0 +1,37 @@ +// Example of inline kickasm resource data - using #pramga resource() + // Commodore 64 PRG executable file +.file [name="inline-kasm-resource-2.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + .label SCREEN = $400 + .label SPRITES_ENABLE = $d015 + .label SPRITES_XPOS = $d000 + .label SPRITES_YPOS = $d001 +.segment Code +main: { + // *(SCREEN+0x3f8) = (char)((unsigned int)SPRITE/$40) + lda #$ff&SPRITE/$40 + sta SCREEN+$3f8 + // *SPRITES_ENABLE = 1 + lda #1 + sta SPRITES_ENABLE + // *SPRITES_XPOS = 100 + lda #$64 + sta SPRITES_XPOS + // *SPRITES_YPOS = 100 + sta SPRITES_YPOS + // } + rts +} +.segment Data +.pc = $c00 "SPRITE" +SPRITE: +.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + diff --git a/src/test/ref/inline-kasm-resource-2.cfg b/src/test/ref/inline-kasm-resource-2.cfg new file mode 100644 index 000000000..6ca07b570 --- /dev/null +++ b/src/test/ref/inline-kasm-resource-2.cfg @@ -0,0 +1,11 @@ + +void main() +main: scope:[main] from + [0] *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 + [1] *SPRITES_ENABLE = 1 + [2] *SPRITES_XPOS = $64 + [3] *SPRITES_YPOS = $64 + to:main::@return +main::@return: scope:[main] from main + [4] return + to:@return diff --git a/src/test/ref/inline-kasm-resource-2.log b/src/test/ref/inline-kasm-resource-2.log new file mode 100644 index 000000000..12f17531d --- /dev/null +++ b/src/test/ref/inline-kasm-resource-2.log @@ -0,0 +1,229 @@ + +CONTROL FLOW GRAPH SSA + +void main() +main: scope:[main] from __start + *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 + *SPRITES_ENABLE = 1 + *SPRITES_XPOS = $64 + *SPRITES_YPOS = $64 + to:main::@return +main::@return: scope:[main] from main + return + to:@return + +void __start() +__start: scope:[__start] from + call main + to:__start::@1 +__start::@1: scope:[__start] from __start + to:__start::@return +__start::@return: scope:[__start] from __start::@1 + return + to:@return + +SYMBOL TABLE SSA +__constant char * const SCREEN = (char *)$400 +__constant char SPRITE[] = kickasm {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + }} +__constant char * const SPRITES_ENABLE = (char *)$d015 +__constant char * const SPRITES_XPOS = (char *)$d000 +__constant char * const SPRITES_YPOS = (char *)$d001 +void __start() +void main() + +Adding number conversion cast (unumber) $40 in *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 +Adding number conversion cast (unumber) $3f8 in *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/(unumber)$40 +Adding number conversion cast (unumber) 1 in *SPRITES_ENABLE = 1 +Adding number conversion cast (unumber) $64 in *SPRITES_XPOS = $64 +Adding number conversion cast (unumber) $64 in *SPRITES_YPOS = $64 +Successful SSA optimization PassNAddNumberTypeConversions +Inlining cast *SPRITES_ENABLE = (unumber)1 +Inlining cast *SPRITES_XPOS = (unumber)$64 +Inlining cast *SPRITES_YPOS = (unumber)$64 +Successful SSA optimization Pass2InlineCast +Simplifying constant pointer cast (char *) 1024 +Simplifying constant pointer cast (char *) 53269 +Simplifying constant pointer cast (char *) 53248 +Simplifying constant pointer cast (char *) 53249 +Simplifying constant integer cast $40 +Simplifying constant integer cast $3f8 +Simplifying constant integer cast 1 +Simplifying constant integer cast $64 +Simplifying constant integer cast $64 +Successful SSA optimization PassNCastSimplification +Finalized unsigned number type (char) $40 +Finalized unsigned number type (unsigned int) $3f8 +Finalized unsigned number type (char) 1 +Finalized unsigned number type (char) $64 +Finalized unsigned number type (char) $64 +Successful SSA optimization PassNFinalizeNumberTypeConversions +Removing unused procedure __start +Removing unused procedure block __start +Removing unused procedure block __start::@1 +Removing unused procedure block __start::@return +Successful SSA optimization PassNEliminateEmptyStart +Finalized unsigned number type (unsigned int) $c00 +Successful SSA optimization PassNFinalizeNumberTypeConversions +CALL GRAPH + +Created 0 initial phi equivalence classes +Coalesced down to 0 phi equivalence classes + +FINAL CONTROL FLOW GRAPH + +void main() +main: scope:[main] from + [0] *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 + [1] *SPRITES_ENABLE = 1 + [2] *SPRITES_XPOS = $64 + [3] *SPRITES_YPOS = $64 + to:main::@return +main::@return: scope:[main] from main + [4] return + to:@return + + +VARIABLE REGISTER WEIGHTS +void main() + +Initial phi equivalence classes +Complete equivalence classes +REGISTER UPLIFT POTENTIAL REGISTERS +Statement [0] *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 [ ] ( [ ] { } ) always clobbers reg byte a +Statement [1] *SPRITES_ENABLE = 1 [ ] ( [ ] { } ) always clobbers reg byte a +Statement [2] *SPRITES_XPOS = $64 [ ] ( [ ] { } ) always clobbers reg byte a +Statement [3] *SPRITES_YPOS = $64 [ ] ( [ ] { } ) always clobbers reg byte a + +REGISTER UPLIFT SCOPES +Uplift Scope [main] +Uplift Scope [] + +Uplifting [main] best 33 combination +Uplifting [] best 33 combination + +ASSEMBLER BEFORE OPTIMIZATION + // File Comments +// Example of inline kickasm resource data - using #pramga resource() + // Upstart + // Commodore 64 PRG executable file +.file [name="inline-kasm-resource-2.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + .label SCREEN = $400 + .label SPRITES_ENABLE = $d015 + .label SPRITES_XPOS = $d000 + .label SPRITES_YPOS = $d001 +.segment Code + // main +main: { + // [0] *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 -- _deref_pbuc1=vbuc2 + lda #$ff&SPRITE/$40 + sta SCREEN+$3f8 + // [1] *SPRITES_ENABLE = 1 -- _deref_pbuc1=vbuc2 + lda #1 + sta SPRITES_ENABLE + // [2] *SPRITES_XPOS = $64 -- _deref_pbuc1=vbuc2 + lda #$64 + sta SPRITES_XPOS + // [3] *SPRITES_YPOS = $64 -- _deref_pbuc1=vbuc2 + lda #$64 + sta SPRITES_YPOS + jmp __breturn + // main::@return + __breturn: + // [4] return + rts +} + // File Data +.segment Data +.pc = $c00 "SPRITE" +SPRITE: +.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + + +ASSEMBLER OPTIMIZATIONS +Removing instruction jmp __breturn +Succesful ASM optimization Pass5NextJumpElimination +Removing instruction lda #$64 +Succesful ASM optimization Pass5UnnecesaryLoadElimination +Removing instruction __breturn: +Succesful ASM optimization Pass5UnusedLabelElimination + +FINAL SYMBOL TABLE +__constant char * const SCREEN = (char *) 1024 +__constant char SPRITE[] = kickasm {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + }} +__constant char * const SPRITES_ENABLE = (char *) 53269 +__constant char * const SPRITES_XPOS = (char *) 53248 +__constant char * const SPRITES_YPOS = (char *) 53249 +void main() + + + +FINAL ASSEMBLER +Score: 28 + + // File Comments +// Example of inline kickasm resource data - using #pramga resource() + // Upstart + // Commodore 64 PRG executable file +.file [name="inline-kasm-resource-2.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$80d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(main) + // Global Constants & labels + .label SCREEN = $400 + .label SPRITES_ENABLE = $d015 + .label SPRITES_XPOS = $d000 + .label SPRITES_YPOS = $d001 +.segment Code + // main +main: { + // *(SCREEN+0x3f8) = (char)((unsigned int)SPRITE/$40) + // [0] *(SCREEN+$3f8) = (char)(unsigned int)SPRITE/$40 -- _deref_pbuc1=vbuc2 + lda #$ff&SPRITE/$40 + sta SCREEN+$3f8 + // *SPRITES_ENABLE = 1 + // [1] *SPRITES_ENABLE = 1 -- _deref_pbuc1=vbuc2 + lda #1 + sta SPRITES_ENABLE + // *SPRITES_XPOS = 100 + // [2] *SPRITES_XPOS = $64 -- _deref_pbuc1=vbuc2 + lda #$64 + sta SPRITES_XPOS + // *SPRITES_YPOS = 100 + // [3] *SPRITES_YPOS = $64 -- _deref_pbuc1=vbuc2 + sta SPRITES_YPOS + // main::@return + // } + // [4] return + rts +} + // File Data +.segment Data +.pc = $c00 "SPRITE" +SPRITE: +.var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + + diff --git a/src/test/ref/inline-kasm-resource-2.sym b/src/test/ref/inline-kasm-resource-2.sym new file mode 100644 index 000000000..48e3480ee --- /dev/null +++ b/src/test/ref/inline-kasm-resource-2.sym @@ -0,0 +1,11 @@ +__constant char * const SCREEN = (char *) 1024 +__constant char SPRITE[] = kickasm {{ .var pic = LoadPicture("balloon.png", List().add($000000, $ffffff)) + .for (var y=0; y<21; y++) + .for (var x=0;x<3; x++) + .byte pic.getSinglecolorByte(x,y) + }} +__constant char * const SPRITES_ENABLE = (char *) 53269 +__constant char * const SPRITES_XPOS = (char *) 53248 +__constant char * const SPRITES_YPOS = (char *) 53249 +void main() +