mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-12-26 18:29:54 +00:00
Added command line support for var_model().
This commit is contained in:
parent
b05a321d85
commit
946144135a
@ -42,6 +42,9 @@ public class Compiler {
|
|||||||
/** File name of link script to use (from command line parameter). */
|
/** File name of link script to use (from command line parameter). */
|
||||||
private String linkScriptFileName;
|
private String linkScriptFileName;
|
||||||
|
|
||||||
|
/** Variable optimization/memory area configuration to use (from command line parameter). */
|
||||||
|
private VariableBuilderConfig variableBuilderConfig;
|
||||||
|
|
||||||
public Compiler() {
|
public Compiler() {
|
||||||
this.program = new Program();
|
this.program = new Program();
|
||||||
}
|
}
|
||||||
@ -55,7 +58,11 @@ public class Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setLinkScriptFileName(String linkScript) {
|
public void setLinkScriptFileName(String linkScript) {
|
||||||
linkScriptFileName = linkScript;
|
this.linkScriptFileName = linkScript;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVariableBuilderConfig(VariableBuilderConfig variableBuilderConfig) {
|
||||||
|
this.variableBuilderConfig = variableBuilderConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUpliftCombinations(int upliftCombinations) {
|
public void setUpliftCombinations(int upliftCombinations) {
|
||||||
@ -128,7 +135,16 @@ public class Compiler {
|
|||||||
program.setStatementSequence(new StatementSequence());
|
program.setStatementSequence(new StatementSequence());
|
||||||
CParser cParser = new CParser(program);
|
CParser cParser = new CParser(program);
|
||||||
KickCParser.FileContext cFileContext = cParser.loadAndParseCFile(fileName, currentPath);
|
KickCParser.FileContext cFileContext = cParser.loadAndParseCFile(fileName, currentPath);
|
||||||
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(cParser, cFileContext, program);
|
|
||||||
|
if(variableBuilderConfig == null) {
|
||||||
|
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||||
|
VariableBuilderConfig.defaultPreConfig(config, program.getLog());
|
||||||
|
VariableBuilderConfig.defaultPostConfig(config, program.getLog());
|
||||||
|
this.variableBuilderConfig = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
Pass0GenerateStatementSequence pass0GenerateStatementSequence = new Pass0GenerateStatementSequence(cParser, cFileContext, program, variableBuilderConfig);
|
||||||
|
|
||||||
pass0GenerateStatementSequence.generate();
|
pass0GenerateStatementSequence.generate();
|
||||||
|
|
||||||
StatementSequence sequence = program.getStatementSequence();
|
StatementSequence sequence = program.getStatementSequence();
|
||||||
@ -298,8 +314,8 @@ public class Compiler {
|
|||||||
optimizations.add(new Pass2AliasElimination(program));
|
optimizations.add(new Pass2AliasElimination(program));
|
||||||
optimizations.add(new Pass2IdenticalPhiElimination(program));
|
optimizations.add(new Pass2IdenticalPhiElimination(program));
|
||||||
optimizations.add(new Pass2DuplicateRValueIdentification(program));
|
optimizations.add(new Pass2DuplicateRValueIdentification(program));
|
||||||
optimizations.add(() -> { program.clearStatementIndices(); return false; });
|
optimizations.add(() -> { program.clearStatementIndices(); return false; });
|
||||||
optimizations.add(() -> { program.clearVariableReferenceInfos(); return false; });
|
optimizations.add(() -> { program.clearVariableReferenceInfos();return false; });
|
||||||
optimizations.add(() -> { program.clearStatementInfos(); return false; });
|
optimizations.add(() -> { program.clearStatementInfos(); return false; });
|
||||||
optimizations.add(new PassNStatementIndices(program));
|
optimizations.add(new PassNStatementIndices(program));
|
||||||
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
optimizations.add(new Pass2ConditionalJumpSimplification(program));
|
||||||
|
@ -3,10 +3,8 @@ package dk.camelot64.kickc;
|
|||||||
import dk.camelot64.kickc.asm.AsmProgram;
|
import dk.camelot64.kickc.asm.AsmProgram;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
|
import dk.camelot64.kickc.fragment.AsmFragmentTemplate;
|
||||||
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
|
import dk.camelot64.kickc.fragment.AsmFragmentTemplateUsages;
|
||||||
import dk.camelot64.kickc.model.CompileError;
|
import dk.camelot64.kickc.model.*;
|
||||||
import dk.camelot64.kickc.model.Program;
|
import dk.camelot64.kickc.model.statements.StatementSource;
|
||||||
import dk.camelot64.kickc.model.TargetCpu;
|
|
||||||
import dk.camelot64.kickc.model.TargetPlatform;
|
|
||||||
import kickass.KickAssembler;
|
import kickass.KickAssembler;
|
||||||
import kickass.nonasm.c64.CharToPetsciiConverter;
|
import kickass.nonasm.c64.CharToPetsciiConverter;
|
||||||
import picocli.CommandLine;
|
import picocli.CommandLine;
|
||||||
@ -16,9 +14,11 @@ import java.nio.file.FileAlreadyExistsException;
|
|||||||
import java.nio.file.FileSystems;
|
import java.nio.file.FileSystems;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/** KickC Commandline */
|
/** KickC Commandline */
|
||||||
@CommandLine.Command(
|
@CommandLine.Command(
|
||||||
@ -132,15 +132,18 @@ public class KickC implements Callable<Void> {
|
|||||||
@CommandLine.Option(names = {"-Si"}, description = "Interleave comments with intermediate language code and ASM fragment names in the generated ASM.")
|
@CommandLine.Option(names = {"-Si"}, description = "Interleave comments with intermediate language code and ASM fragment names in the generated ASM.")
|
||||||
private boolean interleaveIclFile = false;
|
private boolean interleaveIclFile = false;
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-t", "-target"}, description = "The target system. Default is C64 with BASIC upstart. ")
|
@CommandLine.Option(names = {"-t", "-target"}, description = "The target system. Default is C64 with BASIC upstart. See #pragma target()")
|
||||||
private String target = TargetPlatform.C64BASIC.getName();
|
private String target = TargetPlatform.C64BASIC.getName();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-cpu"}, description = "The target CPU. Default is 6502 with illegal opcodes. ")
|
@CommandLine.Option(names = {"-cpu"}, description = "The target CPU. Default is 6502 with illegal opcodes. See #pragma cpu()")
|
||||||
private String cpu = TargetCpu.MOS6502X.getName();
|
private String cpu = TargetCpu.MOS6502X.getName();
|
||||||
|
|
||||||
@CommandLine.Option(names = {"-T", "-link"}, description = "Link using a linker script in KickAss segment format.")
|
@CommandLine.Option(names = {"-T", "-link"}, description = "Link using a linker script in KickAss segment format. See #pragma link()")
|
||||||
private String linkScript = null;
|
private String linkScript = null;
|
||||||
|
|
||||||
|
@CommandLine.Option(names = {"-var_model"}, description = "Configure variable optimization/memory area. Default is ssa_zp. See #pragma var_model()")
|
||||||
|
private String varModel = null;
|
||||||
|
|
||||||
/** Program Exit Code signaling a compile error. */
|
/** Program Exit Code signaling a compile error. */
|
||||||
public static final int COMPILE_ERROR = 1;
|
public static final int COMPILE_ERROR = 1;
|
||||||
|
|
||||||
@ -268,6 +271,13 @@ public class KickC implements Callable<Void> {
|
|||||||
compiler.setLinkScriptFileName(linkScript);
|
compiler.setLinkScriptFileName(linkScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(varModel!=null) {
|
||||||
|
List<String> settings = Arrays.asList(varModel.split(","));
|
||||||
|
settings = settings.stream().map(String::trim).collect(Collectors.toList());
|
||||||
|
final VariableBuilderConfig config = VariableBuilderConfig.fromSettings(settings, StatementSource.NONE, compiler.getLog());
|
||||||
|
compiler.setVariableBuilderConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
System.out.println("Compiling " + kcFile);
|
System.out.println("Compiling " + kcFile);
|
||||||
Program program = null;
|
Program program = null;
|
||||||
try {
|
try {
|
||||||
|
@ -40,6 +40,32 @@ import java.util.*;
|
|||||||
*/
|
*/
|
||||||
public class VariableBuilderConfig {
|
public class VariableBuilderConfig {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create variable builder configuration from a number of settings.
|
||||||
|
* @param settings The settings.
|
||||||
|
* @param statementSource The statement source (used for error messages)
|
||||||
|
* @param program The program log (used for error messages)
|
||||||
|
* @return A variable builder configuration
|
||||||
|
*/
|
||||||
|
public static VariableBuilderConfig fromSettings(List<String> settings, StatementSource statementSource, CompileLog log) {
|
||||||
|
// Detect if the first setting is "full"
|
||||||
|
boolean full = false;
|
||||||
|
if(settings.size() > 0 && settings.get(0).equals(SETTING_FULL)) {
|
||||||
|
full = true;
|
||||||
|
settings = settings.subList(1, settings.size());
|
||||||
|
}
|
||||||
|
VariableBuilderConfig config = new VariableBuilderConfig();
|
||||||
|
if(!full)
|
||||||
|
defaultPreConfig(config, log);
|
||||||
|
// Apply all settings
|
||||||
|
for(String setting : settings) {
|
||||||
|
config.addSetting(setting, log, statementSource);
|
||||||
|
}
|
||||||
|
if(!full)
|
||||||
|
defaultPostConfig(config, log);
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
/** Setting specifying that the Variable Builder config is "full" and the default pre/post should not be applied. */
|
/** Setting specifying that the Variable Builder config is "full" and the default pre/post should not be applied. */
|
||||||
public static final String SETTING_FULL = "full";
|
public static final String SETTING_FULL = "full";
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ import java.nio.file.Path;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates program SSA form by visiting the ANTLR4 parse tree
|
* Generates program SSA form by visiting the ANTLR4 parse tree
|
||||||
@ -51,17 +52,14 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
/** Configuration for the variable builder. */
|
/** Configuration for the variable builder. */
|
||||||
private VariableBuilderConfig variableBuilderConfig;
|
private VariableBuilderConfig variableBuilderConfig;
|
||||||
|
|
||||||
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program) {
|
public Pass0GenerateStatementSequence(CParser cParser, KickCParser.FileContext fileCtx, Program program, VariableBuilderConfig variableBuilderConfig) {
|
||||||
this.cParser = cParser;
|
this.cParser = cParser;
|
||||||
this.fileCtx = fileCtx;
|
this.fileCtx = fileCtx;
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.sequence = program.getStatementSequence();
|
this.sequence = program.getStatementSequence();
|
||||||
this.scopeStack = new Stack<>();
|
this.scopeStack = new Stack<>();
|
||||||
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
|
this.defaultMemoryArea = Variable.MemoryArea.ZEROPAGE_MEMORY;
|
||||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
this.variableBuilderConfig = variableBuilderConfig;
|
||||||
VariableBuilderConfig.defaultPreConfig(config, program.getLog());
|
|
||||||
VariableBuilderConfig.defaultPostConfig(config, program.getLog());
|
|
||||||
this.variableBuilderConfig = config;
|
|
||||||
scopeStack.push(program.getScope());
|
scopeStack.push(program.getScope());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,22 +105,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitGlobalDirectiveVarModel(KickCParser.GlobalDirectiveVarModelContext ctx) {
|
public Object visitGlobalDirectiveVarModel(KickCParser.GlobalDirectiveVarModelContext ctx) {
|
||||||
List<TerminalNode> settings = new ArrayList<>(ctx.NAME());
|
List<TerminalNode> settingNodes = new ArrayList<>(ctx.NAME());
|
||||||
// Detect if the first setting is "full"
|
List<String> settings = settingNodes.stream().map(ParseTree::getText).collect(Collectors.toList());
|
||||||
boolean full = false;
|
this.variableBuilderConfig = VariableBuilderConfig.fromSettings(settings, new StatementSource(ctx), program.getLog());
|
||||||
if(settings.size() > 0 && settings.get(0).getText().equals(VariableBuilderConfig.SETTING_FULL)) {
|
|
||||||
full = true;
|
|
||||||
settings = settings.subList(1, settings.size());
|
|
||||||
}
|
|
||||||
VariableBuilderConfig config = new VariableBuilderConfig();
|
|
||||||
if(!full)
|
|
||||||
VariableBuilderConfig.defaultPreConfig(config, program.getLog());
|
|
||||||
for(TerminalNode varModel : settings) {
|
|
||||||
config.addSetting(varModel.getText(), program.getLog(), new StatementSource(ctx));
|
|
||||||
}
|
|
||||||
if(!full)
|
|
||||||
VariableBuilderConfig.defaultPostConfig(config, program.getLog());
|
|
||||||
this.variableBuilderConfig = config;
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
// Screen Sprite pointers on screen 2
|
// Screen Sprite pointers on screen 2
|
||||||
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
||||||
// Address of the sprites covering the playfield
|
// Address of the sprites covering the playfield
|
||||||
.label PLAYFIELD_SPRITES = $2000
|
.label PLAYFIELD_SPRITES = $3000
|
||||||
// Address of the charset
|
// Address of the charset
|
||||||
.label PLAYFIELD_CHARSET = $2800
|
.label PLAYFIELD_CHARSET = $2800
|
||||||
// The Y-position of the first sprite row
|
// The Y-position of the first sprite row
|
||||||
|
@ -427,7 +427,7 @@ SYMBOL TABLE SSA
|
|||||||
(const byte*) PLAYFIELD_CHARSET = (byte*)(number) $2800
|
(const byte*) PLAYFIELD_CHARSET = (byte*)(number) $2800
|
||||||
(const byte*) PLAYFIELD_SCREEN_1 = (byte*)(number) $400
|
(const byte*) PLAYFIELD_SCREEN_1 = (byte*)(number) $400
|
||||||
(const byte*) PLAYFIELD_SCREEN_2 = (byte*)(number) $2c00
|
(const byte*) PLAYFIELD_SCREEN_2 = (byte*)(number) $2c00
|
||||||
(const byte*) PLAYFIELD_SPRITES = (byte*)(number) $2000
|
(const byte*) PLAYFIELD_SPRITES = (byte*)(number) $3000
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
||||||
(const byte*) PROCPORT = (byte*)(number) 1
|
(const byte*) PROCPORT = (byte*)(number) 1
|
||||||
@ -779,7 +779,7 @@ Simplifying constant pointer cast (byte*) 56578
|
|||||||
Simplifying constant pointer cast (void()**) 65534
|
Simplifying constant pointer cast (void()**) 65534
|
||||||
Simplifying constant pointer cast (byte*) 1024
|
Simplifying constant pointer cast (byte*) 1024
|
||||||
Simplifying constant pointer cast (byte*) 11264
|
Simplifying constant pointer cast (byte*) 11264
|
||||||
Simplifying constant pointer cast (byte*) 8192
|
Simplifying constant pointer cast (byte*) 12288
|
||||||
Simplifying constant pointer cast (byte*) 10240
|
Simplifying constant pointer cast (byte*) 10240
|
||||||
Simplifying constant integer cast $13
|
Simplifying constant integer cast $13
|
||||||
Simplifying constant pointer cast (byte*) 10240
|
Simplifying constant pointer cast (byte*) 10240
|
||||||
@ -1631,7 +1631,7 @@ Target platform is c64basic / MOS6502X
|
|||||||
// Screen Sprite pointers on screen 2
|
// Screen Sprite pointers on screen 2
|
||||||
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
||||||
// Address of the sprites covering the playfield
|
// Address of the sprites covering the playfield
|
||||||
.label PLAYFIELD_SPRITES = $2000
|
.label PLAYFIELD_SPRITES = $3000
|
||||||
// Address of the charset
|
// Address of the charset
|
||||||
.label PLAYFIELD_CHARSET = $2800
|
.label PLAYFIELD_CHARSET = $2800
|
||||||
// The Y-position of the first sprite row
|
// The Y-position of the first sprite row
|
||||||
@ -2501,7 +2501,7 @@ ASSEMBLER BEFORE OPTIMIZATION
|
|||||||
// Screen Sprite pointers on screen 2
|
// Screen Sprite pointers on screen 2
|
||||||
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
||||||
// Address of the sprites covering the playfield
|
// Address of the sprites covering the playfield
|
||||||
.label PLAYFIELD_SPRITES = $2000
|
.label PLAYFIELD_SPRITES = $3000
|
||||||
// Address of the charset
|
// Address of the charset
|
||||||
.label PLAYFIELD_CHARSET = $2800
|
.label PLAYFIELD_CHARSET = $2800
|
||||||
// The Y-position of the first sprite row
|
// The Y-position of the first sprite row
|
||||||
@ -3186,7 +3186,7 @@ FINAL SYMBOL TABLE
|
|||||||
(const byte*) PLAYFIELD_CHARSET = (byte*) 10240
|
(const byte*) PLAYFIELD_CHARSET = (byte*) 10240
|
||||||
(const byte*) PLAYFIELD_SCREEN_1 = (byte*) 1024
|
(const byte*) PLAYFIELD_SCREEN_1 = (byte*) 1024
|
||||||
(const byte*) PLAYFIELD_SCREEN_2 = (byte*) 11264
|
(const byte*) PLAYFIELD_SCREEN_2 = (byte*) 11264
|
||||||
(const byte*) PLAYFIELD_SPRITES = (byte*) 8192
|
(const byte*) PLAYFIELD_SPRITES = (byte*) 12288
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
||||||
(const byte*) PROCPORT = (byte*) 1
|
(const byte*) PROCPORT = (byte*) 1
|
||||||
@ -3393,7 +3393,7 @@ Score: 11662
|
|||||||
// Screen Sprite pointers on screen 2
|
// Screen Sprite pointers on screen 2
|
||||||
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
.label PLAYFIELD_SPRITE_PTRS_2 = PLAYFIELD_SCREEN_2+SPRITE_PTRS
|
||||||
// Address of the sprites covering the playfield
|
// Address of the sprites covering the playfield
|
||||||
.label PLAYFIELD_SPRITES = $2000
|
.label PLAYFIELD_SPRITES = $3000
|
||||||
// Address of the charset
|
// Address of the charset
|
||||||
.label PLAYFIELD_CHARSET = $2800
|
.label PLAYFIELD_CHARSET = $2800
|
||||||
// The Y-position of the first sprite row
|
// The Y-position of the first sprite row
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
(const byte*) PLAYFIELD_CHARSET = (byte*) 10240
|
(const byte*) PLAYFIELD_CHARSET = (byte*) 10240
|
||||||
(const byte*) PLAYFIELD_SCREEN_1 = (byte*) 1024
|
(const byte*) PLAYFIELD_SCREEN_1 = (byte*) 1024
|
||||||
(const byte*) PLAYFIELD_SCREEN_2 = (byte*) 11264
|
(const byte*) PLAYFIELD_SCREEN_2 = (byte*) 11264
|
||||||
(const byte*) PLAYFIELD_SPRITES = (byte*) 8192
|
(const byte*) PLAYFIELD_SPRITES = (byte*) 12288
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_1 = (const byte*) PLAYFIELD_SCREEN_1+(const word) SPRITE_PTRS
|
||||||
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
(const byte*) PLAYFIELD_SPRITE_PTRS_2 = (const byte*) PLAYFIELD_SCREEN_2+(const word) SPRITE_PTRS
|
||||||
(const byte*) PROCPORT = (byte*) 1
|
(const byte*) PROCPORT = (byte*) 1
|
||||||
|
Loading…
Reference in New Issue
Block a user