mirror of
https://gitlab.com/camelot/kickc.git
synced 2025-04-09 05:37:16 +00:00
Added support for header-files found in include-folders and C-files found in library-folders. The compiler auto-searches for the C-file in the defined lib search path whenever a H-file is included. Closes #387
This commit is contained in:
parent
c150976b2f
commit
a378e831e2
@ -15,7 +15,8 @@ release:
|
||||
paths:
|
||||
- ./kickc/bin
|
||||
- ./kickc/lib
|
||||
- ./kickc/stdlib
|
||||
- ./kickc/include
|
||||
- ./kickc/lib
|
||||
- ./kickc/fragment
|
||||
- ./kickc/examples
|
||||
- ./kickc/LICENSE*
|
||||
|
@ -12,8 +12,16 @@
|
||||
</dependencySets>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>src/main/kc/stdlib</directory>
|
||||
<outputDirectory>stdlib</outputDirectory>
|
||||
<directory>src/main/kc/include</directory>
|
||||
<outputDirectory>include</outputDirectory>
|
||||
<includes>
|
||||
<include>*.c</include>
|
||||
<include>*.h</include>
|
||||
</includes>
|
||||
</fileSet>
|
||||
<fileSet>
|
||||
<directory>src/main/kc/lib</directory>
|
||||
<outputDirectory>lib</outputDirectory>
|
||||
<includes>
|
||||
<include>*.c</include>
|
||||
<include>*.h</include>
|
||||
|
@ -8,12 +8,12 @@ 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 java.io.File;
|
||||
import java.nio.file.Path;
|
||||
@ -140,16 +140,20 @@ public class Compiler {
|
||||
return program.getLog();
|
||||
}
|
||||
|
||||
public void addImportPath(String path) {
|
||||
program.getImportPaths().add(path);
|
||||
public void addIncludePath(String path) {
|
||||
program.getIncludePaths().add(path);
|
||||
}
|
||||
|
||||
public void addLibraryPath(String path) {
|
||||
program.getLibraryPaths().add(path);
|
||||
}
|
||||
|
||||
public void preprocess(List<Path> cFiles) {
|
||||
Path currentPath = new File(".").toPath();
|
||||
CParser cParser = new CParser(program);
|
||||
for(Path cFile : cFiles) {
|
||||
final KickCLexer fileLexer = cParser.loadCFile(cFile.toString(), currentPath);
|
||||
cParser.addSourceLast(fileLexer);
|
||||
final TokenSource cFileTokens = cParser.loadCFile(cFile.toString(), currentPath, program.getIncludePaths(), false);
|
||||
cParser.addSourceLast(cFileTokens);
|
||||
}
|
||||
final CPreprocessor preprocessor = cParser.getPreprocessor();
|
||||
Token token = preprocessor.nextToken();
|
||||
@ -175,9 +179,9 @@ public class Compiler {
|
||||
}
|
||||
program.setStatementSequence(new StatementSequence());
|
||||
CParser cParser = new CParser(program);
|
||||
for(Path file : cFiles) {
|
||||
final KickCLexer fileLexer = cParser.loadCFile(file.toString(), currentPath);
|
||||
cParser.addSourceLast(fileLexer);
|
||||
for(Path cFile : cFiles) {
|
||||
final TokenSource cFileTokens = cParser.loadCFile(cFile.toString(), currentPath, program.getIncludePaths(), false);
|
||||
cParser.addSourceLast(cFileTokens);
|
||||
}
|
||||
|
||||
// Parse the files
|
||||
|
@ -40,7 +40,10 @@ public class KickC implements Callable<Void> {
|
||||
@CommandLine.Parameters(index = "0", arity = "0..n", description = "The C source files to compile.")
|
||||
private List<Path> cFiles = null;
|
||||
|
||||
@CommandLine.Option(names = {"-I", "-libdir"}, description = "Path to a library folder, where the compiler looks for included files. This option can be repeated to add multiple library folders.")
|
||||
@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<Path> 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<Path> libDir = null;
|
||||
|
||||
@CommandLine.Option(names = {"-F", "-fragmentdir"}, description = "Path to the ASM fragment folder, where the compiler looks for ASM fragments.")
|
||||
@ -205,9 +208,15 @@ public class KickC implements Callable<Void> {
|
||||
compiler.setTargetCpu(targetCpu);
|
||||
}
|
||||
|
||||
if(includeDir != null) {
|
||||
for(Path includePath : includeDir) {
|
||||
compiler.addIncludePath(includePath.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if(libDir != null) {
|
||||
for(Path libPath : libDir) {
|
||||
compiler.addImportPath(libPath.toString());
|
||||
compiler.addLibraryPath(libPath.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,16 +16,23 @@ import java.util.List;
|
||||
*/
|
||||
public class SourceLoader {
|
||||
|
||||
public static File loadFile(String fileName, Path currentPath, Program program) {
|
||||
List<String> searchPaths = new ArrayList<>();
|
||||
/**
|
||||
* Locate a file and load it. Looks through the current path and a set of search folder.
|
||||
* @param fileName The file to look for.
|
||||
* @param currentPath The current path. May be null.
|
||||
* @param searchPaths The search paths to look through if the file is not found in the current path.
|
||||
* @return The file if found. null if not.
|
||||
*/
|
||||
public static File loadFile(String fileName, Path currentPath, List<String> searchPaths) {
|
||||
List<String> allSearchPaths = new ArrayList<>();
|
||||
if(currentPath != null)
|
||||
searchPaths.add(currentPath.toString());
|
||||
searchPaths.addAll(program.getImportPaths());
|
||||
for(String importPath : searchPaths) {
|
||||
if(!importPath.endsWith("/")) {
|
||||
importPath += "/";
|
||||
allSearchPaths.add(currentPath.toString());
|
||||
allSearchPaths.addAll(searchPaths);
|
||||
for(String searchPath : allSearchPaths) {
|
||||
if(!searchPath.endsWith("/")) {
|
||||
searchPath += "/";
|
||||
}
|
||||
String filePath = importPath + fileName;
|
||||
String filePath = searchPath + fileName;
|
||||
//System.out.println("Looking for file "+filePath);
|
||||
File file = new File(filePath);
|
||||
if(file.exists()) {
|
||||
@ -33,12 +40,15 @@ public class SourceLoader {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
throw new CompileError("File not found " + fileName);
|
||||
// Not found
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void loadLinkScriptFile(String fileName, Path currentPath, Program program) {
|
||||
try {
|
||||
File file = loadFile(fileName, currentPath, program);
|
||||
File file = loadFile(fileName, currentPath, program.getIncludePaths());
|
||||
if(file==null)
|
||||
throw new CompileError("File not found " + fileName);
|
||||
Path filePath = file.toPath();
|
||||
String linkScript = new String(Files.readAllBytes(filePath));
|
||||
program.setLinkScript(filePath, linkScript);
|
||||
|
@ -21,10 +21,12 @@ public class Program {
|
||||
|
||||
/** The name of the primary file being compiled. PASS 0-5 (STATIC) */
|
||||
private String primaryFileName;
|
||||
/** Paths used for importing files. PASS 0 (STATIC) */
|
||||
private List<String> importPaths;
|
||||
/** Imported files. PASS 0 (STATIC) */
|
||||
private List<String> imported;
|
||||
/** Paths used for including files. PASS 0 (STATIC) */
|
||||
private List<String> includePaths;
|
||||
/** Paths used for library files. PASS 0 (STATIC) */
|
||||
private List<String> libraryPaths;
|
||||
/** All loaded H/C-files. PASS 0 (STATIC) */
|
||||
private List<String> loadedFiles;
|
||||
|
||||
/** The target platform that the program is being build for. PASS 0-5 (STATIC) */
|
||||
private TargetPlatform targetPlatform = TargetPlatform.DEFAULT;
|
||||
@ -106,8 +108,9 @@ public class Program {
|
||||
public Program() {
|
||||
this.scope = new ProgramScope();
|
||||
this.log = new CompileLog();
|
||||
this.importPaths = new ArrayList<>();
|
||||
this.imported = new ArrayList<>();
|
||||
this.includePaths = new ArrayList<>();
|
||||
this.libraryPaths = new ArrayList<>();
|
||||
this.loadedFiles = new ArrayList<>();
|
||||
this.asmResourceFiles = new ArrayList<>();
|
||||
this.reservedZps = new ArrayList<>();
|
||||
}
|
||||
@ -116,8 +119,9 @@ public class Program {
|
||||
* Clears all data that is only used in PASS 1
|
||||
*/
|
||||
public void endPass1() {
|
||||
this.importPaths = null;
|
||||
this.imported = null;
|
||||
this.includePaths = null;
|
||||
this.libraryPaths = null;
|
||||
this.loadedFiles = null;
|
||||
this.statementSequence = null;
|
||||
this.procedureModifiedVars = null;
|
||||
this.structVariableMemberUnwinding = null;
|
||||
@ -249,12 +253,16 @@ public class Program {
|
||||
this.fileComments = fileComments;
|
||||
}
|
||||
|
||||
public List<String> getImportPaths() {
|
||||
return importPaths;
|
||||
public List<String> getIncludePaths() {
|
||||
return includePaths;
|
||||
}
|
||||
|
||||
public List<String> getImported() {
|
||||
return imported;
|
||||
public List<String> getLibraryPaths() {
|
||||
return libraryPaths;
|
||||
}
|
||||
|
||||
public List<String> getLoadedFiles() {
|
||||
return loadedFiles;
|
||||
}
|
||||
|
||||
public List<Path> getAsmResourceFiles() {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package dk.camelot64.kickc.parser;
|
||||
|
||||
import dk.camelot64.kickc.Compiler;
|
||||
import dk.camelot64.kickc.SourceLoader;
|
||||
import dk.camelot64.kickc.model.CompileError;
|
||||
import dk.camelot64.kickc.model.Program;
|
||||
@ -93,6 +94,7 @@ public class CParser {
|
||||
|
||||
/**
|
||||
* Get the preprocessor (usable for getting all preprocessed tokens).
|
||||
*
|
||||
* @return The preprocessor
|
||||
*/
|
||||
public CPreprocessor getPreprocessor() {
|
||||
@ -147,15 +149,24 @@ public class CParser {
|
||||
|
||||
/**
|
||||
* Loads a C-file (if it has not already been loaded).
|
||||
*
|
||||
* <p>
|
||||
* The C-file is inserted into the C token stream at the current parse-point - so the parser will parse the entire content of the file before moving on.
|
||||
*
|
||||
* @param fileName The file name of the file
|
||||
*/
|
||||
public void includeCFile(String fileName, boolean isSystem) {
|
||||
if(fileName.startsWith("\"") || fileName.startsWith("<")) {
|
||||
fileName = fileName.substring(1, fileName.length() - 1);
|
||||
}
|
||||
final Path currentSourceFolderPath = isSystem ? null : getCurrentSourceFolderPath();
|
||||
final KickCLexer lexer = loadCFile(fileName, currentSourceFolderPath);
|
||||
addSourceFirst(lexer);
|
||||
final TokenSource fileTokens = loadCFile(fileName, currentSourceFolderPath, program.getIncludePaths(), false);
|
||||
if(fileName.endsWith(".h")) {
|
||||
// The included file was a H-file - attempt to find the matching library C-file
|
||||
String libFileName = Compiler.removeFileNameExtension(fileName) + ".c";
|
||||
final TokenSource cLibFileTokens = loadCFile(libFileName, currentSourceFolderPath, program.getLibraryPaths(), true);
|
||||
addSourceFirst(cLibFileTokens);
|
||||
}
|
||||
addSourceFirst(fileTokens);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -163,20 +174,23 @@ public class CParser {
|
||||
*
|
||||
* @param fileName The file name of the file
|
||||
* @param currentPath The path of the current folder (searched before the search path).
|
||||
* @return The lexer to be inserted into the source-list using one of the {@link #addSourceFirst(KickCLexer)} / {@link #addSourceLast(KickCLexer)} methods.
|
||||
* @param searchPaths The folders to look in if the files is not found in current path
|
||||
* @return The lexer tokens to be inserted into the source-list using one of the {@link #addSourceFirst(TokenSource)} / {@link #addSourceLast(TokenSource)} methods.
|
||||
*/
|
||||
public KickCLexer loadCFile(String fileName, Path currentPath) {
|
||||
public TokenSource loadCFile(String fileName, Path currentPath, List<String> searchPaths, boolean acceptFileNotFound) {
|
||||
try {
|
||||
if(fileName.startsWith("\"") || fileName.startsWith("<")) {
|
||||
fileName = fileName.substring(1, fileName.length() - 1);
|
||||
}
|
||||
File file = SourceLoader.loadFile(fileName, currentPath, program);
|
||||
List<String> imported = program.getImported();
|
||||
if(imported.contains(file.getAbsolutePath())) {
|
||||
File file = SourceLoader.loadFile(fileName, currentPath, searchPaths);
|
||||
if(file == null)
|
||||
if(acceptFileNotFound)
|
||||
return null;
|
||||
else
|
||||
throw new CompileError("File not found " + fileName);
|
||||
List<String> included = program.getLoadedFiles();
|
||||
if(included.contains(file.getAbsolutePath())) {
|
||||
return null;
|
||||
}
|
||||
final CharStream fileStream = CharStreams.fromPath(file.toPath().toAbsolutePath());
|
||||
imported.add(file.getAbsolutePath());
|
||||
included.add(file.getAbsolutePath());
|
||||
if(program.getLog().isVerboseParse()) {
|
||||
program.getLog().append("PARSING " + file.getPath().replace("\\", "/"));
|
||||
program.getLog().append(fileStream.toString());
|
||||
@ -217,21 +231,21 @@ public class CParser {
|
||||
/**
|
||||
* Add source code at the start of the token stream being parsed.
|
||||
*
|
||||
* @param lexer The lexer for reading the source tokens
|
||||
* @param tokenSource The lexer for reading the source tokens
|
||||
*/
|
||||
public void addSourceFirst(KickCLexer lexer) {
|
||||
if(lexer != null)
|
||||
cTokenSource.addSourceFirst(lexer);
|
||||
public void addSourceFirst(TokenSource tokenSource) {
|
||||
if(tokenSource != null)
|
||||
cTokenSource.addSourceFirst(tokenSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add source code at the end of the token stream being parsed.
|
||||
*
|
||||
* @param lexer The lexer for reading the source tokens
|
||||
* @param tokenSource The lexer for reading the source tokens
|
||||
*/
|
||||
public void addSourceLast(KickCLexer lexer) {
|
||||
if(lexer != null)
|
||||
cTokenSource.addSourceLast(lexer);
|
||||
public void addSourceLast(TokenSource tokenSource) {
|
||||
if(tokenSource != null)
|
||||
cTokenSource.addSourceLast(tokenSource);
|
||||
}
|
||||
|
||||
|
||||
|
@ -255,7 +255,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
if(existingSymbol!=null) {
|
||||
// Already declared - check equality
|
||||
if(!SymbolTypeConversion.procedureDeclarationMatch((Procedure) existingSymbol, procedure))
|
||||
throw new CompileError("Error! Conflicting declarations for: "+procedure.getFullName(), StatementSource.procedureBegin(ctx));
|
||||
throw new CompileError("Error! Conflicting declarations for: "+procedure.getFullName(), new StatementSource(ctx));
|
||||
} else {
|
||||
// Not declared before - add it
|
||||
program.getScope().add(procedure);
|
||||
@ -527,7 +527,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
String resourceName = resource.getText();
|
||||
resourceName = resourceName.substring(1, resourceName.length() - 1);
|
||||
Path currentPath = cParser.getSourceFolderPath(ctx);
|
||||
File resourceFile = SourceLoader.loadFile(resourceName, currentPath, program);
|
||||
File resourceFile = SourceLoader.loadFile(resourceName, currentPath, new ArrayList<>());
|
||||
if(resourceFile==null)
|
||||
throw new CompileError("File not found " + resourceName);
|
||||
program.addAsmResourceFile(resourceFile.toPath());
|
||||
if(program.getLog().isVerboseParse()) {
|
||||
program.getLog().append("Added resource " + resourceFile.getPath().replace('\\', '/'));
|
||||
@ -873,28 +875,34 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
||||
final List<Directive> effectiveDirectives = varDecl.getEffectiveDirectives();
|
||||
final List<Comment> declComments = varDecl.getDeclComments();
|
||||
varDecl.exitVar();
|
||||
|
||||
if(isStructMember && (initializer != null))
|
||||
throw new CompileError("Initializer not supported inside structs " + effectiveType.getTypeName(), statementSource);
|
||||
if(initializer != null)
|
||||
PrePostModifierHandler.addPreModifiers(this, initializer, statementSource);
|
||||
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
|
||||
initValue = Initializers.constantify(initValue, new Initializers.ValueTypeSpec(effectiveType, effectiveArraySpec), program, statementSource);
|
||||
VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, effectiveType, effectiveArraySpec, effectiveDirectives, currentDataSegment, variableBuilderConfig);
|
||||
Variable variable = varBuilder.build();
|
||||
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
|
||||
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !isStructMember && variable.getRegister() == null)) {
|
||||
// Set initial value
|
||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
variable.setInitValue(constInitValue);
|
||||
// Add comments to constant
|
||||
variable.setComments(ensureUnusedComments(declComments));
|
||||
} else if(!variable.isKindConstant() && !isStructMember) {
|
||||
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, statementSource, ensureUnusedComments(declComments));
|
||||
sequence.addStatement(initStmt);
|
||||
if(isStructMember && (initializer != null))
|
||||
throw new CompileError("Initializer not supported inside structs " + effectiveType.getTypeName(), statementSource);
|
||||
if(variable.isDeclarationOnly()) {
|
||||
if(initializer != null) {
|
||||
throw new CompileError("Initializer not allowed for extern variables " + varName, statementSource);
|
||||
}
|
||||
} else {
|
||||
// Create a proper initializer
|
||||
if(initializer != null)
|
||||
PrePostModifierHandler.addPreModifiers(this, initializer, statementSource);
|
||||
RValue initValue = (initializer == null) ? null : (RValue) visit(initializer);
|
||||
initValue = Initializers.constantify(initValue, new Initializers.ValueTypeSpec(effectiveType, effectiveArraySpec), program, statementSource);
|
||||
boolean isPermanent = ScopeRef.ROOT.equals(variable.getScope().getRef()) || variable.isPermanent();
|
||||
if(variable.isKindConstant() || (isPermanent && variable.isKindLoadStore() && Variable.MemoryArea.MAIN_MEMORY.equals(variable.getMemoryArea()) && initValue instanceof ConstantValue && !isStructMember && variable.getRegister() == null)) {
|
||||
// Set initial value
|
||||
ConstantValue constInitValue = getConstInitValue(initValue, initializer, statementSource);
|
||||
variable.setInitValue(constInitValue);
|
||||
// Add comments to constant
|
||||
variable.setComments(ensureUnusedComments(declComments));
|
||||
} else if(!variable.isKindConstant() && !isStructMember) {
|
||||
Statement initStmt = new StatementAssignment(variable.getVariableRef(), initValue, true, statementSource, ensureUnusedComments(declComments));
|
||||
sequence.addStatement(initStmt);
|
||||
}
|
||||
if(initializer != null)
|
||||
PrePostModifierHandler.addPostModifiers(this, initializer, statementSource);
|
||||
}
|
||||
if(initializer != null)
|
||||
PrePostModifierHandler.addPostModifiers(this, initializer, statementSource);
|
||||
} catch(CompileError e) {
|
||||
throw new CompileError(e.getMessage(), declSource);
|
||||
}
|
||||
|
12
src/main/kc/include/atan2.h
Normal file
12
src/main/kc/include/atan2.h
Normal file
@ -0,0 +1,12 @@
|
||||
// Find atan2(x, y) using the CORDIC method
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
|
||||
// Find the atan2(x, y) - which is the angle of the line from (0,0) to (x,y)
|
||||
// Finding the angle requires a binary search using CORDIC_ITERATIONS_16
|
||||
// Returns the angle in hex-degrees (0=0, 0x8000=PI, 0x10000=2*PI)
|
||||
word atan2_16(signed word x, signed word y);
|
||||
|
||||
// Find the atan2(x, y) - which is the angle of the line from (0,0) to (x,y)
|
||||
// Finding the angle requires a binary search using CORDIC_ITERATIONS_8
|
||||
// Returns the angle in hex-degrees (0=0, 0x80=PI, 0x100=2*PI)
|
||||
byte atan2_8(signed byte x, signed byte y);
|
128
src/main/kc/include/basic-floats.h
Normal file
128
src/main/kc/include/basic-floats.h
Normal file
@ -0,0 +1,128 @@
|
||||
// Library wrapping the BASIC floating point functions
|
||||
// See https://www.c64-wiki.com/wiki/Floating_point_arithmetic
|
||||
// See http://www.pagetable.com/c64rom/c64rom_sc.html
|
||||
|
||||
// Prepare MEM pointers for operations using MEM
|
||||
inline void prepareMEM(unsigned int mem);
|
||||
|
||||
// FAC = word
|
||||
// Set the FAC (floating point accumulator) to the integer value of a 16bit word
|
||||
void setFAC(unsigned int w);
|
||||
|
||||
// word = FAC
|
||||
// Get the value of the FAC (floating point accumulator) as an integer 16bit word
|
||||
// Destroys the value in the FAC in the process
|
||||
unsigned int getFAC();
|
||||
|
||||
// ARG = FAC
|
||||
// Set the ARG (floating point argument) to the value of the FAC (floating point accumulator)
|
||||
void setARGtoFAC();
|
||||
|
||||
// FAC = ARG
|
||||
// Set the FAC (floating point accumulator) to the value of the ARG (floating point argument)
|
||||
void setFACtoARG();
|
||||
|
||||
// MEM = FAC
|
||||
// Stores the value of the FAC to memory
|
||||
// Stores 5 bytes (means it is necessary to allocate 5 bytes to avoid clobbering other data using eg. byte[] mem = {0, 0, 0, 0, 0};)
|
||||
void setMEMtoFAC(char* mem);
|
||||
|
||||
// FAC = MEM
|
||||
// Set the FAC to value from MEM (float saved in memory)
|
||||
// Reads 5 bytes
|
||||
void setFACtoMEM(char* mem);
|
||||
|
||||
// FAC = PI/2
|
||||
// Set the FAC to PI/2
|
||||
// Reads 5 bytes from the BASIC ROM
|
||||
void setFACtoPIhalf();
|
||||
|
||||
// FAC = 2*PI
|
||||
// Set the FAC to 2*PI
|
||||
// Reads 5 bytes from the BASIC ROM
|
||||
void setFACto2PI();
|
||||
|
||||
// ARG = MEM
|
||||
// Load the ARG from memory
|
||||
// Reads 5 bytes
|
||||
void setARGtoMEM(char* mem);
|
||||
|
||||
// FAC = MEM+FAC
|
||||
// Set FAC to MEM (float saved in memory) plus FAC (float accumulator)
|
||||
// Reads 5 bytes from memory
|
||||
void addMEMtoFAC(char* mem);
|
||||
|
||||
// FAC = ARG+FAC
|
||||
// Add ARG (floating point argument) to FAC (floating point accumulator)
|
||||
void addARGtoFAC();
|
||||
|
||||
// FAC = MEM-FAC
|
||||
// Set FAC to MEM (float saved in memory) minus FAC (float accumulator)
|
||||
// Reads 5 bytes from memory
|
||||
void subFACfromMEM(char* mem);
|
||||
|
||||
// FAC = ARG-FAC
|
||||
// Set FAC to ARG minus FAC
|
||||
void subFACfromARG();
|
||||
|
||||
// FAC = MEM/FAC
|
||||
// Set FAC to MEM (float saved in memory) divided by FAC (float accumulator)
|
||||
// Reads 5 bytes from memory
|
||||
void divMEMbyFAC(char* mem);
|
||||
|
||||
// FAC = MEM*FAC
|
||||
// Set FAC to MEM (float saved in memory) multiplied by FAC (float accumulator)
|
||||
// Reads 5 bytes from memory
|
||||
void mulFACbyMEM(char* mem);
|
||||
|
||||
// FAC = MEM^FAC
|
||||
// Set FAC to MEM (float saved in memory) raised to power of FAC (float accumulator)
|
||||
// Reads 5 bytes from memory
|
||||
void pwrMEMbyFAC(char* mem);
|
||||
|
||||
// FAC = int(FAC)
|
||||
// Set FAC to integer part of the FAC - int(FAC)
|
||||
// The integer part is defined as the next lower integer - like java floor()
|
||||
void intFAC();
|
||||
|
||||
// FAC = sin(FAC)
|
||||
// Set FAC to sinus of the FAC - sin(FAC)
|
||||
// Sinus is calculated on radians (0-2*PI)
|
||||
void sinFAC();
|
||||
|
||||
// FAC = cos(FAC)
|
||||
// Set FAC to cosinus of the FAC - cos(FAC)
|
||||
// Cosinus is calculated on radians (0-2*PI)
|
||||
void cosFAC();
|
||||
|
||||
// FAC = tan(FAC)
|
||||
// Set FAC to the tangens of FAC - tan(FAC)
|
||||
// Tangens is calculated on radians (0-2*PI)
|
||||
void tanFAC();
|
||||
|
||||
// FAC = atn(FAC)
|
||||
// Set FAC to the arc tangens of FAC - atn(FAC)
|
||||
// Arc Tangens is calculated on radians (0-2*PI)
|
||||
void atnFAC();
|
||||
|
||||
// FAC = sqr(FAC)
|
||||
// Set FAC to the square root of FAC - sqr(FAC)
|
||||
void sqrFAC();
|
||||
|
||||
// FAC = exp(FAC)
|
||||
// Set FAC to the exponential function of FAC - exp(FAC)
|
||||
// Exp is based on the natural logarithm e=2.71828183
|
||||
void expFAC();
|
||||
|
||||
// FAC = log(FAC)
|
||||
// Set FAC to the logarithm of FAC - log(FAC)
|
||||
// Log is based on the natural logarithm e=2.71828183
|
||||
void logFAC();
|
||||
|
||||
// FAC = FAC/10
|
||||
// Set FAC to FAC divided by 10
|
||||
void divFACby10();
|
||||
|
||||
// FAC = FAC*10
|
||||
// Set FAC to FAC multiplied by 10
|
||||
void mulFACby10();
|
13
src/main/kc/include/bitmap-draw.h
Normal file
13
src/main/kc/include/bitmap-draw.h
Normal file
@ -0,0 +1,13 @@
|
||||
// Plot and line drawing routines for HIRES bitmaps
|
||||
// Currently it can only plot on the first 256 x-positions.
|
||||
|
||||
// Initialize the bitmap plotter tables for a specific bitmap
|
||||
void bitmap_init(byte* bitmap);
|
||||
|
||||
// Clear all graphics on the bitmap
|
||||
void bitmap_clear();
|
||||
|
||||
void bitmap_plot(byte x, byte y);
|
||||
|
||||
// Draw a line on the bitmap
|
||||
void bitmap_line(byte x0, byte x1, byte y0, byte y1);
|
23
src/main/kc/include/bitmap2.h
Normal file
23
src/main/kc/include/bitmap2.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Simple single-color (320x200) bitmap routines
|
||||
#include <string.h>
|
||||
|
||||
// Initialize bitmap plotting tables
|
||||
void bitmap_init(byte* gfx, byte* screen);
|
||||
|
||||
// Clear all graphics on the bitmap
|
||||
// bgcol - the background color to fill the screen with
|
||||
// fgcol - the foreground color to fill the screen with
|
||||
void bitmap_clear(byte bgcol, byte fgcol);
|
||||
|
||||
// Plot a single dot in the bitmap
|
||||
void bitmap_plot(word x, byte y);
|
||||
|
||||
// Draw a line on the bitmap using bresenhams algorithm
|
||||
void bitmap_line(word x1, word y1, word x2, word y2);
|
||||
|
||||
// Get the absolute value of a 16-bit unsigned number treated as a signed number.
|
||||
word abs_u16(word w);
|
||||
|
||||
// Get the sign of a 16-bit unsigned number treated as a signed number.
|
||||
// Returns unsigned -1 if the number is
|
||||
word sgn_u16(word w);
|
224
src/main/kc/include/c64.h
Normal file
224
src/main/kc/include/c64.h
Normal file
@ -0,0 +1,224 @@
|
||||
// Commodore 64 Registers and Constants
|
||||
|
||||
// Processor port data direction register
|
||||
char* const PROCPORT_DDR = $00;
|
||||
// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
|
||||
const char PROCPORT_DDR_MEMORY_MASK = %00000111;
|
||||
|
||||
// Processor Port Register controlling RAM/ROM configuration and the datasette
|
||||
char* const PROCPORT = $01;
|
||||
// RAM in all three areas $A000, $D000, $E000
|
||||
const char PROCPORT_RAM_ALL = %00000000;
|
||||
// RAM in $A000, $E000 I/O in $D000
|
||||
const char PROCPORT_RAM_IO = %00000101;
|
||||
// RAM in $A000, $E000 CHAR ROM in $D000
|
||||
const char PROCPORT_RAM_CHARROM = %00000001;
|
||||
// RAM in $A000, I/O in $D000, KERNEL in $E000
|
||||
const char PROCPORT_KERNEL_IO = %00000110;
|
||||
// BASIC in $A000, I/O in $D000, KERNEL in $E000
|
||||
const char PROCPORT_BASIC_KERNEL_IO = %00000111;
|
||||
|
||||
// The address of the CHARGEN character set
|
||||
char* const CHARGEN = $d000;
|
||||
|
||||
// Positions of the border (in sprite positions)
|
||||
const char BORDER_XPOS_LEFT=24;
|
||||
const unsigned int BORDER_XPOS_RIGHT=344;
|
||||
const char BORDER_YPOS_TOP=50;
|
||||
const char BORDER_YPOS_BOTTOM=250;
|
||||
|
||||
// The offset of the sprite pointers from the screen start address
|
||||
const unsigned int SPRITE_PTRS = $3f8;
|
||||
|
||||
char* const SPRITES_XPOS = $d000;
|
||||
char* const SPRITES_YPOS = $d001;
|
||||
char* const SPRITES_XMSB = $d010;
|
||||
char* const RASTER = $d012;
|
||||
char* const SPRITES_ENABLE = $d015;
|
||||
char* const SPRITES_EXPAND_Y = $d017;
|
||||
char* const SPRITES_PRIORITY = $d01b;
|
||||
char* const SPRITES_MC = $d01c;
|
||||
char* const SPRITES_EXPAND_X = $d01d;
|
||||
char* const BORDERCOL = $d020;
|
||||
char* const BGCOL = $d021;
|
||||
char* const BGCOL1 = $d021;
|
||||
char* const BGCOL2 = $d022;
|
||||
char* const BGCOL3 = $d023;
|
||||
char* const BGCOL4 = $d024;
|
||||
char* const SPRITES_MC1 = $d025;
|
||||
char* const SPRITES_MC2 = $d026;
|
||||
char* const SPRITES_COLS = $d027;
|
||||
|
||||
char* const VIC_CONTROL = $d011;
|
||||
char* const D011 = $d011;
|
||||
const char VIC_RST8 = %10000000;
|
||||
const char VIC_ECM = %01000000;
|
||||
const char VIC_BMM = %00100000;
|
||||
const char VIC_DEN = %00010000;
|
||||
const char VIC_RSEL = %00001000;
|
||||
|
||||
char* const VIC_CONTROL2 = $d016;
|
||||
char* const D016 = $d016;
|
||||
const char VIC_MCM = %00010000;
|
||||
const char VIC_CSEL = %00001000;
|
||||
|
||||
char* const D018 = $d018;
|
||||
char* const VIC_MEMORY = $d018;
|
||||
|
||||
char* const LIGHTPEN_X = $d013;
|
||||
char* const LIGHTPEN_Y = $d014;
|
||||
|
||||
// VIC II IRQ Status Register
|
||||
char* const IRQ_STATUS = $d019;
|
||||
// VIC II IRQ Enable Register
|
||||
char* const IRQ_ENABLE = $d01a;
|
||||
// Bits for the IRQ Status/Enable Registers
|
||||
const char IRQ_RASTER = %00000001;
|
||||
const char IRQ_COLLISION_BG = %00000010;
|
||||
const char IRQ_COLLISION_SPRITE = %00000100;
|
||||
const char IRQ_LIGHTPEN = %00001000;
|
||||
|
||||
// Color Ram
|
||||
char* const COLS = $d800;
|
||||
|
||||
// CIA#1 Port A: keyboard matrix columns and joystick #2
|
||||
char* const CIA1_PORT_A = $dc00;
|
||||
// CIA#1 Port B: keyboard matrix rows and joystick #1.
|
||||
char* const CIA1_PORT_B = $dc01;
|
||||
// CIA #1 Port A data direction register.
|
||||
char* const CIA1_PORT_A_DDR = $dc02;
|
||||
// CIA #1 Port B data direction register.
|
||||
char* const CIA1_PORT_B_DDR = $dc03;
|
||||
// CIA #1 Timer A Value
|
||||
unsigned int* const CIA1_TIMER_A = $dc04;
|
||||
// CIA #1 Timer B Value
|
||||
unsigned int* const CIA1_TIMER_B = $dc06;
|
||||
// CIA #1 Time-of-day real-time-clock tenth seconds (BCD)
|
||||
char* const CIA1_TOD_10THS = $dc08;
|
||||
// CIA #1 Time-of-day real-time-clock seconds (BCD)
|
||||
char* const CIA1_TOD_SEC = $dc09;
|
||||
// CIA #1 Time-of-day real-time-clock minutes (BCD)
|
||||
char* const CIA1_TOD_MIN = $dc0a;
|
||||
// CIA #1 Time-of-day real-time-clock hours (BCD)
|
||||
char* const CIA1_TOD_HOURS = $dc0b;
|
||||
// CIA #1 Serial Shift Register
|
||||
char* const CIA1_SERIAL_SHIFT_OUT = $dc0c;
|
||||
// CIA#1 Interrupt Status & Control Register
|
||||
char* const CIA1_INTERRUPT = $dc0d;
|
||||
// CIA#1 Timer A Control Register
|
||||
char* const CIA1_TIMER_A_CONTROL = $dc0e;
|
||||
// CIA#1 Timer B Control Register
|
||||
char* const CIA1_TIMER_B_CONTROL = $dc0f;
|
||||
|
||||
// CIA#2 Port A: Serial bus, RS-232, VIC memory bank
|
||||
char* const CIA2_PORT_A = $dd00;
|
||||
// CIA#2 Port B: RS-232
|
||||
char* const CIA2_PORT_B = $dd01;
|
||||
// CIA #2 Port A data direction register.
|
||||
char* const CIA2_PORT_A_DDR = $dd02;
|
||||
// CIA #2 Port B data direction register.
|
||||
char* const CIA2_PORT_B_DDR = $dd03;
|
||||
// CIA #2 Timer A+B Value (32-bit)
|
||||
unsigned long* const CIA2_TIMER_AB = $dd04;
|
||||
// CIA #2 Timer A Value (16-bit)
|
||||
unsigned int* const CIA2_TIMER_A = $dd04;
|
||||
// CIA #2 Timer B Value (16-bit)
|
||||
unsigned int* const CIA2_TIMER_B = $dd06;
|
||||
// CIA #2 Time-of-day real-time-clock tenth seconds (BCD)
|
||||
char* const CIA2_TOD_10THS = $dd08;
|
||||
// CIA #2 Time-of-day real-time-clock seconds (BCD)
|
||||
char* const CIA2_TOD_SEC = $dd09;
|
||||
// CIA #2 Time-of-day real-time-clock minutes (BCD)
|
||||
char* const CIA2_TOD_MIN = $dd0a;
|
||||
// CIA #2 Time-of-day real-time-clock hours (BCD)
|
||||
char* const CIA2_TOD_HOURS = $dd0b;
|
||||
// CIA #2 Serial Shift Register
|
||||
char* const CIA2_SERIAL_SHIFT_OUT = $dd0c;
|
||||
// CIA #2 Interrupt Status & Control Register
|
||||
char* const CIA2_INTERRUPT = $dd0d;
|
||||
// CIA #2 Timer A Control Register
|
||||
char* const CIA2_TIMER_A_CONTROL = $dd0e;
|
||||
// CIA #2 Timer B Control Register
|
||||
char* const CIA2_TIMER_B_CONTROL = $dd0f;
|
||||
|
||||
// Value that disables all CIA interrupts when stored to the CIA Interrupt registers
|
||||
const char CIA_INTERRUPT_CLEAR = $7f;
|
||||
|
||||
// Timer Control - Start/stop timer (0:stop, 1: start)
|
||||
const char CIA_TIMER_CONTROL_STOP = 0b00000000;
|
||||
// Timer Control - Start/stop timer (0:stop, 1: start)
|
||||
const char CIA_TIMER_CONTROL_START = 0b00000001;
|
||||
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
|
||||
const char CIA_TIMER_CONTROL_CONTINUOUS = 0b00000000;
|
||||
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
|
||||
const char CIA_TIMER_CONTROL_ONESHOT = 0b00001000;
|
||||
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
|
||||
const char CIA_TIMER_CONTROL_A_COUNT_CYCLES = 0b00000000;
|
||||
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
|
||||
const char CIA_TIMER_CONTROL_A_COUNT_CNT = 0b00100000;
|
||||
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
|
||||
const char CIA_TIMER_CONTROL_A_SERIAL_IN = 0b00000000;
|
||||
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
|
||||
const char CIA_TIMER_CONTROL_A_SERIAL_OUT = 0b01000000;
|
||||
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
|
||||
const char CIA_TIMER_CONTROL_A_TOD_60HZ = 0b00000000;
|
||||
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
|
||||
const char CIA_TIMER_CONTROL_A_TOD_50HZ = 0b10000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const char CIA_TIMER_CONTROL_B_COUNT_CYCLES = 0b00000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const char CIA_TIMER_CONTROL_B_COUNT_CNT = 0b00100000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const char CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A = 0b01000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const char CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A_CNT = 0b01100000;
|
||||
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
|
||||
const char CIA_TIMER_CONTROL_B_TOD_CLOCK_SET = 0b00000000;
|
||||
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
|
||||
const char CIA_TIMER_CONTROL_B_TOD_ALARM_SET = 0b10000000;
|
||||
|
||||
// The vector used when the KERNAL serves IRQ interrupts
|
||||
void()** const KERNEL_IRQ = $0314;
|
||||
// The vector used when the KERNAL serves NMI interrupts
|
||||
void()** const KERNEL_NMI = $0318;
|
||||
|
||||
// The vector used when the HARDWARE serves IRQ interrupts
|
||||
void()** const HARDWARE_IRQ = $fffe;
|
||||
|
||||
// The SID volume
|
||||
char* const SID_VOLUME = $d418;
|
||||
|
||||
|
||||
// The colors of the C64
|
||||
const char BLACK = $0;
|
||||
const char WHITE = $1;
|
||||
const char RED = $2;
|
||||
const char CYAN = $3;
|
||||
const char PURPLE = $4;
|
||||
const char GREEN = $5;
|
||||
const char BLUE = $6;
|
||||
const char YELLOW = $7;
|
||||
const char ORANGE = $8;
|
||||
const char BROWN = $9;
|
||||
const char PINK = $a;
|
||||
const char DARK_GREY= $b;
|
||||
const char GREY = $c;
|
||||
const char LIGHT_GREEN = $d;
|
||||
const char LIGHT_BLUE = $e;
|
||||
const char LIGHT_GREY = $f;
|
||||
|
||||
// Get the value to store into D018 to display a specific screen and charset/bitmap
|
||||
// Optimized for ASM from (char)((((unsigned int)screen&0x3fff)/$40)|(((unsigned int)charset&$3fff)/$400));
|
||||
inline char toD018(char* screen, char* gfx);
|
||||
|
||||
// Get the value to store into DD00 (CIA 2 port A) to choose a specific VIC bank
|
||||
// Optimized for ASM from %00000011 ^ (char)((unsigned int)gfx/$4000)
|
||||
inline char toDd00(char* gfx);
|
||||
|
||||
// Get the sprite pointer for a sprite.
|
||||
// The sprite pointer is the index of the sprite within the graphics bank and equal to the sprite (char)(sprite_addr/64)
|
||||
// The sprite pointers are stored SCREEN+$3f8+sprite_id to set the pointer of each sprite
|
||||
inline char toSpritePtr(char* sprite);
|
||||
|
||||
// Select a specific VIC graphics bank by setting the CIA 2 port A ($dd00) as needed
|
||||
inline void vicSelectGfxBank(char* gfx);
|
@ -4,7 +4,8 @@
|
||||
// (J) https://www.c64-wiki.com/wiki/C64DTV_Programming_Guide
|
||||
// (H) http://dtvhacking.cbm8bit.com/dtv_wiki/images/d/d9/Dtv_registers_full.txt
|
||||
|
||||
#include <c64.c>
|
||||
#include <c64dtv.h>
|
||||
#include <c64.h>
|
||||
|
||||
// Feature enables or disables the extra C64 DTV features
|
||||
byte* const DTV_FEATURE = $d03f;
|
||||
@ -63,19 +64,7 @@ byte* const DTV_GRAPHICS_HICOL_BANK = $d03e;
|
||||
// Set the memory pointed to by CPU BANK 1 SEGMENT ($4000-$7fff)
|
||||
// This sets which actual memory is addressed when the CPU reads/writes to $4000-$7fff
|
||||
// The actual memory addressed will be $4000*cpuSegmentIdx
|
||||
void dtvSetCpuBankSegment1(byte cpuBankIdx) {
|
||||
// Move CPU BANK 1 SEGMENT ($4000-$7fff)
|
||||
byte* cpuBank = $ff;
|
||||
*cpuBank = cpuBankIdx;
|
||||
asm {
|
||||
// SAC $dd - A register points to 13 BANK 1 segment
|
||||
.byte $32, $dd
|
||||
// LDA $ff - Set CPU BANK 1 SEGMENT ($4000-$7fff) to ($ff)*$4000
|
||||
lda $ff
|
||||
// SAC $00 - A register points to 0 ACCUMULATOR
|
||||
.byte $32, $00
|
||||
}
|
||||
}
|
||||
void dtvSetCpuBankSegment1(byte cpuBankIdx);
|
||||
|
||||
// Blitter Source A Start
|
||||
byte* const DTV_BLITTER_SRCA_LO = $d320;
|
66
src/main/kc/include/division.h
Normal file
66
src/main/kc/include/division.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Simple binary division implementation
|
||||
// Follows the C99 standard by truncating toward zero on negative results.
|
||||
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf section 6.5.5
|
||||
|
||||
// Remainder after signed 8 bit division
|
||||
extern char rem8u;
|
||||
|
||||
// Performs division on two 8 bit unsigned bytes
|
||||
// Returns dividend/divisor.
|
||||
// The remainder will be set into the global variable rem8u
|
||||
// Implemented using simple binary division
|
||||
char div8u(char dividend, char divisor);
|
||||
|
||||
// Performs division on two 8 bit unsigned bytes and an initial remainder
|
||||
// Returns dividend/divisor.
|
||||
// The final remainder will be set into the global variable rem8u
|
||||
// Implemented using simple binary division
|
||||
char divr8u(char dividend, char divisor, char rem);
|
||||
|
||||
// Remainder after unsigned 16-bit division
|
||||
extern unsigned int rem16u;
|
||||
|
||||
// Performs division on two 16 bit unsigned words and an initial remainder
|
||||
// Returns the quotient dividend/divisor.
|
||||
// The final remainder will be set into the global variable rem16u
|
||||
// Implemented using simple binary division
|
||||
unsigned int divr16u(unsigned int dividend, unsigned int divisor, unsigned int rem);
|
||||
|
||||
// Performs division on two 16 bit unsigned words
|
||||
// Returns the quotient dividend/divisor.
|
||||
// The remainder will be set into the global variable rem16u
|
||||
// Implemented using simple binary division
|
||||
unsigned int div16u(unsigned int dividend, unsigned int divisor);
|
||||
|
||||
// Divide unsigned 32-bit dword dividend with a 16-bit word divisor
|
||||
// The 16-bit word remainder can be found in rem16u after the division
|
||||
unsigned long div32u16u(unsigned long dividend, unsigned int divisor);
|
||||
|
||||
// Remainder after signed 8 bit division
|
||||
extern signed char rem8s;
|
||||
|
||||
// Perform division on two signed 8-bit numbers
|
||||
// Returns dividend/divisor.
|
||||
// The remainder will be set into the global variable rem8s.
|
||||
// Implemented using simple binary division
|
||||
// Follows the C99 standard by truncating toward zero on negative results.
|
||||
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf section 6.5.5
|
||||
signed char div8s(signed char dividend, signed char divisor);
|
||||
|
||||
// Remainder after signed 16 bit division
|
||||
extern int rem16s;
|
||||
|
||||
// Perform division on two signed 16-bit numbers with an initial remainder.
|
||||
// Returns dividend/divisor. The remainder will be set into the global variable rem16s.
|
||||
// Implemented using simple binary division
|
||||
// Follows the C99 standard by truncating toward zero on negative results.
|
||||
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf section 6.5.5
|
||||
int divr16s(int dividend, int divisor, int rem);
|
||||
|
||||
// Perform division on two signed 16-bit numbers
|
||||
// Returns dividend/divisor.
|
||||
// The remainder will be set into the global variable rem16s.
|
||||
// Implemented using simple binary division
|
||||
// Follows the C99 standard by truncating toward zero on negative results.
|
||||
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf section 6.5.5
|
||||
int div16s(int dividend, int divisor);
|
34
src/main/kc/include/fastmultiply.h
Normal file
34
src/main/kc/include/fastmultiply.h
Normal file
@ -0,0 +1,34 @@
|
||||
// Library Implementation of the Seriously Fast Multiplication
|
||||
// See http://codebase64.org/doku.php?id=base:seriously_fast_multiplication
|
||||
// Utilizes the fact that a*b = ((a+b)/2)^2 - ((a-b)/2)^2
|
||||
|
||||
// Initialize the mulf_sqr multiplication tables with f(x)=int(x*x/4)
|
||||
void mulf_init();
|
||||
|
||||
// Prepare for fast multiply with an unsigned byte to a word result
|
||||
void mulf8u_prepare(byte a);
|
||||
|
||||
// Calculate fast multiply with a prepared unsigned byte to a word result
|
||||
// The prepared number is set by calling mulf8u_prepare(byte a)
|
||||
word mulf8u_prepared(byte b);
|
||||
|
||||
// Fast multiply two unsigned bytes to a word result
|
||||
word mulf8u(byte a, byte b);
|
||||
|
||||
// Prepare for fast multiply with an signed byte to a word result
|
||||
inline void mulf8s_prepare(signed byte a);
|
||||
|
||||
// Calculate fast multiply with a prepared unsigned byte to a word result
|
||||
// The prepared number is set by calling mulf8s_prepare(byte a)
|
||||
signed word mulf8s_prepared(signed byte b);
|
||||
|
||||
// Fast multiply two signed bytes to a word result
|
||||
signed word mulf8s(signed byte a, signed byte b);
|
||||
|
||||
// Fast multiply two unsigned words to a double word result
|
||||
// Done in assembler to utilize fast addition A+X
|
||||
dword mulf16u(word a, word b);
|
||||
|
||||
// Fast multiply two signed words to a signed double word result
|
||||
// Fixes offsets introduced by using unsigned multiplication
|
||||
signed dword mulf16s(signed word a, signed word b);
|
136
src/main/kc/include/keyboard.h
Normal file
136
src/main/kc/include/keyboard.h
Normal file
@ -0,0 +1,136 @@
|
||||
// Simple Keyboard Input Library
|
||||
// C64 Keyboard Matrix Reference - from http://codebase64.org/doku.php?id=base:reading_the_keyboard
|
||||
// Keyboard Codes are %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
|
||||
// +----+----------------------+-------------------------------------------------------------------------------------------------------+
|
||||
// | | Write | Read $dc01 (C64 screen code in parenthesis): |
|
||||
// |row:| $dc00: row bits +------------+------------+------------+------------+------------+------------+------------+------------+
|
||||
// | | | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 |
|
||||
// +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|
||||
// |0. | #%11111110 (254/$fe) | DOWN ($ )| F5 ($ )| F3 ($ )| F1 ($ )| F7 ($ )| RIGHT ($ )| RETURN($ )|DELETE ($ )|
|
||||
// |1. | #%11111101 (253/$fd) |LEFT-SH($ )| e ($05)| s ($13)| z ($1a)| 4 ($34)| a ($01)| w ($17)| 3 ($33)|
|
||||
// |2. | #%11111011 (251/$fb) | x ($18)| t ($14)| f ($06)| c ($03)| 6 ($36)| d ($04)| r ($12)| 5 ($35)|
|
||||
// |3. | #%11110111 (247/$f7) | v ($16)| u ($15)| h ($08)| b ($02)| 8 ($38)| g ($07)| y ($19)| 7 ($37)|
|
||||
// |4. | #%11101111 (239/$ef) | n ($0e)| o ($0f)| k ($0b)| m ($0d)| 0 ($30)| j ($0a)| i ($09)| 9 ($39)|
|
||||
// |5. | #%11011111 (223/$df) | , ($2c)| @ ($00)| : ($3a)| . ($2e)| - ($2d)| l ($0c)| p ($10)| + ($2b)|
|
||||
// |6. | #%10111111 (191/$bf) | / ($2f)| ^ ($1e)| = ($3d)|RGHT-SH($ )| HOME ($ )| ; ($3b)| * ($2a)| £ ($1c)|
|
||||
// |7. | #%01111111 (127/$7f) | STOP ($ )| q ($11)|COMMODR($ )| SPACE ($20)| 2 ($32)|CONTROL($ )| <- ($1f)| 1 ($31)|
|
||||
// +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|
||||
|
||||
// Keyboard Codes for all 63 keys.
|
||||
// Keyboard Codes are %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7).
|
||||
// See C64 Keyboard Matrix Reference http://codebase64.org/doku.php?id=base:reading_the_keyboard
|
||||
const byte KEY_DEL = $00;
|
||||
const byte KEY_RETURN = $01;
|
||||
const byte KEY_CRSR_RIGHT = $02;
|
||||
const byte KEY_F7 = $03;
|
||||
const byte KEY_F1 = $04;
|
||||
const byte KEY_F3 = $05;
|
||||
const byte KEY_F5 = $06;
|
||||
const byte KEY_CRSR_DOWN = $07;
|
||||
const byte KEY_3 = $08;
|
||||
const byte KEY_W = $09;
|
||||
const byte KEY_A = $0a;
|
||||
const byte KEY_4 = $0b;
|
||||
const byte KEY_Z = $0c;
|
||||
const byte KEY_S = $0d;
|
||||
const byte KEY_E = $0e;
|
||||
const byte KEY_LSHIFT = $0f;
|
||||
const byte KEY_5 = $10;
|
||||
const byte KEY_R = $11;
|
||||
const byte KEY_D = $12;
|
||||
const byte KEY_6 = $13;
|
||||
const byte KEY_C = $14;
|
||||
const byte KEY_F = $15;
|
||||
const byte KEY_T = $16;
|
||||
const byte KEY_X = $17;
|
||||
const byte KEY_7 = $18;
|
||||
const byte KEY_Y = $19;
|
||||
const byte KEY_G = $1a;
|
||||
const byte KEY_8 = $1b;
|
||||
const byte KEY_B = $1c;
|
||||
const byte KEY_H = $1d;
|
||||
const byte KEY_U = $1e;
|
||||
const byte KEY_V = $1f;
|
||||
const byte KEY_9 = $20;
|
||||
const byte KEY_I = $21;
|
||||
const byte KEY_J = $22;
|
||||
const byte KEY_0 = $23;
|
||||
const byte KEY_M = $24;
|
||||
const byte KEY_K = $25;
|
||||
const byte KEY_O = $26;
|
||||
const byte KEY_N = $27;
|
||||
const byte KEY_PLUS = $28;
|
||||
const byte KEY_P = $29;
|
||||
const byte KEY_L = $2a;
|
||||
const byte KEY_MINUS = $2b;
|
||||
const byte KEY_DOT = $2c;
|
||||
const byte KEY_COLON = $2d;
|
||||
const byte KEY_AT = $2e;
|
||||
const byte KEY_COMMA = $2f;
|
||||
const byte KEY_POUND = $30;
|
||||
const byte KEY_ASTERISK = $31;
|
||||
const byte KEY_SEMICOLON = $32;
|
||||
const byte KEY_HOME = $33;
|
||||
const byte KEY_RSHIFT = $34;
|
||||
const byte KEY_EQUALS = $35;
|
||||
const byte KEY_ARROW_UP = $36;
|
||||
const byte KEY_SLASH = $37;
|
||||
const byte KEY_1 = $38;
|
||||
const byte KEY_ARROW_LEFT = $39;
|
||||
const byte KEY_CTRL = $3a;
|
||||
const byte KEY_2 = $3b;
|
||||
const byte KEY_SPACE = $3c;
|
||||
const byte KEY_COMMODORE = $3d;
|
||||
const byte KEY_Q = $3e;
|
||||
const byte KEY_RUNSTOP = $3f;
|
||||
|
||||
// Initialize keyboard reading by setting CIA#$ Data Direction Registers
|
||||
void keyboard_init();
|
||||
|
||||
// Read a single row of the keyboard matrix
|
||||
// The row ID (0-7) of the keyboard matrix row to read. See the C64 key matrix for row IDs.
|
||||
// Returns the keys pressed on the row as bits according to the C64 key matrix.
|
||||
// Notice: If the C64 normal interrupt is still running it will occasionally interrupt right between the read & write
|
||||
// leading to erroneous readings. You must disable kill the normal interrupt or sei/cli around calls to the keyboard matrix reader.
|
||||
byte keyboard_matrix_read(byte rowid);
|
||||
|
||||
// Determines whether a specific key is currently pressed by accessing the matrix directly
|
||||
// The key is a keyboard code defined from the keyboard matrix by %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7)
|
||||
// All keys exist as as KEY_XXX constants.
|
||||
// Returns zero if the key is not pressed and a non-zero value if the key is currently pressed
|
||||
byte keyboard_key_pressed(byte key);
|
||||
|
||||
// Get the keycode corresponding to a specific screen code character
|
||||
// ch is the character to get the key code for ($00-$3f)
|
||||
// Returns the key code corresponding to the passed character. Only characters with a non-shifted key are handled.
|
||||
// If there is no non-shifted key representing the char $3f is returned (representing RUN/STOP) .
|
||||
byte keyboard_get_keycode(byte ch);
|
||||
|
||||
// Current keyboard modifiers (left shift, right shift, ctrl, commodore)
|
||||
extern byte keyboard_modifiers;
|
||||
// Left shift is pressed
|
||||
extern const byte KEY_MODIFIER_LSHIFT;
|
||||
// Right shift is pressed
|
||||
extern const byte KEY_MODIFIER_RSHIFT;
|
||||
// CTRL is pressed
|
||||
extern const byte KEY_MODIFIER_CTRL;
|
||||
// Commodore is pressed
|
||||
extern const byte KEY_MODIFIER_COMMODORE;
|
||||
// Any shift is pressed
|
||||
extern const byte KEY_MODIFIER_SHIFT;
|
||||
|
||||
// Scans the entire matrix to determine which keys have been pressed/depressed.
|
||||
// Generates keyboard events into the event buffer. Events can be read using keyboard_event_get().
|
||||
// Handles debounce and only generates events when the status of a key changes.
|
||||
// Also stores current status of modifiers in keyboard_modifiers.
|
||||
void keyboard_event_scan();
|
||||
|
||||
// Determine if a specific key is currently pressed based on the last keyboard_event_scan()
|
||||
// Returns 0 is not pressed and non-0 if pressed
|
||||
byte keyboard_event_pressed(byte keycode);
|
||||
|
||||
// Get the next event from the keyboard event buffer.
|
||||
// Returns $ff if there is no event waiting. As all events are <$7f it is enough to examine bit 7 when determining if there is any event to process.
|
||||
// The buffer is filled by keyboard_event_scan()
|
||||
byte keyboard_event_get();
|
||||
|
66
src/main/kc/include/multiplexer.h
Normal file
66
src/main/kc/include/multiplexer.h
Normal file
@ -0,0 +1,66 @@
|
||||
// A flexible sprite multiplexer routine for 32 sprites.
|
||||
// Usage:
|
||||
// - Once:
|
||||
// - plexInit(screen): Initialize the data structures and set the screen address
|
||||
// Each frame:
|
||||
// - Set x-pos, y-pos and pointer in PLEX_XPOS[id], PLEX_YPOS[id], PLEX_PTR[id]
|
||||
// - plexSort() Sorts the sprites according to y-positions and prepares for showing them. This uses an insertion sort that is quite fast when the relative order of the sprites does not change very much.
|
||||
// - plexShowSprite() Shows the next sprite by copying values from PLEX_XXX[] to an actual sprite. Actual sprites are used round-robin. This should be called once for each of the 24 virtual sprites.
|
||||
// - plexFreeNextYpos() Returns the Y-position where the next sprite is available to be shown (ie. the next pos where the next sprite is no longer in use showing something else).
|
||||
// - plexShowNextYpos() Returns the Y-position of the next sprite to show.
|
||||
//
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
|
||||
|
||||
#include <c64.h>
|
||||
|
||||
// The number of sprites in the multiplexer
|
||||
extern const char PLEX_COUNT;
|
||||
|
||||
// The x-positions of the multiplexer sprites (0x000-0x1ff)
|
||||
extern unsigned int PLEX_XPOS[PLEX_COUNT];
|
||||
|
||||
// The y-positions of the multiplexer sprites.
|
||||
extern char PLEX_YPOS[PLEX_COUNT];
|
||||
|
||||
// The sprite pointers for the multiplexed sprites
|
||||
extern char PLEX_PTR[PLEX_COUNT];
|
||||
|
||||
// The address of the sprite pointers on the current screen (screen+0x3f8).
|
||||
extern char* PLEX_SCREEN_PTR;
|
||||
|
||||
// Indexes of the plex-sprites sorted by sprite y-position. Each call to plexSort() will fix the sorting if changes to the Y-positions have ruined it.
|
||||
extern char PLEX_SORTED_IDX[PLEX_COUNT];
|
||||
|
||||
// Initialize the multiplexer data structures
|
||||
void plexInit(char* screen);
|
||||
|
||||
// Set the address of the current screen used for setting sprite pointers (at screen+0x3f8)
|
||||
inline void plexSetScreen(char* screen);
|
||||
|
||||
// Ensure that the indices in PLEX_SORTED_IDX is sorted based on the y-positions in PLEX_YPOS
|
||||
// Assumes that the positions are nearly sorted already (as each sprite just moves a bit)
|
||||
// Uses an insertion sort:
|
||||
// 1. Moves a marker (m) from the start to end of the array. Every time the marker moves forward all elements before the marker are sorted correctly.
|
||||
// 2a. If the next element after the marker is larger that the current element
|
||||
// the marker can be moved forwards (as the sorting is correct).
|
||||
// 2b. If the next element after the marker is smaller than the current element:
|
||||
// elements before the marker are shifted right one at a time until encountering one smaller than the current one.
|
||||
// It is then inserted at the spot. Now the marker can move forward.
|
||||
void plexSort();
|
||||
|
||||
// Show the next sprite.
|
||||
// plexSort() prepares showing the sprites
|
||||
void plexShowSprite();
|
||||
|
||||
// Get the y-position of the next sprite to show
|
||||
inline char plexShowNextYpos();
|
||||
|
||||
// Prepare for a new frame. Initialize free to zero for all sprites.
|
||||
inline void plexFreePrepare();
|
||||
|
||||
// Get the Y-position where the next sprite to be shown is free to use.
|
||||
inline char plexFreeNextYpos();
|
||||
|
||||
// Update the data structure to reflect that a sprite has been shown. This sprite will be free again after 21 lines.
|
||||
inline void plexFreeAdd(char ypos);
|
19
src/main/kc/include/multiply.h
Normal file
19
src/main/kc/include/multiply.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Simple binary multiplication implementation
|
||||
|
||||
// Perform binary multiplication of two unsigned 8-bit bytes into a 16-bit unsigned word
|
||||
unsigned int mul8u(char a, char b);
|
||||
|
||||
// Multiply of two signed bytes to a signed word
|
||||
// Fixes offsets introduced by using unsigned multiplication
|
||||
int mul8s(signed char a, signed char b);
|
||||
|
||||
// Multiply a signed byte and an unsigned byte (into a signed word)
|
||||
// Fixes offsets introduced by using unsigned multiplication
|
||||
int mul8su(signed char a, char b);
|
||||
|
||||
// Perform binary multiplication of two unsigned 16-bit words into a 32-bit unsigned double word
|
||||
unsigned long mul16u(unsigned int a, unsigned int b);
|
||||
|
||||
// Multiply of two signed words to a signed double word
|
||||
// Fixes offsets introduced by using unsigned multiplication
|
||||
signed long mul16s(int a, int b);
|
76
src/main/kc/include/print.h
Normal file
76
src/main/kc/include/print.h
Normal file
@ -0,0 +1,76 @@
|
||||
#include <print.h>
|
||||
|
||||
// Print a number of zero-terminated strings, each followed by a newline.
|
||||
// The sequence of lines is terminated by another zero.
|
||||
void print_str_lines(byte* str);
|
||||
|
||||
// Print a zero-terminated string followed by a newline
|
||||
void print_str_ln(byte* str);
|
||||
|
||||
// Print a zero-terminated string
|
||||
void print_str(byte* str);
|
||||
|
||||
// Print a string at a specific screen position
|
||||
void print_str_at(byte* str, byte* at);
|
||||
|
||||
// Print a newline
|
||||
void print_ln();
|
||||
|
||||
// Print a int as HEX
|
||||
void print_sword(signed word w);
|
||||
|
||||
// Print a signed byte as HEX
|
||||
void print_sbyte(signed byte b);
|
||||
|
||||
// Prints a signed byte as HEX at a specific position on the screen
|
||||
// row and col are 0-based indices
|
||||
inline void print_sbyte_pos(signed byte sb, byte row, byte col);
|
||||
|
||||
// Print a signed byte as hex at a specific screen position
|
||||
void print_sbyte_at(signed byte b, byte* at);
|
||||
|
||||
// Print a word as HEX
|
||||
void print_word(word w);
|
||||
|
||||
// Print a byte as DECIMAL
|
||||
void print_byte_decimal(byte b);
|
||||
|
||||
// Print a word as DECIMAL
|
||||
void print_word_decimal(word w);
|
||||
|
||||
// Print a word as HEX at a specific position
|
||||
void print_word_at(word w, byte* at);
|
||||
|
||||
// Print a dword as HEX
|
||||
void print_dword(unsigned dword dw);
|
||||
|
||||
// Print a unsigned long as DECIMAL
|
||||
void print_dword_decimal(unsigned dword w);
|
||||
|
||||
// Print a unsigned long as HEX at a specific position
|
||||
void print_dword_at(unsigned dword dw, byte* at);
|
||||
|
||||
// Print a signed long as HEX
|
||||
void print_sdword(signed dword dw);
|
||||
|
||||
// Print a byte as HEX
|
||||
void print_byte(byte b);
|
||||
|
||||
// Prints a byte as HEX at a specific position on the screen
|
||||
// row and col are 0-based indices
|
||||
void print_byte_pos(byte b, byte row, byte col);
|
||||
|
||||
// Print a byte as HEX at a specific position
|
||||
void print_byte_at(byte b, byte* at);
|
||||
|
||||
// Print a single char
|
||||
void print_char(byte ch);
|
||||
|
||||
// Print a single char
|
||||
void print_char_at(byte ch, byte* at);
|
||||
|
||||
// Clear the screen. Also resets current line/char cursor.
|
||||
void print_cls();
|
||||
|
||||
// Set the screen to print on. Also resets current line/char cursor.
|
||||
void print_set_screen(byte* screen);
|
52
src/main/kc/include/sinus.h
Normal file
52
src/main/kc/include/sinus.h
Normal file
@ -0,0 +1,52 @@
|
||||
// Sinus Generator functions using only multiplication, addition and bit shifting
|
||||
// Uses a single division for converting the wavelength to a reciprocal.
|
||||
// Generates sinus using the series sin(x) = x - x^/3! + x^-5! - x^7/7! ...
|
||||
// Uses the approximation sin(x) = x - x^/6 + x^/128
|
||||
// Optimization possibility: Use symmetries when generating sinustables. wavelength%2==0 -> mirror symmetry over PI, wavelength%4==0 -> mirror symmetry over PI/2.
|
||||
|
||||
// PI*2 in u[4.28] format
|
||||
extern const unsigned long PI2_u4f28;
|
||||
// PI in u[4.28] format
|
||||
extern const unsigned long PI_u4f28;
|
||||
// PI/2 in u[4.28] format
|
||||
extern const unsigned long PI_HALF_u4f28;
|
||||
|
||||
// PI*2 in u[4.12] format
|
||||
extern const unsigned int PI2_u4f12;
|
||||
// PI in u[4.12] format
|
||||
extern const unsigned int PI_u4f12;
|
||||
// PI/2 in u[4.12] format
|
||||
extern const unsigned int PI_HALF_u4f12;
|
||||
|
||||
// Generate signed (large) word sinus table - on the full -$7fff - $7fff range
|
||||
// sintab - the table to generate into
|
||||
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
|
||||
void sin16s_gen(int* sintab, unsigned int wavelength);
|
||||
|
||||
// Generate signed word sinus table - with values in the range min-max.
|
||||
// sintab - the table to generate into
|
||||
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
|
||||
void sin16s_gen2(int* sintab, unsigned int wavelength, int min, int max);
|
||||
|
||||
// Generate signed byte sinus table - on the full -$7f - $7f range
|
||||
// sintab - the table to generate into
|
||||
// wavelength - the number of sinus points in a total sinus wavelength (the size of the table)
|
||||
void sin8s_gen(signed char* sintab, unsigned int wavelength);
|
||||
|
||||
// Calculate signed word sinus sin(x)
|
||||
// x: unsigned dword input u[4.28] in the interval $00000000 - PI2_u4f28
|
||||
// result: signed word sin(x) s[0.15] - using the full range -$7fff - $7fff
|
||||
int sin16s(unsigned long x);
|
||||
|
||||
// Calculate signed byte sinus sin(x)
|
||||
// x: unsigned word input u[4.12] in the interval $0000 - PI2_u4f12
|
||||
// result: signed byte sin(x) s[0.7] - using the full range -$7f - $7f
|
||||
signed char sin8s(unsigned int x);
|
||||
|
||||
// Calculate val*val for two unsigned word values - the result is 16 selected bits of the 32-bit result.
|
||||
// The select parameter indicates how many of the highest bits of the 32-bit result to skip
|
||||
unsigned int mulu16_sel(unsigned int v1, unsigned int v2, char select);
|
||||
|
||||
// Calculate val*val for two unsigned byte values - the result is 8 selected bits of the 16-bit result.
|
||||
// The select parameter indicates how many of the highest bits of the 16-bit result to skip
|
||||
char mulu8_sel(char v1, char v2, char select);
|
14
src/main/kc/include/sqr.h
Normal file
14
src/main/kc/include/sqr.h
Normal file
@ -0,0 +1,14 @@
|
||||
// Table-based implementation of integer square sqr() and square root sqrt()
|
||||
|
||||
// Initialize squares table
|
||||
// Uses iterative formula (x+1)^2 = x^2 + 2*x + 1
|
||||
void init_squares();
|
||||
|
||||
// Find the square of a byte value
|
||||
// Uses a table of squares that must be initialized by calling init_squares()
|
||||
word sqr(byte val);
|
||||
|
||||
// Find the (integer) square root of a word value
|
||||
// If the square is not an integer then it returns the largest integer N where N*N <= val
|
||||
// Uses a table of squares that must be initialized by calling init_squares()
|
||||
byte sqrt(word val);
|
41
src/main/kc/include/stdlib.h
Normal file
41
src/main/kc/include/stdlib.h
Normal file
@ -0,0 +1,41 @@
|
||||
// C standard library stdlib.h
|
||||
// Implementation of functions found int C stdlib.h / stdlib.c
|
||||
#include <string.h>
|
||||
|
||||
// Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.
|
||||
// The content of the newly allocated block of memory is not initialized, remaining with indeterminate values.
|
||||
void* malloc(unsigned int size);
|
||||
|
||||
// A block of memory previously allocated by a call to malloc is deallocated, making it available again for further allocations.
|
||||
// If ptr is a null pointer, the function does nothing.
|
||||
void free(void* ptr);
|
||||
|
||||
// Allocates memory and returns a pointer to it. Sets allocated memory to zero.
|
||||
// - nitems − This is the number of elements to be allocated.
|
||||
// - size − This is the size of elements.
|
||||
void *calloc(size_t nitems, size_t size);
|
||||
|
||||
// Searches an array of nitems unsigned words, the initial member of which is pointed to by base, for a member that matches the value key.
|
||||
// - key - The value to look for
|
||||
// - items - Pointer to the start of the array to search in
|
||||
// - num - The number of items in the array
|
||||
// Returns pointer to an entry in the array that matches the search key
|
||||
unsigned int* bsearch16u(unsigned int key, unsigned int* items, char num);
|
||||
|
||||
// The different supported radix
|
||||
enum RADIX { BINARY=2, OCTAL=8, DECIMAL=10, HEXADECIMAL=16 };
|
||||
|
||||
// Converts unsigned number value to a string representing it in RADIX format.
|
||||
// If the leading digits are zero they are not included in the string.
|
||||
// - value : The number to be converted to RADIX
|
||||
// - buffer : receives the string representing the number and zero-termination.
|
||||
// - radix : The radix to convert the number to (from the enum RADIX)
|
||||
void utoa(unsigned int value, char* buffer, enum RADIX radix);
|
||||
|
||||
// Converts unsigned number value to a string representing it in RADIX format.
|
||||
// If the leading digits are zero they are not included in the string.
|
||||
// - value : The number to be converted to RADIX
|
||||
// - buffer : receives the string representing the number and zero-termination.
|
||||
// - radix : The radix to convert the number to (from the enum RADIX)
|
||||
void ultoa(unsigned long value, char* buffer, enum RADIX radix);
|
||||
|
21
src/main/kc/include/string.h
Normal file
21
src/main/kc/include/string.h
Normal file
@ -0,0 +1,21 @@
|
||||
// C standard library string.h
|
||||
// Functions to manipulate C strings and arrays.
|
||||
|
||||
typedef unsigned int size_t ;
|
||||
|
||||
// Copy block of memory (forwards)
|
||||
// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
|
||||
void* memcpy( void* destination, void* source, size_t num );
|
||||
|
||||
// Move block of memory
|
||||
// Copies the values of num bytes from the location pointed by source to the memory block pointed by destination. Copying takes place as if an intermediate buffer were used, allowing the destination and source to overlap.
|
||||
void* memmove( void* destination, void* source, size_t num );
|
||||
|
||||
// Copies the character c (an unsigned char) to the first num characters of the object pointed to by the argument str.
|
||||
void *memset(void *str, char c, size_t num);
|
||||
|
||||
// Copies the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
|
||||
char* strcpy( char* destination, char* source );
|
||||
|
||||
// Computes the length of the string str up to but not including the terminating null character.
|
||||
size_t strlen(char *str);
|
@ -1,8 +1,6 @@
|
||||
// C standard library time.h
|
||||
// Functions to get and manipulate date and time information.
|
||||
|
||||
#include <c64.c>
|
||||
|
||||
// Type suitable for storing the processor time.
|
||||
typedef unsigned long clock_t;
|
||||
|
||||
@ -21,17 +19,8 @@ const unsigned long CLOCKS_PER_INIT = 0x12;
|
||||
|
||||
// Returns the processor clock time used since the beginning of an implementation defined era (normally the beginning of the program).
|
||||
// This uses CIA #2 Timer A+B on the C64, and must be initialized using clock_start()
|
||||
clock_t clock(void) {
|
||||
return 0xffffffff - *CIA2_TIMER_AB;
|
||||
}
|
||||
clock_t clock(void);
|
||||
|
||||
// Reset & start the processor clock time. The value can be read using clock().
|
||||
// This uses CIA #2 Timer A+B on the C64
|
||||
void clock_start(void) {
|
||||
// Setup CIA#2 timer A to count (down) CPU cycles
|
||||
*CIA2_TIMER_A_CONTROL = CIA_TIMER_CONTROL_STOP | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_A_COUNT_CYCLES;
|
||||
*CIA2_TIMER_B_CONTROL = CIA_TIMER_CONTROL_STOP | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A;
|
||||
*CIA2_TIMER_AB = 0xffffffff;
|
||||
*CIA2_TIMER_B_CONTROL = CIA_TIMER_CONTROL_START | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A;
|
||||
*CIA2_TIMER_A_CONTROL = CIA_TIMER_CONTROL_START | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_A_COUNT_CYCLES;
|
||||
}
|
||||
void clock_start(void);
|
@ -1,6 +1,8 @@
|
||||
// Find atan2(x, y) using the CORDIC method
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
|
||||
#include <atan2.h>
|
||||
|
||||
// The number of iterations performed during 16-bit CORDIC atan2 calculation
|
||||
const byte CORDIC_ITERATIONS_16 = 15;
|
||||
|
@ -2,6 +2,8 @@
|
||||
// See https://www.c64-wiki.com/wiki/Floating_point_arithmetic
|
||||
// See http://www.pagetable.com/c64rom/c64rom_sc.html
|
||||
|
||||
#include <basic-floats.h>
|
||||
|
||||
// Zeropage addresses used to hold lo/hi-bytes of addresses of float numbers in MEM
|
||||
char* const memLo = 0xfe;
|
||||
char* const memHi = 0xff;
|
@ -1,6 +1,8 @@
|
||||
// Plot and line drawing routines for HIRES bitmaps
|
||||
// Currently it can only plot on the first 256 x-positions.
|
||||
|
||||
#include <bitmap-draw.h>
|
||||
|
||||
// Tables for the plotter - initialized by calling bitmap_draw_init();
|
||||
const byte bitmap_plot_xlo[256];
|
||||
const byte bitmap_plot_xhi[256];
|
@ -1,5 +1,6 @@
|
||||
// Simple single-color (320x200) bitmap routines
|
||||
#include <string.c>
|
||||
#include <bitmap2.h>
|
||||
#include <string.h>
|
||||
|
||||
// The adddress of the bitmap screen (used for colors)
|
||||
byte* bitmap_screen;
|
27
src/main/kc/lib/c64.c
Normal file
27
src/main/kc/lib/c64.c
Normal file
@ -0,0 +1,27 @@
|
||||
// Commodore 64 Registers and Constants
|
||||
#include <c64.h>
|
||||
|
||||
// Get the value to store into D018 to display a specific screen and charset/bitmap
|
||||
// Optimized for ASM from (byte)((((word)screen&$3fff)/$40)|(((word)charset&$3fff)/$400));
|
||||
inline char toD018(char* screen, char* gfx) {
|
||||
return (>((((unsigned int)screen&$3fff)*4)))|(((>((unsigned int)gfx))/4)&$f);
|
||||
}
|
||||
|
||||
// Get the value to store into DD00 (CIA 2 port A) to choose a specific VIC bank
|
||||
// Optimized for ASM from %00000011 ^ (byte)((word)gfx/$4000)
|
||||
inline char toDd00(char* gfx) {
|
||||
return %00000011 ^ (>((unsigned int)gfx))/$40;
|
||||
}
|
||||
|
||||
// Get the sprite pointer for a sprite.
|
||||
// The sprite pointer is the index of the sprite within the graphics bank and equal to the sprite (byte)(sprite_addr/64)
|
||||
// The sprite pointers are stored SCREEN+$3f8+sprite_id to set the pointer of each sprite
|
||||
inline char toSpritePtr(char* sprite) {
|
||||
return (char)(((unsigned int)sprite)/$40);
|
||||
}
|
||||
|
||||
// Select a specific VIC graphics bank by setting the CIA 2 port A ($dd00) as needed
|
||||
inline void vicSelectGfxBank(char* gfx) {
|
||||
*CIA2_PORT_A_DDR = %00000011;
|
||||
*CIA2_PORT_A = toDd00(gfx);
|
||||
}
|
24
src/main/kc/lib/c64dtv.c
Normal file
24
src/main/kc/lib/c64dtv.c
Normal file
@ -0,0 +1,24 @@
|
||||
// C64 DTV version 2 Registers and Constants
|
||||
//
|
||||
// Sources
|
||||
// (J) https://www.c64-wiki.com/wiki/C64DTV_Programming_Guide
|
||||
// (H) http://dtvhacking.cbm8bit.com/dtv_wiki/images/d/d9/Dtv_registers_full.txt
|
||||
|
||||
#include <c64dtv.h>
|
||||
|
||||
// Set the memory pointed to by CPU BANK 1 SEGMENT ($4000-$7fff)
|
||||
// This sets which actual memory is addressed when the CPU reads/writes to $4000-$7fff
|
||||
// The actual memory addressed will be $4000*cpuSegmentIdx
|
||||
void dtvSetCpuBankSegment1(byte cpuBankIdx) {
|
||||
// Move CPU BANK 1 SEGMENT ($4000-$7fff)
|
||||
byte* cpuBank = $ff;
|
||||
*cpuBank = cpuBankIdx;
|
||||
asm {
|
||||
// SAC $dd - A register points to 13 BANK 1 segment
|
||||
.byte $32, $dd
|
||||
// LDA $ff - Set CPU BANK 1 SEGMENT ($4000-$7fff) to ($ff)*$4000
|
||||
lda $ff
|
||||
// SAC $00 - A register points to 0 ACCUMULATOR
|
||||
.byte $32, $00
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
// Follows the C99 standard by truncating toward zero on negative results.
|
||||
// See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf section 6.5.5
|
||||
|
||||
#include <division.h>
|
||||
|
||||
// Remainder after signed 8 bit division
|
||||
byte rem8u =0;
|
||||
|
@ -2,6 +2,8 @@
|
||||
// See http://codebase64.org/doku.php?id=base:seriously_fast_multiplication
|
||||
// Utilizes the fact that a*b = ((a+b)/2)^2 - ((a-b)/2)^2
|
||||
|
||||
#include <fastmultiply.h>
|
||||
|
||||
// mulf_sqr tables will contain f(x)=int(x*x/4) and g(x) = f(x-255).
|
||||
// <f(x) = <(( x * x )/4)
|
||||
byte align($100) mulf_sqr1_lo[512];
|
@ -16,75 +16,8 @@
|
||||
// |7. | #%01111111 (127/$7f) | STOP ($ )| q ($11)|COMMODR($ )| SPACE ($20)| 2 ($32)|CONTROL($ )| <- ($1f)| 1 ($31)|
|
||||
// +----+----------------------+------------+------------+------------+------------+------------+------------+------------+------------+
|
||||
|
||||
#include <c64.c>
|
||||
|
||||
// Keyboard Codes for all 63 keys.
|
||||
// Keyboard Codes are %00rrrccc, where rrr is the row ID (0-7) and ccc is the column ID (0-7).
|
||||
// See C64 Keyboard Matrix Reference http://codebase64.org/doku.php?id=base:reading_the_keyboard
|
||||
const byte KEY_DEL = $00;
|
||||
const byte KEY_RETURN = $01;
|
||||
const byte KEY_CRSR_RIGHT = $02;
|
||||
const byte KEY_F7 = $03;
|
||||
const byte KEY_F1 = $04;
|
||||
const byte KEY_F3 = $05;
|
||||
const byte KEY_F5 = $06;
|
||||
const byte KEY_CRSR_DOWN = $07;
|
||||
const byte KEY_3 = $08;
|
||||
const byte KEY_W = $09;
|
||||
const byte KEY_A = $0a;
|
||||
const byte KEY_4 = $0b;
|
||||
const byte KEY_Z = $0c;
|
||||
const byte KEY_S = $0d;
|
||||
const byte KEY_E = $0e;
|
||||
const byte KEY_LSHIFT = $0f;
|
||||
const byte KEY_5 = $10;
|
||||
const byte KEY_R = $11;
|
||||
const byte KEY_D = $12;
|
||||
const byte KEY_6 = $13;
|
||||
const byte KEY_C = $14;
|
||||
const byte KEY_F = $15;
|
||||
const byte KEY_T = $16;
|
||||
const byte KEY_X = $17;
|
||||
const byte KEY_7 = $18;
|
||||
const byte KEY_Y = $19;
|
||||
const byte KEY_G = $1a;
|
||||
const byte KEY_8 = $1b;
|
||||
const byte KEY_B = $1c;
|
||||
const byte KEY_H = $1d;
|
||||
const byte KEY_U = $1e;
|
||||
const byte KEY_V = $1f;
|
||||
const byte KEY_9 = $20;
|
||||
const byte KEY_I = $21;
|
||||
const byte KEY_J = $22;
|
||||
const byte KEY_0 = $23;
|
||||
const byte KEY_M = $24;
|
||||
const byte KEY_K = $25;
|
||||
const byte KEY_O = $26;
|
||||
const byte KEY_N = $27;
|
||||
const byte KEY_PLUS = $28;
|
||||
const byte KEY_P = $29;
|
||||
const byte KEY_L = $2a;
|
||||
const byte KEY_MINUS = $2b;
|
||||
const byte KEY_DOT = $2c;
|
||||
const byte KEY_COLON = $2d;
|
||||
const byte KEY_AT = $2e;
|
||||
const byte KEY_COMMA = $2f;
|
||||
const byte KEY_POUND = $30;
|
||||
const byte KEY_ASTERISK = $31;
|
||||
const byte KEY_SEMICOLON = $32;
|
||||
const byte KEY_HOME = $33;
|
||||
const byte KEY_RSHIFT = $34;
|
||||
const byte KEY_EQUALS = $35;
|
||||
const byte KEY_ARROW_UP = $36;
|
||||
const byte KEY_SLASH = $37;
|
||||
const byte KEY_1 = $38;
|
||||
const byte KEY_ARROW_LEFT = $39;
|
||||
const byte KEY_CTRL = $3a;
|
||||
const byte KEY_2 = $3b;
|
||||
const byte KEY_SPACE = $3c;
|
||||
const byte KEY_COMMODORE = $3d;
|
||||
const byte KEY_Q = $3e;
|
||||
const byte KEY_RUNSTOP = $3f;
|
||||
#include <keyboard.h>
|
||||
#include <c64.h>
|
||||
|
||||
// Keycodes for each screen code character from $00-$3f.
|
||||
// Chars that do not have an unmodified keycode return $3f (representing RUN/STOP).
|
@ -12,7 +12,8 @@
|
||||
// In practice a good method is to wait until the raster is beyond plexFreeNextYpos() and then call plexShowSprite(). Repeat until all 32 sprites have been shown.
|
||||
// TODO: Let the caller specify the number of sprites to use (or add PLEX_ENABLE[PLEX_COUNT])
|
||||
|
||||
#include <c64.c>
|
||||
#include <multiplexer.h>
|
||||
#include <c64.h>
|
||||
|
||||
// The number of sprites in the multiplexer
|
||||
const char PLEX_COUNT = 32;
|
@ -1,5 +1,7 @@
|
||||
// Simple binary multiplication implementation
|
||||
|
||||
#include <multiply.h>
|
||||
|
||||
// Perform binary multiplication of two unsigned 8-bit bytes into a 16-bit unsigned word
|
||||
word mul8u(byte a, byte b) {
|
||||
word res = 0;
|
@ -1,5 +1,5 @@
|
||||
#include <stdlib.c>
|
||||
#include <string.c>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
byte* print_screen = $0400;
|
||||
byte* print_line_cursor = print_screen;
|
@ -4,8 +4,9 @@
|
||||
// Uses the approximation sin(x) = x - x^/6 + x^/128
|
||||
// Optimization possibility: Use symmetries when generating sinustables. wavelength%2==0 -> mirror symmetry over PI, wavelength%4==0 -> mirror symmetry over PI/2.
|
||||
|
||||
#include <division.c>
|
||||
#include <multiply.c>
|
||||
#include <sinus.h>
|
||||
#include <division.h>
|
||||
#include <multiply.h>
|
||||
|
||||
// PI*2 in u[4.28] format
|
||||
const dword PI2_u4f28 = $6487ed51;
|
@ -1,6 +1,7 @@
|
||||
// Table-based implementation of integer square sqr() and square root sqrt()
|
||||
|
||||
#include <stdlib.c>
|
||||
#include <sqr.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// The number of squares to pre-calculate. Limits what values sqr() can calculate and the result of sqrt()
|
||||
byte NUM_SQUARES = 0xff;
|
@ -1,6 +1,7 @@
|
||||
// C standard library stdlib.h
|
||||
// Implementation of functions found int C stdlib.h / stdlib.c
|
||||
#include <string.c>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// Top of the heap used by malloc()
|
||||
unsigned char* HEAP_TOP = 0xa000;
|
||||
@ -52,8 +53,6 @@ unsigned int* bsearch16u(unsigned int key, unsigned int* items, char num) {
|
||||
return *items<=key?items:items-1;
|
||||
}
|
||||
|
||||
// The different supported radix
|
||||
enum RADIX { BINARY=2, OCTAL=8, DECIMAL=10, HEXADECIMAL=16 };
|
||||
// The digits used for numbers
|
||||
char DIGITS[] = "0123456789abcdef"z;
|
||||
|
@ -1,7 +1,6 @@
|
||||
// C standard library string.h
|
||||
// Functions to manipulate C strings and arrays.
|
||||
|
||||
typedef word size_t ;
|
||||
#include <string.h>
|
||||
|
||||
// Copy block of memory (forwards)
|
||||
// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination.
|
21
src/main/kc/lib/time.c
Normal file
21
src/main/kc/lib/time.c
Normal file
@ -0,0 +1,21 @@
|
||||
// C standard library time.h
|
||||
// Functions to get and manipulate date and time information.
|
||||
#include <time.h>
|
||||
#include <c64.h>
|
||||
|
||||
// Returns the processor clock time used since the beginning of an implementation defined era (normally the beginning of the program).
|
||||
// This uses CIA #2 Timer A+B on the C64, and must be initialized using clock_start()
|
||||
clock_t clock(void) {
|
||||
return 0xffffffff - *CIA2_TIMER_AB;
|
||||
}
|
||||
|
||||
// Reset & start the processor clock time. The value can be read using clock().
|
||||
// This uses CIA #2 Timer A+B on the C64
|
||||
void clock_start(void) {
|
||||
// Setup CIA#2 timer A to count (down) CPU cycles
|
||||
*CIA2_TIMER_A_CONTROL = CIA_TIMER_CONTROL_STOP | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_A_COUNT_CYCLES;
|
||||
*CIA2_TIMER_B_CONTROL = CIA_TIMER_CONTROL_STOP | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A;
|
||||
*CIA2_TIMER_AB = 0xffffffff;
|
||||
*CIA2_TIMER_B_CONTROL = CIA_TIMER_CONTROL_START | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A;
|
||||
*CIA2_TIMER_A_CONTROL = CIA_TIMER_CONTROL_START | CIA_TIMER_CONTROL_CONTINUOUS | CIA_TIMER_CONTROL_A_COUNT_CYCLES;
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
// Commodore 64 Registers and Constants
|
||||
|
||||
// Processor port data direction register
|
||||
byte* const PROCPORT_DDR = $00;
|
||||
// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
|
||||
const byte PROCPORT_DDR_MEMORY_MASK = %00000111;
|
||||
|
||||
// Processor Port Register controlling RAM/ROM configuration and the datasette
|
||||
byte* const PROCPORT = $01;
|
||||
// RAM in all three areas $A000, $D000, $E000
|
||||
const byte PROCPORT_RAM_ALL = %00000000;
|
||||
// RAM in $A000, $E000 I/O in $D000
|
||||
const byte PROCPORT_RAM_IO = %00000101;
|
||||
// RAM in $A000, $E000 CHAR ROM in $D000
|
||||
const byte PROCPORT_RAM_CHARROM = %00000001;
|
||||
// RAM in $A000, I/O in $D000, KERNEL in $E000
|
||||
const byte PROCPORT_KERNEL_IO = %00000110;
|
||||
// BASIC in $A000, I/O in $D000, KERNEL in $E000
|
||||
const byte PROCPORT_BASIC_KERNEL_IO = %00000111;
|
||||
|
||||
// The address of the CHARGEN character set
|
||||
byte* const CHARGEN = $d000;
|
||||
|
||||
// Positions of the border (in sprite positions)
|
||||
const byte BORDER_XPOS_LEFT=24;
|
||||
const word BORDER_XPOS_RIGHT=344;
|
||||
const byte BORDER_YPOS_TOP=50;
|
||||
const byte BORDER_YPOS_BOTTOM=250;
|
||||
|
||||
// The offset of the sprite pointers from the screen start address
|
||||
const word SPRITE_PTRS = $3f8;
|
||||
|
||||
byte* const SPRITES_XPOS = $d000;
|
||||
byte* const SPRITES_YPOS = $d001;
|
||||
byte* const SPRITES_XMSB = $d010;
|
||||
byte* const RASTER = $d012;
|
||||
byte* const SPRITES_ENABLE = $d015;
|
||||
byte* const SPRITES_EXPAND_Y = $d017;
|
||||
byte* const SPRITES_PRIORITY = $d01b;
|
||||
byte* const SPRITES_MC = $d01c;
|
||||
byte* const SPRITES_EXPAND_X = $d01d;
|
||||
byte* const BORDERCOL = $d020;
|
||||
byte* const BGCOL = $d021;
|
||||
byte* const BGCOL1 = $d021;
|
||||
byte* const BGCOL2 = $d022;
|
||||
byte* const BGCOL3 = $d023;
|
||||
byte* const BGCOL4 = $d024;
|
||||
byte* const SPRITES_MC1 = $d025;
|
||||
byte* const SPRITES_MC2 = $d026;
|
||||
byte* const SPRITES_COLS = $d027;
|
||||
|
||||
byte* const VIC_CONTROL = $d011;
|
||||
byte* const D011 = $d011;
|
||||
const byte VIC_RST8 = %10000000;
|
||||
const byte VIC_ECM = %01000000;
|
||||
const byte VIC_BMM = %00100000;
|
||||
const byte VIC_DEN = %00010000;
|
||||
const byte VIC_RSEL = %00001000;
|
||||
|
||||
byte* const VIC_CONTROL2 = $d016;
|
||||
byte* const D016 = $d016;
|
||||
const byte VIC_MCM = %00010000;
|
||||
const byte VIC_CSEL = %00001000;
|
||||
|
||||
byte* const D018 = $d018;
|
||||
byte* const VIC_MEMORY = $d018;
|
||||
|
||||
byte* const LIGHTPEN_X = $d013;
|
||||
byte* const LIGHTPEN_Y = $d014;
|
||||
|
||||
// VIC II IRQ Status Register
|
||||
byte* const IRQ_STATUS = $d019;
|
||||
// VIC II IRQ Enable Register
|
||||
byte* const IRQ_ENABLE = $d01a;
|
||||
// Bits for the IRQ Status/Enable Registers
|
||||
const byte IRQ_RASTER = %00000001;
|
||||
const byte IRQ_COLLISION_BG = %00000010;
|
||||
const byte IRQ_COLLISION_SPRITE = %00000100;
|
||||
const byte IRQ_LIGHTPEN = %00001000;
|
||||
|
||||
// Color Ram
|
||||
byte* const COLS = $d800;
|
||||
|
||||
// CIA#1 Port A: keyboard matrix columns and joystick #2
|
||||
byte* const CIA1_PORT_A = $dc00;
|
||||
// CIA#1 Port B: keyboard matrix rows and joystick #1.
|
||||
byte* const CIA1_PORT_B = $dc01;
|
||||
// CIA #1 Port A data direction register.
|
||||
byte* const CIA1_PORT_A_DDR = $dc02;
|
||||
// CIA #1 Port B data direction register.
|
||||
byte* const CIA1_PORT_B_DDR = $dc03;
|
||||
// CIA #1 Timer A Value
|
||||
word* const CIA1_TIMER_A = $dc04;
|
||||
// CIA #1 Timer B Value
|
||||
word* const CIA1_TIMER_B = $dc06;
|
||||
// CIA #1 Time-of-day real-time-clock tenth seconds (BCD)
|
||||
byte* const CIA1_TOD_10THS = $dc08;
|
||||
// CIA #1 Time-of-day real-time-clock seconds (BCD)
|
||||
byte* const CIA1_TOD_SEC = $dc09;
|
||||
// CIA #1 Time-of-day real-time-clock minutes (BCD)
|
||||
byte* const CIA1_TOD_MIN = $dc0a;
|
||||
// CIA #1 Time-of-day real-time-clock hours (BCD)
|
||||
byte* const CIA1_TOD_HOURS = $dc0b;
|
||||
// CIA #1 Serial Shift Register
|
||||
byte* const CIA1_SERIAL_SHIFT_OUT = $dc0c;
|
||||
// CIA#1 Interrupt Status & Control Register
|
||||
byte* const CIA1_INTERRUPT = $dc0d;
|
||||
// CIA#1 Timer A Control Register
|
||||
byte* const CIA1_TIMER_A_CONTROL = $dc0e;
|
||||
// CIA#1 Timer B Control Register
|
||||
byte* const CIA1_TIMER_B_CONTROL = $dc0f;
|
||||
|
||||
// CIA#2 Port A: Serial bus, RS-232, VIC memory bank
|
||||
byte* const CIA2_PORT_A = $dd00;
|
||||
// CIA#2 Port B: RS-232
|
||||
byte* const CIA2_PORT_B = $dd01;
|
||||
// CIA #2 Port A data direction register.
|
||||
byte* const CIA2_PORT_A_DDR = $dd02;
|
||||
// CIA #2 Port B data direction register.
|
||||
byte* const CIA2_PORT_B_DDR = $dd03;
|
||||
// CIA #2 Timer A+B Value (32-bit)
|
||||
dword* const CIA2_TIMER_AB = $dd04;
|
||||
// CIA #2 Timer A Value (16-bit)
|
||||
word* const CIA2_TIMER_A = $dd04;
|
||||
// CIA #2 Timer B Value (16-bit)
|
||||
word* const CIA2_TIMER_B = $dd06;
|
||||
// CIA #2 Time-of-day real-time-clock tenth seconds (BCD)
|
||||
byte* const CIA2_TOD_10THS = $dd08;
|
||||
// CIA #2 Time-of-day real-time-clock seconds (BCD)
|
||||
byte* const CIA2_TOD_SEC = $dd09;
|
||||
// CIA #2 Time-of-day real-time-clock minutes (BCD)
|
||||
byte* const CIA2_TOD_MIN = $dd0a;
|
||||
// CIA #2 Time-of-day real-time-clock hours (BCD)
|
||||
byte* const CIA2_TOD_HOURS = $dd0b;
|
||||
// CIA #2 Serial Shift Register
|
||||
byte* const CIA2_SERIAL_SHIFT_OUT = $dd0c;
|
||||
// CIA #2 Interrupt Status & Control Register
|
||||
byte* const CIA2_INTERRUPT = $dd0d;
|
||||
// CIA #2 Timer A Control Register
|
||||
byte* const CIA2_TIMER_A_CONTROL = $dd0e;
|
||||
// CIA #2 Timer B Control Register
|
||||
byte* const CIA2_TIMER_B_CONTROL = $dd0f;
|
||||
|
||||
// Value that disables all CIA interrupts when stored to the CIA Interrupt registers
|
||||
const byte CIA_INTERRUPT_CLEAR = $7f;
|
||||
|
||||
// Timer Control - Start/stop timer (0:stop, 1: start)
|
||||
const byte CIA_TIMER_CONTROL_STOP = 0b00000000;
|
||||
// Timer Control - Start/stop timer (0:stop, 1: start)
|
||||
const byte CIA_TIMER_CONTROL_START = 0b00000001;
|
||||
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
|
||||
const byte CIA_TIMER_CONTROL_CONTINUOUS = 0b00000000;
|
||||
// Timer Control - Time CONTINUOUS/ONE-SHOT (0:CONTINUOUS, 1: ONE-SHOT)
|
||||
const byte CIA_TIMER_CONTROL_ONESHOT = 0b00001000;
|
||||
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
|
||||
const byte CIA_TIMER_CONTROL_A_COUNT_CYCLES = 0b00000000;
|
||||
// Timer A Control - Timer counts (0:system cycles, 1: CNT pulses)
|
||||
const byte CIA_TIMER_CONTROL_A_COUNT_CNT = 0b00100000;
|
||||
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
|
||||
const byte CIA_TIMER_CONTROL_A_SERIAL_IN = 0b00000000;
|
||||
// Timer A Control - Serial Port Mode (0: Serial Port Input, 1: Serial Port Output)
|
||||
const byte CIA_TIMER_CONTROL_A_SERIAL_OUT = 0b01000000;
|
||||
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
|
||||
const byte CIA_TIMER_CONTROL_A_TOD_60HZ = 0b00000000;
|
||||
// Timer A Control - time-of-day clock Mode (0: 60Hz, 1: 50Hz)
|
||||
const byte CIA_TIMER_CONTROL_A_TOD_50HZ = 0b10000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const byte CIA_TIMER_CONTROL_B_COUNT_CYCLES = 0b00000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const byte CIA_TIMER_CONTROL_B_COUNT_CNT = 0b00100000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const byte CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A = 0b01000000;
|
||||
// Timer B Control - Timer counts (00:system cycles, 01: CNT pulses, 10: timer A underflow, 11: time A underflow while CNT is high)
|
||||
const byte CIA_TIMER_CONTROL_B_COUNT_UNDERFLOW_A_CNT = 0b01100000;
|
||||
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
|
||||
const byte CIA_TIMER_CONTROL_B_TOD_CLOCK_SET = 0b00000000;
|
||||
// Timer B Control - time-of-day write mode (0: TOD clock, 1: TOD alarm)
|
||||
const byte CIA_TIMER_CONTROL_B_TOD_ALARM_SET = 0b10000000;
|
||||
|
||||
// The vector used when the KERNAL serves IRQ interrupts
|
||||
void()** const KERNEL_IRQ = $0314;
|
||||
// The vector used when the KERNAL serves NMI interrupts
|
||||
void()** const KERNEL_NMI = $0318;
|
||||
|
||||
// The vector used when the HARDWARE serves IRQ interrupts
|
||||
void()** const HARDWARE_IRQ = $fffe;
|
||||
|
||||
// The SID volume
|
||||
byte* const SID_VOLUME = $d418;
|
||||
|
||||
|
||||
// The colors of the C64
|
||||
const byte BLACK = $0;
|
||||
const byte WHITE = $1;
|
||||
const byte RED = $2;
|
||||
const byte CYAN = $3;
|
||||
const byte PURPLE = $4;
|
||||
const byte GREEN = $5;
|
||||
const byte BLUE = $6;
|
||||
const byte YELLOW = $7;
|
||||
const byte ORANGE = $8;
|
||||
const byte BROWN = $9;
|
||||
const byte PINK = $a;
|
||||
const byte DARK_GREY= $b;
|
||||
const byte GREY = $c;
|
||||
const byte LIGHT_GREEN = $d;
|
||||
const byte LIGHT_BLUE = $e;
|
||||
const byte LIGHT_GREY = $f;
|
||||
|
||||
// Get the value to store into D018 to display a specific screen and charset/bitmap
|
||||
// Optimized for ASM from (byte)((((word)screen&$3fff)/$40)|(((word)charset&$3fff)/$400));
|
||||
inline byte toD018(byte* screen, byte* gfx) {
|
||||
return (>((((word)screen&$3fff)*4)))|(((>((word)gfx))/4)&$f);
|
||||
}
|
||||
|
||||
// Get the value to store into DD00 (CIA 2 port A) to choose a specific VIC bank
|
||||
// Optimized for ASM from %00000011 ^ (byte)((word)gfx/$4000)
|
||||
inline byte toDd00(byte* gfx) {
|
||||
return %00000011 ^ (>((word)gfx))/$40;
|
||||
}
|
||||
|
||||
// Get the sprite pointer for a sprite.
|
||||
// The sprite pointer is the index of the sprite within the graphics bank and equal to the sprite (byte)(sprite_addr/64)
|
||||
// The sprite pointers are stored SCREEN+$3f8+sprite_id to set the pointer of each sprite
|
||||
inline byte toSpritePtr(byte* sprite) {
|
||||
return (byte)(((word)sprite)/$40);
|
||||
}
|
||||
|
||||
// Select a specific VIC graphics bank by setting the CIA 2 port A ($dd00) as needed
|
||||
inline void vicSelectGfxBank(byte* gfx) {
|
||||
*CIA2_PORT_A_DDR = %00000011;
|
||||
*CIA2_PORT_A = toDd00(gfx);
|
||||
}
|
@ -4,7 +4,8 @@ REM KICKC HOME
|
||||
set KICKC_HOME=%~dp0..
|
||||
echo KICKC_HOME=%KICKC_HOME%
|
||||
REM KCLIB HOME
|
||||
set KICKCLIB_HOME=%KICKC_HOME%\stdlib
|
||||
set KICKC_STDLIB=%KICKC_HOME%\lib
|
||||
set KICKC_STDINCLUDE=%KICKC_HOME%\include
|
||||
echo KICKCLIB_HOME=%KICKCLIB_HOME%
|
||||
set KICKC_FRAGMENT_HOME=%KICKC_HOME%\fragment
|
||||
echo KICKC_FRAGMENT_HOME=%KICKC_FRAGMENT_HOME%
|
||||
@ -14,5 +15,5 @@ REM KICKC_JAR
|
||||
for %%I in ( %KICKC_HOME%\lib\kickc-*.jar ) do set KICKC_JAR=%%I
|
||||
echo KICKC_JAR=%KICKC_JAR%
|
||||
|
||||
echo java -jar %KICKC_JAR% -I %KICKCLIB_HOME% -F %KICKC_FRAGMENT_HOME% %*
|
||||
java -jar %KICKC_JAR% -I %KICKCLIB_HOME% -F %KICKC_FRAGMENT_HOME% %*
|
||||
echo java -jar %KICKC_JAR% -I %KICKC_STDINCLUDE% -L %KICKC_STDLIB% -F %KICKC_FRAGMENT_HOME% %*
|
||||
java -jar %KICKC_JAR% -I %KICKC_STDINCLUDE% -L %KICKC_STDLIB% -F %KICKC_FRAGMENT_HOME% %*
|
@ -3,8 +3,10 @@
|
||||
# JAVA HOME
|
||||
# KICKC HOME
|
||||
export KICKC_HOME="$(dirname $0)/.."
|
||||
# KCLIB HOME
|
||||
export KICKC_STDLIB_HOME="$KICKC_HOME/stdlib"
|
||||
# STANDARD INCLUDE
|
||||
export KICKC_STD_INCLUDE="$KICKC_HOME/include"
|
||||
# STANDARD LIBRARY
|
||||
export KICKC_STD_LIB="$KICKC_HOME/lib"
|
||||
# FRAGMENTS HOME
|
||||
export KICKC_FRAGMENT_HOME="$KICKC_HOME/fragment"
|
||||
# KICKASSEMBLER HOME
|
||||
@ -19,5 +21,5 @@ while [[ "$#" -gt 0 ]]; do case $1 in
|
||||
*) export PARAM="$PARAM $1"; shift;;
|
||||
esac; done
|
||||
|
||||
echo java -jar $KICKC_JAR -F $KICKC_FRAGMENT_HOME $PARAM -I $KICKC_STDLIB_HOME
|
||||
java -jar $KICKC_JAR -F $KICKC_FRAGMENT_HOME $PARAM -I $KICKC_STDLIB_HOME
|
||||
echo java -jar $KICKC_JAR -F $KICKC_FRAGMENT_HOME $PARAM -I $KICKC_STD_INCLUDE -L $KICKC_STD_LIB
|
||||
java -jar $KICKC_JAR -F $KICKC_FRAGMENT_HOME $PARAM -I $KICKC_STD_INCLUDE -L $KICKC_STD_LIB
|
@ -32,13 +32,19 @@ import static org.junit.Assert.assertTrue;
|
||||
*/
|
||||
public class TestPrograms {
|
||||
|
||||
final String stdlibPath = "src/main/kc/stdlib";
|
||||
final String stdIncludePath = "src/main/kc/include";
|
||||
final String stdLibPath = "src/main/kc/lib";
|
||||
final String testPath = "src/test/kc";
|
||||
final String refPath = "src/test/ref/";
|
||||
|
||||
public TestPrograms() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludes3() throws IOException, URISyntaxException {
|
||||
compileAndCompare("complex/includes/includes-3.c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludes2() throws IOException, URISyntaxException {
|
||||
compileAndCompare("complex/includes/includes-2.c");
|
||||
@ -4023,8 +4029,9 @@ public class TestPrograms {
|
||||
if(compileLog != null) {
|
||||
compiler.setLog(compileLog);
|
||||
}
|
||||
compiler.addImportPath(stdlibPath);
|
||||
compiler.addImportPath(testPath);
|
||||
compiler.addIncludePath(stdIncludePath);
|
||||
compiler.addIncludePath(testPath);
|
||||
compiler.addLibraryPath(stdLibPath);
|
||||
compiler.initAsmFragmentSynthesizer(asmFragmentSynthesizer);
|
||||
if(upliftCombinations != null) {
|
||||
compiler.setUpliftCombinations(upliftCombinations);
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
byte* const BITMAP = $2000;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Coded by Richard-William Loerakker
|
||||
// Original Source https://bcaorganizer.blogspot.com/p/c-program-for_21.html?fbclid=IwAR0iL8pYcCqhCPa6LmtQ9qej-YonYVepY2cBegYRIWO0l8RPeOnTVniMAac
|
||||
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
byte* const BITMAP = $2000;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Illustrates problem with bitmap-draw.kc line()
|
||||
// Reported by Janne Johansson
|
||||
|
||||
#include <c64.c>
|
||||
#include <bitmap-draw.c>
|
||||
#include <c64.h>
|
||||
#include <bitmap-draw.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
byte* const BITMAP = $2000;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Shows that bitmap2.kc line() does not have the same problem as bitmap-draw.kc
|
||||
// See bitmap-line-anim-1.kc
|
||||
|
||||
#include <c64.c>
|
||||
#include <bitmap2.c>
|
||||
#include <c64.h>
|
||||
#include <bitmap2.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
byte* const BITMAP = $2000;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Tests the simple bitmap plotter - and counts plots per frame in an IRQ
|
||||
// Plots simple plots
|
||||
#include <c64.c>
|
||||
#include <bitmap2.c>
|
||||
#include <c64.h>
|
||||
#include <bitmap2.h>
|
||||
|
||||
byte* BITMAP = 0x2000;
|
||||
byte* SCREEN = 0x0400;
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Tests the simple bitmap plotter - and counts plots per frame in an IRQ
|
||||
// Plots a fullscreen elipsis
|
||||
#include <c64.c>
|
||||
#include <sinus.c>
|
||||
#include <multiply.c>
|
||||
#include <bitmap2.c>
|
||||
#include <c64.h>
|
||||
#include <sinus.h>
|
||||
#include <multiply.h>
|
||||
#include <bitmap2.h>
|
||||
|
||||
byte* BITMAP = 0x2000;
|
||||
byte* SCREEN = 0x0400;
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Tests the simple bitmap plotter - and counts plots per frame in an IRQ
|
||||
// Plots a spiral
|
||||
#include <c64.c>
|
||||
#include <sinus.c>
|
||||
#include <multiply.c>
|
||||
#include <bitmap2.c>
|
||||
#include <c64.h>
|
||||
#include <sinus.h>
|
||||
#include <multiply.h>
|
||||
#include <bitmap2.h>
|
||||
|
||||
byte* BITMAP = 0x2000;
|
||||
byte* SCREEN = 0x0400;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Tests the simple bitmap plotter
|
||||
// Plots a few lines using the bresenham line algorithm
|
||||
#include <c64.c>
|
||||
#include <bitmap2.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <bitmap2.h>
|
||||
#include <print.h>
|
||||
|
||||
byte* BITMAP = 0x2000;
|
||||
byte* SCREEN = 0x0400;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Tests the different standard C types
|
||||
|
||||
#include <print.c>
|
||||
#include <print.h>
|
||||
|
||||
void main() {
|
||||
print_cls();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// C64DTV 8bpp charmode stretcher
|
||||
#include <c64dtv.c>
|
||||
#include <c64dtv.h>
|
||||
|
||||
// Plane with the screen
|
||||
byte* const SCREEN = $7c00;
|
||||
|
@ -1,5 +1,5 @@
|
||||
// C64DTV 8bpp charmode stretcher
|
||||
#include <c64dtv.c>
|
||||
#include <c64dtv.h>
|
||||
|
||||
// Plane with all pixels
|
||||
byte* const CHUNKY = $8000;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Fill a box on the screen using the blitter
|
||||
|
||||
#include <c64dtv.c>
|
||||
#include <c64dtv.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
const byte SRCA[] = "camelot rules!";
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <c64dtv.c>
|
||||
#include <c64dtv.h>
|
||||
|
||||
byte* const SCREEN = $400;
|
||||
const byte SRCA[] = { 'c', 'a', 'm', 'e', 'l', 'o', 't', '!', ' '};
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Test C64DTV v2 256-colors and the 16-color redefinable palette
|
||||
|
||||
#include <c64dtv.c>
|
||||
#include <c64dtv.h>
|
||||
|
||||
void main() {
|
||||
asm { sei }
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Interactive Explorer for C64DTV Screen Modes
|
||||
#include <c64dtv.c>
|
||||
#include <print.c>
|
||||
#include <keyboard.c>
|
||||
#include <bitmap-draw.c>
|
||||
#include <c64dtv.h>
|
||||
#include <print.h>
|
||||
#include <keyboard.h>
|
||||
#include <bitmap-draw.h>
|
||||
|
||||
void main() {
|
||||
asm { sei } // Disable normal interrupt (prevent keyboard reading glitches and allows to hide basic/kernal)
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Exploring C64DTV Screen Modes
|
||||
#include <c64dtv.c>
|
||||
#include <print.c>
|
||||
#include <keyboard.c>
|
||||
#include <bitmap-draw.c>
|
||||
#include <c64dtv.h>
|
||||
#include <print.h>
|
||||
#include <keyboard.h>
|
||||
#include <bitmap-draw.h>
|
||||
|
||||
void main() {
|
||||
asm { sei } // Disable normal interrupt (prevent keyboard reading glitches and allows to hide basic/kernal)
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Counting cycles using a CIA timer
|
||||
|
||||
#include <c64.c>
|
||||
#include <time.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <time.h>
|
||||
#include <print.h>
|
||||
|
||||
byte* const SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Setup and run a simple CIA-timer
|
||||
|
||||
#include <c64.c>
|
||||
#include <time.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <time.h>
|
||||
#include <print.h>
|
||||
|
||||
byte* const SCREEN = 0x0400;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Clears start screen throwing around the letters (by turning them into sprites)
|
||||
#include <stdlib.c>
|
||||
#include <sqr.c>
|
||||
#include <atan2.c>
|
||||
#include <multiply.c>
|
||||
#include <c64.c>
|
||||
#include <stdlib.h>
|
||||
#include <sqr.h>
|
||||
#include <atan2.h>
|
||||
#include <multiply.h>
|
||||
#include <c64.h>
|
||||
|
||||
// Generate debug code (raster time usage etc.)
|
||||
const bool DEBUG = false;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Includes a system library - ignores the local file with the same name
|
||||
|
||||
#include <string.c>
|
||||
#include <string.h>
|
||||
|
||||
char* STR = "camelot!";
|
||||
|
||||
|
14
src/test/kc/complex/includes/includes-3.c
Normal file
14
src/test/kc/complex/includes/includes-3.c
Normal file
@ -0,0 +1,14 @@
|
||||
// A file using a library
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
const char* SCREEN = 0x0400;
|
||||
|
||||
void main() {
|
||||
|
||||
char i = 0;
|
||||
SCREEN[i++] = value;
|
||||
value = 'x';
|
||||
SCREEN[i++] = value;
|
||||
|
||||
}
|
6
src/test/kc/complex/includes/lib.c
Normal file
6
src/test/kc/complex/includes/lib.c
Normal file
@ -0,0 +1,6 @@
|
||||
// The library containing the char value definition
|
||||
|
||||
#include "lib.h"
|
||||
|
||||
// The char value
|
||||
char value = 'a';
|
4
src/test/kc/complex/includes/lib.h
Normal file
4
src/test/kc/complex/includes/lib.h
Normal file
@ -0,0 +1,4 @@
|
||||
// Library declaring a char value
|
||||
|
||||
// The char value
|
||||
extern char value;
|
@ -1,8 +1,8 @@
|
||||
// Display MEDUSA PETSCII by Buzz_clik
|
||||
// https://csdb.dk/release/?id=178673
|
||||
|
||||
#include <c64.c>
|
||||
#include <string.c>
|
||||
#include <c64.h>
|
||||
#include <string.h>
|
||||
|
||||
char MEDUSA_SCREEN[1000] = kickasm(resource "medusas.prg" ) {{
|
||||
.var fileScreen = LoadBinary("medusas.prg", BF_C64FILE)
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Pre-calculated bobs inside a charset (pre-moved to all x/y-combinations)
|
||||
#include <c64.c>
|
||||
#include <string.c>
|
||||
#include <keyboard.c>
|
||||
#include <time.c>
|
||||
#include <print.c>
|
||||
#include <fastmultiply.c>
|
||||
#include <c64.h>
|
||||
#include <string.h>
|
||||
#include <keyboard.h>
|
||||
#include <time.h>
|
||||
#include <print.h>
|
||||
#include <fastmultiply.h>
|
||||
|
||||
// The prototype BOB (a 3x3 char image with a bob image in the upper 2x2 chars)
|
||||
// The chars are layout as follows with data in chars 0, 1, 3, 4 initially
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Pre-calculated bobs inside a charset (pre-moved to all x/y-combinations)
|
||||
#include <c64.c>
|
||||
#include <string.c>
|
||||
#include <keyboard.c>
|
||||
#include <time.c>
|
||||
#include <print.c>
|
||||
#include <fastmultiply.c>
|
||||
#include <c64.h>
|
||||
#include <string.h>
|
||||
#include <keyboard.h>
|
||||
#include <time.h>
|
||||
#include <print.h>
|
||||
#include <fastmultiply.h>
|
||||
|
||||
// The prototype BOB (a 3x3 char image with a bob image in the upper 2x2 chars)
|
||||
// The chars are layout as follows with data in chars 0, 1, 3, 4 initially
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Same animation using a multiplexer
|
||||
#include <c64.c>
|
||||
#include <multiplexer.c>
|
||||
#include <fastmultiply.c>
|
||||
#include <string.c>
|
||||
#include <keyboard.c>
|
||||
#include <c64.h>
|
||||
#include <multiplexer.h>
|
||||
#include <fastmultiply.h>
|
||||
#include <string.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
// The BOB sprite
|
||||
align(0x1000) char SPRITE[] = kickasm(resource "smiley.png") {{
|
||||
|
@ -1,11 +1,11 @@
|
||||
// Show a few simple splines using the splines library
|
||||
|
||||
#include "splines.c"
|
||||
#include <bitmap2.c>
|
||||
#include <time.c>
|
||||
#include <print.c>
|
||||
#include <fastmultiply.c>
|
||||
#include <c64.c>
|
||||
#include <bitmap2.h>
|
||||
#include <time.h>
|
||||
#include <print.h>
|
||||
#include <fastmultiply.h>
|
||||
#include <c64.h>
|
||||
|
||||
char* const PRINT_SCREEN = 0x0400;
|
||||
char* const BITMAP_SCREEN = 0x5c00;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Put a 2x2 font into sprites and show it on screen
|
||||
#include <c64.c>
|
||||
#include <multiplexer.c>
|
||||
#include <c64.h>
|
||||
#include <multiplexer.h>
|
||||
|
||||
char * const CHARSET_DEFAULT = 0x1000;
|
||||
char * const SPRITES = 0x3000;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Tetris Game for the Commodore 64
|
||||
// A sprite multiplexer covering the playfield with a black layer to allow for 3 single-pixel colors
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
#include "tetris-data.c"
|
||||
|
||||
kickasm(pc PLAYFIELD_SPRITES, resource "playfield-sprites.png") {{
|
||||
|
@ -2,8 +2,8 @@
|
||||
// The tetris game tries to match NES tetris gameplay pretty closely
|
||||
// Source: https://meatfighter.com/nintendotetrisai/
|
||||
|
||||
#include <c64.c>
|
||||
#include <keyboard.c>
|
||||
#include <c64.h>
|
||||
#include <keyboard.h>
|
||||
#include "sid.c"
|
||||
#include "tetris-data.c"
|
||||
#include "tetris-render.c"
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <c64.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <print.h>
|
||||
|
||||
byte* SCREEN = $0400;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Each function of the kernal is a no-args function
|
||||
// The functions are placed in the SYSCALLS table surrounded by JMP and NOP
|
||||
|
||||
#include <string.c>
|
||||
#include <string.h>
|
||||
|
||||
#pragma link("xmega65.ld")
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <print.c>
|
||||
#include <print.h>
|
||||
byte* const BGCOL = $d021;
|
||||
const byte GREEN = 5;
|
||||
const byte RED = 2 ;
|
||||
|
@ -2,9 +2,9 @@
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
|
||||
#include "font-hex.c"
|
||||
#include <atan2.c>
|
||||
#include <c64.c>
|
||||
#include <print.c>
|
||||
#include <atan2.h>
|
||||
#include <c64.h>
|
||||
#include <print.h>
|
||||
|
||||
byte* const CHARSET = 0x2000;
|
||||
byte* const SCREEN = 0x2800;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
|
||||
#include "font-hex.c"
|
||||
#include <atan2.c>
|
||||
#include <c64.c>
|
||||
#include <atan2.h>
|
||||
#include <c64.h>
|
||||
|
||||
byte* const CHARSET = 0x2000;
|
||||
byte* const SCREEN = 0x2800;
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Find atan2(x, y) using the CORDIC method
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
#include "font-hex.c"
|
||||
#include <atan2.c>
|
||||
#include <c64.c>
|
||||
#include <atan2.h>
|
||||
#include <c64.h>
|
||||
|
||||
byte* const CHARSET = 0x2000;
|
||||
byte* const SCREEN = 0x2800;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// See http://bsvi.ru/uploads/CORDIC--_10EBA/cordic.pdf
|
||||
|
||||
#include "font-hex.c"
|
||||
#include <c64.c>
|
||||
#include <atan2.c>
|
||||
#include <c64.h>
|
||||
#include <atan2.h>
|
||||
|
||||
|
||||
byte* const CHARSET = 0x2000;
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Missing definition
|
||||
|
||||
// The definition
|
||||
extern char * const SCREEN = 0x0400;
|
||||
extern char * const SCREEN;
|
||||
|
||||
//Second definition
|
||||
char idx;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Tests problem writing/reading joystick encountered by Danny Spijksma
|
||||
// https://www.protovision.games/hardw/build4player.php?language=en&fbclid=IwAR1MJLgQjOU0zVa0ax2aNeGa-xVbE9IGY9zC6b6eInTV4HQzoUAoCPoXu14
|
||||
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
char* const SCREEN = 0x0400;
|
||||
void main() {
|
||||
(*CIA2_PORT_B) &= 0x7f;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Show default font on screen
|
||||
|
||||
#include <string.c>
|
||||
#include <string.h>
|
||||
|
||||
byte* SCREEN = 0x0400;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Based on facebook post from
|
||||
*/
|
||||
|
||||
#include <print.c>
|
||||
#include <print.h>
|
||||
|
||||
void main () {
|
||||
print_cls();
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Based on:
|
||||
// - C= Hacking Magazine Issue 8. http://www.ffd2.com/fridge/chacking/c=hacking8.txt
|
||||
// - Codebase64 Article http://codebase64.org/doku.php?id=base:3d_rotation
|
||||
#include <c64.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <print.h>
|
||||
|
||||
// The rotated point - updated by calling rotate_matrix()
|
||||
signed char* xr = $f0;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Based on:
|
||||
// - C= Hacking Magazine Issue 8. http://www.ffd2.com/fridge/chacking/c=hacking8.txt
|
||||
// - Codebase64 Article http://codebase64.org/doku.php?id=base:3d_rotation
|
||||
#include <c64.c>
|
||||
#include <print.c>
|
||||
#include <c64.h>
|
||||
#include <print.h>
|
||||
|
||||
// The rotated point - updated by calling rotate()
|
||||
signed char* xr = $f0;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <c64.c>
|
||||
#include <bitmap-draw.c>
|
||||
#include <c64.h>
|
||||
#include <bitmap-draw.h>
|
||||
|
||||
char* const SCREEN = $400;
|
||||
char* const BITMAP = $2000;
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Allows analysis of the CHARGEN ROM font
|
||||
#include <c64.c>
|
||||
#include <keyboard.c>
|
||||
#include <c64.h>
|
||||
#include <keyboard.h>
|
||||
|
||||
char* SCREEN = $400;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
// - http://codebase64.org/doku.php?id=base:seriously_fast_multiplication
|
||||
// - http://codebase64.org/doku.php?id=magazines:chacking16
|
||||
|
||||
#include <print.c>
|
||||
#include <print.h>
|
||||
|
||||
signed char vals[] = {-95, -64, -32, -16, 0, 16, 32, 64, 95};
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
// Ported to KickC by Jesper Gravgaard.
|
||||
// Original source https://github.com/cc65/cc65/blob/master/samples/fire.c
|
||||
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
#include "sid.c"
|
||||
|
||||
unsigned char* SCREEN1 = 0x3800;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Creates a 2x2 font from the system CHARGEN font and compress it by identifying identical chars
|
||||
|
||||
#include <c64.c>
|
||||
#include <string.c>
|
||||
#include <c64.h>
|
||||
#include <string.h>
|
||||
|
||||
char* const SCREEN = 0x0400;
|
||||
char* const FONT_ORIGINAL = 0x2000;
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include <print.c>
|
||||
#include <print.h>
|
||||
|
||||
void main() {
|
||||
print_str("hello world!");
|
||||
print_ln();
|
||||
|
@ -1,5 +1,5 @@
|
||||
// A raster IRQ that opens the top/bottom border.
|
||||
#include <c64.c>
|
||||
#include <c64.h>
|
||||
|
||||
char* const GHOST_BYTE = $3fff;
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
// To execute the program succesfully you must mount the D64 disk image and execute the kernalload.PRG program
|
||||
#pragma link("kernalload.ld")
|
||||
|
||||
#include <string.c>
|
||||
#include <c64.c>
|
||||
#include <string.h>
|
||||
#include <c64.h>
|
||||
|
||||
// Sprite file
|
||||
#pragma data_seg(Sprite)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user