diff --git a/pom.xml b/pom.xml index 72dca79eb..1b67bb9a3 100644 --- a/pom.xml +++ b/pom.xml @@ -69,6 +69,7 @@ **/*.c **/*.h + **/*.ld **/*.asm **/*.sym **/*.cfg diff --git a/src/main/assembly/assembly.xml b/src/main/assembly/assembly.xml index c6dc0c840..e9657185e 100644 --- a/src/main/assembly/assembly.xml +++ b/src/main/assembly/assembly.xml @@ -17,6 +17,7 @@ *.c *.h + *.ld @@ -25,6 +26,7 @@ *.c *.h + *.ld diff --git a/src/main/java/dk/camelot64/kickc/Compiler.java b/src/main/java/dk/camelot64/kickc/Compiler.java index 7f9f4e26f..68eab56c2 100644 --- a/src/main/java/dk/camelot64/kickc/Compiler.java +++ b/src/main/java/dk/camelot64/kickc/Compiler.java @@ -8,18 +8,18 @@ import dk.camelot64.kickc.model.statements.StatementSource; import dk.camelot64.kickc.model.symbols.Procedure; import dk.camelot64.kickc.model.values.SymbolRef; import dk.camelot64.kickc.parser.CParser; +import dk.camelot64.kickc.parser.KickCLexer; import dk.camelot64.kickc.parser.KickCParser; import dk.camelot64.kickc.passes.*; import dk.camelot64.kickc.preprocessor.CPreprocessor; -import org.antlr.v4.runtime.RuleContext; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.TokenSource; +import org.antlr.v4.runtime.*; import java.io.File; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Map; /** * Perform KickC compilation and optimizations @@ -148,13 +148,35 @@ public class Compiler { program.getLibraryPaths().add(path); } - public void preprocess(List cFiles) { - Path currentPath = new File(".").toPath(); + /** + * Create a CParser and initialize it by adding any command-line defines and loading the files. + * + * @param defines The defined to add + * @param cFiles The files to load + * @param currentPath The current path (used to search for files) + * @return The initialized parser + */ + private CParser initializeParser(Map defines, List cFiles, Path currentPath) { CParser cParser = new CParser(program); + if(defines != null) { + for(String macroName : defines.keySet()) { + final String macroBodyText = "#define " + macroName + " " + defines.get(macroName) + "\n"; + final CodePointCharStream macroCharStream = CharStreams.fromString(macroBodyText); + final KickCLexer macroLexer = cParser.makeLexer(macroCharStream); + cParser.addSourceFirst(macroLexer); + } + } for(Path cFile : cFiles) { final TokenSource cFileTokens = cParser.loadCFile(cFile.toString(), currentPath, program.getIncludePaths(), false); cParser.addSourceLast(cFileTokens); } + return cParser; + } + + + public void preprocess(List cFiles, Map defines) { + Path currentPath = new File(".").toPath(); + CParser cParser = initializeParser(defines, cFiles, currentPath); final CPreprocessor preprocessor = cParser.getPreprocessor(); Token token = preprocessor.nextToken(); while(token.getType() != Token.EOF) { @@ -164,7 +186,7 @@ public class Compiler { System.out.println(); } - public void compile(List cFiles) { + public void compile(List cFiles, Map defines) { if(cFiles.size() == 0) throw new CompileError("Error! You must supply at least one file to compile!"); @@ -178,11 +200,7 @@ public class Compiler { SourceLoader.loadLinkScriptFile(linkScriptFileName, currentPath, program); } program.setStatementSequence(new StatementSequence()); - CParser cParser = new CParser(program); - for(Path cFile : cFiles) { - final TokenSource cFileTokens = cParser.loadCFile(cFile.toString(), currentPath, program.getIncludePaths(), false); - cParser.addSourceLast(cFileTokens); - } + CParser cParser = initializeParser(defines, cFiles, currentPath); // Parse the files KickCParser.FileContext cFileContext = cParser.getParser().file(); diff --git a/src/main/java/dk/camelot64/kickc/KickC.java b/src/main/java/dk/camelot64/kickc/KickC.java index 8557ff79a..fdc222f8a 100644 --- a/src/main/java/dk/camelot64/kickc/KickC.java +++ b/src/main/java/dk/camelot64/kickc/KickC.java @@ -18,6 +18,7 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.concurrent.Callable; import java.util.stream.Collectors; @@ -40,15 +41,6 @@ public class KickC implements Callable { @CommandLine.Parameters(index = "0", arity = "0..n", description = "The C source files to compile.") private List cFiles = null; - @CommandLine.Option(names = {"-I", "-includedir"}, description = "Path to an include folder, where the compiler looks for included files. This option can be repeated to add multiple include folders.") - private List includeDir = null; - - @CommandLine.Option(names = {"-L", "-libdir"}, description = "Path to a library folder, where the compiler looks for library files. This option can be repeated to add multiple library folders.") - private List libDir = null; - - @CommandLine.Option(names = {"-F", "-fragmentdir"}, description = "Path to the ASM fragment folder, where the compiler looks for ASM fragments.") - private Path fragmentDir = null; - @CommandLine.Option(names = {"-o", "-output"}, description = "Name of the output file. By default it is the same as the first input file with the proper extension.") private String outputFileName = null; @@ -67,9 +59,21 @@ public class KickC implements Callable { @CommandLine.Option(names = {"-d"}, description = "Debug the assembled prg file using C64Debugger. Implicitly assembles the output.") private boolean debug = false; + @CommandLine.Option(names = {"-D"}, description = "Define a macro to have a specific value.") + private Map defines = null; + @CommandLine.Option(names = {"-E"}, description = "Only run the preprocessor. Output is sent to standard out.") private boolean preprocess = false; + @CommandLine.Option(names = {"-I", "-includedir"}, description = "Path to an include folder, where the compiler looks for included files. This option can be repeated to add multiple include folders.") + private List includeDir = null; + + @CommandLine.Option(names = {"-L", "-libdir"}, description = "Path to a library folder, where the compiler looks for library files. This option can be repeated to add multiple library folders.") + private List libDir = null; + + @CommandLine.Option(names = {"-F", "-fragmentdir"}, description = "Path to the ASM fragment folder, where the compiler looks for ASM fragments.") + private Path fragmentDir = null; + @CommandLine.Option(names = {"-Ouplift"}, description = "Optimization Option. Number of combinations to test when uplifting variables to registers in a scope. By default 100 combinations are tested.") private Integer optimizeUpliftCombinations = null; @@ -346,7 +350,7 @@ public class KickC implements Callable { if(preprocess) { System.out.println("Preprocessing " + CFileNames); try { - compiler.preprocess(cFiles); + compiler.preprocess(cFiles, defines); } catch(CompileError e) { // Print the error and exit with compile error System.err.println(e.getMessage()); @@ -358,7 +362,7 @@ public class KickC implements Callable { System.out.println("Compiling " + CFileNames); Program program = compiler.getProgram(); try { - compiler.compile(cFiles); + compiler.compile(cFiles, defines); } catch(CompileError e) { // Print the error and exit with compile error System.err.println(e.getMessage()); @@ -396,13 +400,12 @@ public class KickC implements Callable { // Find emulator - if set by #pragma if(emulator == null) { - if(program.getEmulatorCommand() != null) + if(program.getEmulatorCommand() != null && (debug || execute)) emulator = program.getEmulatorCommand(); - else if(debug) { + else if(debug) emulator = "C64Debugger"; - } else if(execute) { + else if(execute) emulator = "x64sc"; - } } if(assemble || emulator != null) { diff --git a/src/main/kc/include/c64.h b/src/main/kc/include/c64.h index 1ce577c4e..b4431709a 100644 --- a/src/main/kc/include/c64.h +++ b/src/main/kc/include/c64.h @@ -27,6 +27,8 @@ struct MOS6581_SID * const SID = 0xd400; // The VIC-II MOS 6567/6569 struct MOS6569_VICII* const VICII = 0xd000; // Color Ram +char * const COLORRAM = 0xd800; +// Color Ram char * const COLS = 0xd800; // The CIA#1: keyboard matrix, joystick #1/#2 diff --git a/src/main/kc/include/c64.ld b/src/main/kc/include/c64.ld new file mode 100644 index 000000000..a66015cac --- /dev/null +++ b/src/main/kc/include/c64.ld @@ -0,0 +1,9 @@ +.file [name="%O.prg", type="prg", segments="Program"] +.segmentdef Program [segments="Basic, Code, Data"] +.segmentdef Basic [start=$0801] +.segmentdef Code [start=$080d] +.segmentdef Data [startAfter="Code"] +.segment Basic +:BasicUpstart(%E) +.segment Code + diff --git a/src/test/kc/examples/plus4walk/plus4.ld b/src/main/kc/include/plus4.ld similarity index 87% rename from src/test/kc/examples/plus4walk/plus4.ld rename to src/main/kc/include/plus4.ld index 7e2af5568..cd18c7d93 100644 --- a/src/test/kc/examples/plus4walk/plus4.ld +++ b/src/main/kc/include/plus4.ld @@ -1,7 +1,7 @@ .file [name="%O.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$1001] -.segmentdef Code [start=$1010] +.segmentdef Code [start=$100d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(%E) diff --git a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java index afcc828de..3fc082378 100644 --- a/src/test/java/dk/camelot64/kickc/test/TestPrograms.java +++ b/src/test/java/dk/camelot64/kickc/test/TestPrograms.java @@ -23,6 +23,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.LinkedHashMap; import static junit.framework.TestCase.fail; import static org.junit.Assert.assertTrue; @@ -4304,7 +4305,7 @@ public class TestPrograms { final ArrayList files = new ArrayList<>(); final Path filePath = Paths.get(fileName); files.add(filePath); - compiler.compile(files); + compiler.compile(files, null); Program program = compiler.getProgram(); compileAsm(fileName, program); boolean success = true; diff --git a/src/test/ref/examples/plus4walk/plus4walk.asm b/src/test/ref/examples/plus4walk/plus4walk.asm index 7c0c4bb2e..d12795090 100644 --- a/src/test/ref/examples/plus4walk/plus4walk.asm +++ b/src/test/ref/examples/plus4walk/plus4walk.asm @@ -2,7 +2,7 @@ .file [name="plus4walk.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$1001] -.segmentdef Code [start=$1010] +.segmentdef Code [start=$100d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(__bbegin) diff --git a/src/test/ref/examples/plus4walk/plus4walk.log b/src/test/ref/examples/plus4walk/plus4walk.log index 5ee7a244e..235f17be8 100644 --- a/src/test/ref/examples/plus4walk/plus4walk.log +++ b/src/test/ref/examples/plus4walk/plus4walk.log @@ -1103,7 +1103,7 @@ Target platform is custom / MOS6502X .file [name="plus4walk.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$1001] -.segmentdef Code [start=$1010] +.segmentdef Code [start=$100d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(__bbegin) @@ -1746,7 +1746,7 @@ ASSEMBLER BEFORE OPTIMIZATION .file [name="plus4walk.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$1001] -.segmentdef Code [start=$1010] +.segmentdef Code [start=$100d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(__bbegin) @@ -2448,7 +2448,7 @@ Score: 6721 .file [name="plus4walk.prg", type="prg", segments="Program"] .segmentdef Program [segments="Basic, Code, Data"] .segmentdef Basic [start=$1001] -.segmentdef Code [start=$1010] +.segmentdef Code [start=$100d] .segmentdef Data [startAfter="Code"] .segment Basic :BasicUpstart(__bbegin)