comments) {
- super(new StatementSource(RuleContext.EMPTY), comments);
+ super(StatementSource.NONE, comments);
this.phiVariables = new ArrayList<>();
}
diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Bank.java b/src/main/java/dk/camelot64/kickc/model/symbols/Bank.java
new file mode 100644
index 000000000..8c2796371
--- /dev/null
+++ b/src/main/java/dk/camelot64/kickc/model/symbols/Bank.java
@@ -0,0 +1,173 @@
+package dk.camelot64.kickc.model.symbols;
+
+/**
+ *
+ * Specific target computer platforms implement a memory layout that can be banked either in ram or rom.
+ * This class models the capability to calculate which function call implementations are banked and which not.
+ *
Since banking implementations are specific to the target computer platform,
+ * specific assembler fragments are available in the compiler,
+ * that model the implementation of the banking, depending on:
+ *
+ *
+ * - the computer target computer platform.
+ * - the bank method of function call implementation at the call location.
+ *
+ *
+ * The method can implement different banking implementations,
+ * depending on the required function call speed,
+ * the banking routine availability in the kernal (rom) of the target computer platform
+ * or even using specific designed banking routines by kickc to provide alternatives for banking methods.
+ * The method and the platform are the key combinations that select the fragments
+ * in kickc to generate the banked function call implementations used by the compiler.
+ *
+ *
Your C-code can be augmented with 3 new directives, that define which function(s) will be declared as banked:
+ *
+ *
+ * - #pragma bank( area, number ) directive, defines for sequent functions
+ * the the area and the bank number.
+ * - A new #pragma nobank( dummy ) directive, resets the calculation of banking
+ * for the sequent functions.
+ * - __bank( area, number ) directive, defines for one function a
+ * target bank area and number.
+ *
+ * Examples of bank areas are different RAM and/or ROM areas at different
+ * zones in the linear memory addressing space, and may or may not overlap.
+ * Each banking area has its own configuration in the target computer platform and
+ * operate independently from each other.
+ * For example, the Commander X16 has 256 RAM bank between 0xA000 and 0xBFFF and
+ * 256 ROM banks from 0xC000 till 0xFFFF. Each RAM bank is configured through zero page $00
+ * and each ROM bank is configured through zero page $01.
+ * The compiler configures for you these registers, depending on the configured banking area of the function,
+ * when a banked call is required.
+ *
+ *
There are different types of function calls that can be implemented, depending on:
+ *
+ * - the banked location of either or both the caller and/or the called function.
+ * - the banking area of either or both the caller and the called function.
+ *
+ *
+ * The types of (banked) function call implementations are:
+ *
+ * - near - jump to subroutine without any implementation of banking logic.
+ * - close - jump to subroutine with inline banking implementation logic.
+ * - far - jump to subroutine using a specific trampoline banking implementation logic.
+ *
+ * Depending on the target platform of the system the far calls are likely the most complex
+ * and will consume the most CPU cycles. Therefore, careful design of the program flow and the
+ * placement of the functions in the banks need to be done, to avoid as much as possible these far calls.
+ *
+ *
The exact rules when near, close and far calls are implemented by the compiler,
+ * can be summarized in the following 6 cases:
+ *
+ *
+ * - case #1 - If the caller function is not banked,
+ * and the called function is not banked,
+ * then a near call will be implemented.
+ * - case #2 - If the caller function is not banked,
+ * and the called function is banked in any bank in any banking area,
+ * then a close call will be implemented.
+ * - case #3 - If the caller function is banked in any bank in any banking area,
+ * and the called function is not banked,
+ * then a near call will be implemented.
+ * - case #4 - If the caller function is banked,
+ * and the called function is banked,
+ * and both functions are in the same bank and in the same bank area,
+ * then a near call will be implemented.
+ * - case #5 - If the caller function is banked,
+ * and the called function is banked,
+ * and both functions are in a different bank but in the same bank area,
+ * then a far call will be implemented.
+ * - case #6 - If the caller function is banked,
+ * and the called function is banked,
+ * and both functions are in any bank but in a different bank area,
+ * then the a close call will be implemented.
+ *
+ *
+ * The usage of #pragma code_seg( segment ) directive
+ * is very important! The #pragma code_seg( segment ) directive utilization
+ * in harmony with the #pragma bank( method, number ) directive
+ * makes the overall banking implementation work for your program.
+ *
+ *
+ *
+ * - KickC uses the #pragma code_seg( segment ) directive to calculate the
+ * addressing of the allocation of the function code within main or banked memory.
+ * - KickC uses the #pragma bank( method, number ) directive or
+ * __bank( method, number ) directive to calculate the function call implementation
+ * at the function calling locations!
+ *
+ *
+ * The KickC compiler contains several test cases and examples which demonstrate the usage of the banking system.
+ *
+ * @param bankArea The bankable area name.
+ * @param bankNumber The bank number.
+ */
+public record Bank(String bankArea, Long bankNumber) {
+
+ /**
+ * Creates a new Bank which collects the necessary data to handle banking.
+ * For example, on the Commander X16, RAM is banked from address 0xA000 till 0xBFFF.
+ * Zeropage 0x00 configures this banked RAM, with a number from 0x00 till 0xff.
+ * So "Banked RAM" is is a bankArea, and the bank is a configurable bank number in the bankArea.
+ *
+ * @param bankArea A bank area is a memory range that is banked on a target platform.
+ * @param bankNumber A bank is a number that defines a bank configuration in a bank area.
+ */
+ public Bank {
+ }
+
+ /** The common/shared bank which is always visible. */
+ public static Bank COMMON = new Bank("", 0L);
+
+ /**
+ * Is this the common/shared bank which is always visible.
+ * @return True if this is the common bank
+ */
+ public boolean isCommon() {
+ return COMMON.equals(this);
+ }
+
+ @Override
+ public String toString() {
+ if(isCommon()) {
+ return "";
+ } else {
+ return "__bank(" + this.bankArea() + ", " + this.bankNumber() + ") ";
+ }
+ }
+
+ /** The bank distance between a caller and callee, which will determine the type of call needed. */
+ public enum CallingDistance {
+ /** Caller and callee are both in the same bank or in the common bank. No bank change is needed. */
+ NEAR,
+ /** Caller is in the common bank or a different banking area. A direct bank change is needed. */
+ CLOSE,
+ /** Caller and callee are different banks of the same banking area. A trampoline bank change is needed. */
+ FAR;
+
+ public static CallingDistance forCall(Bank from, Bank to) {
+ if(to.isCommon()) {
+ // NEAR: call to the common bank
+ return NEAR;
+ } else if(to.equals(from)) {
+ // NEAR: call to the same bank in the same banking area
+ return NEAR;
+ } else if(from.isCommon()) {
+ // CLOSE: call from common bank to any bank
+ return CLOSE;
+ } else if(!from.bankArea().equals(to.bankArea())) {
+ // CLOSE: from one banking area to another
+ return CLOSE;
+ } else {
+ // FAR: banked to different bank in same bank area
+ return FAR;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+
+ }
+}
diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
index ce46bb5f1..0f59f17a3 100644
--- a/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
+++ b/src/main/java/dk/camelot64/kickc/model/symbols/Procedure.java
@@ -33,14 +33,19 @@ public class Procedure extends Scope {
private List comments;
/** Reserved zeropage addresses. */
private List reservedZps;
- /** The code segment to put the procedure into. */
- private String codeSegment;
+ /** The code segment to put the procedure code into. When null the procedure is not assigned to the code segment. */
+ private String segmentCode;
/** The list of constructor procedures for this procedure. The constructor procedures are called during program initialization. */
private final List constructorRefs;
/** Is this procedure declared as a constructor procedure. */
private boolean isConstructor;
/** The source of the procedure definition. */
private StatementSource definitionSource;
+ /**
+ * The bank that the procedure code is placed in.
+ * Used to decide whether to produce near, close or far call code when generating calls.
+ */
+ private Bank bank;
/** The names of all legal intrinsic procedures. */
final public static List INTRINSIC_PROCEDURES = Arrays.asList(
@@ -50,27 +55,42 @@ public class Procedure extends Scope {
Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4
);
+ public Bank getBank() {
+ return bank;
+ }
+
+ public void setBank(Bank bank) {
+ this.bank = Objects.requireNonNull(bank);
+ }
+
/** The method for passing parameters and return value to the procedure. */
public enum CallingConvention {
/** Parameters and return value handled through PHI-transitions. */
- PHI_CALL("__phicall"),
+ PHI_CALL("__phicall", "phi"),
/** Parameters and return value over the stack. */
- STACK_CALL("__stackcall"),
+ STACK_CALL("__stackcall", "stack"),
/** Parameters and return value handled through shared variables. */
- VAR_CALL("__varcall"),
+ VAR_CALL("__varcall", "var"),
/** Intrinsic calling. Will be converted to intrinsic ASM late in the compile. */
- INTRINSIC_CALL("__intrinsiccall");
+ INTRINSIC_CALL("__intrinsiccall", "intrinsic");
private final String name;
- CallingConvention(String name) {
+ private final String shortName;
+
+ CallingConvention(String name, String shortName) {
this.name = name;
+ this.shortName = shortName;
}
public String getName() {
return name;
}
+ public String getShortName() {
+ return shortName;
+ }
+
/** Get a calling convention by name. */
public static CallingConvention getCallingConvension(String name) {
for(CallingConvention value : CallingConvention.values()) {
@@ -85,13 +105,14 @@ public class Procedure extends Scope {
/** The calling convention used for this procedure. */
private CallingConvention callingConvention;
- public Procedure(String name, SymbolTypeProcedure procedureType, Scope parentScope, String codeSegment, String dataSegment, CallingConvention callingConvention) {
- super(name, parentScope, dataSegment);
+ public Procedure(String name, SymbolTypeProcedure procedureType, Scope parentScope, String segmentCode, String segmentData, CallingConvention callingConvention, Bank bank) {
+ super(name, parentScope, segmentData);
this.procedureType = procedureType;
this.declaredInline = false;
+ this.bank = Objects.requireNonNull(bank);
this.interruptType = null;
this.comments = new ArrayList<>();
- this.codeSegment = codeSegment;
+ this.segmentCode = Objects.requireNonNull(segmentCode);
this.callingConvention = callingConvention;
this.constructorRefs = new ArrayList<>();
this.isConstructor = false;
@@ -113,12 +134,12 @@ public class Procedure extends Scope {
this.callingConvention = callingConvention;
}
- public String getCodeSegment() {
- return codeSegment;
+ public String getSegmentCode() {
+ return segmentCode;
}
- public void setCodeSegment(String codeSegment) {
- this.codeSegment = codeSegment;
+ public void setSegmentCode(String segmentCode) {
+ this.segmentCode = segmentCode;
}
public List getParameterNames() {
@@ -262,6 +283,7 @@ public class Procedure extends Scope {
if(declaredIntrinsic) {
res.append("__intrinsic ");
}
+ res.append(bank.toString());
if(!callingConvention.equals(CallingConvention.PHI_CALL)) {
res.append(getCallingConvention().getName()).append(" ");
}
@@ -307,13 +329,14 @@ public class Procedure extends Scope {
Objects.equals(interruptType, procedure.interruptType) &&
Objects.equals(comments, procedure.comments) &&
Objects.equals(reservedZps, procedure.reservedZps) &&
- Objects.equals(codeSegment, procedure.codeSegment) &&
+ Objects.equals(segmentCode, procedure.segmentCode) &&
Objects.equals(constructorRefs, procedure.constructorRefs) &&
+ Objects.equals(bank, procedure.bank) &&
callingConvention == procedure.callingConvention;
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), procedureType, parameterNames, variableLengthParameterList, declaredInline, declaredIntrinsic, interruptType, comments, reservedZps, codeSegment, constructorRefs, isConstructor, callingConvention);
+ return Objects.hash(super.hashCode(), procedureType, parameterNames, variableLengthParameterList, declaredInline, declaredIntrinsic, interruptType, comments, reservedZps, segmentCode, constructorRefs, isConstructor, bank, callingConvention);
}
}
diff --git a/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java b/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java
index ed32ce6ba..a4b6e0736 100644
--- a/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java
+++ b/src/main/java/dk/camelot64/kickc/model/symbols/Scope.java
@@ -30,7 +30,7 @@ public abstract class Scope implements Symbol {
this.name = name;
this.parentScope = parentScope;
this.symbols = new LinkedHashMap<>();
- this.segmentData = segmentData;
+ this.segmentData = Objects.requireNonNull(segmentData);
setFullName();
}
@@ -43,6 +43,10 @@ public abstract class Scope implements Symbol {
return segmentData;
}
+ public void setSegmentData(String segmentData) {
+ this.segmentData = segmentData;
+ }
+
public HashMap getSymbols() {
return symbols;
}
diff --git a/src/main/java/dk/camelot64/kickc/model/values/UnionDesignator.java b/src/main/java/dk/camelot64/kickc/model/values/UnionDesignator.java
new file mode 100644
index 000000000..6811766db
--- /dev/null
+++ b/src/main/java/dk/camelot64/kickc/model/values/UnionDesignator.java
@@ -0,0 +1,40 @@
+package dk.camelot64.kickc.model.values;
+
+import dk.camelot64.kickc.model.Program;
+
+/**
+ * A union designator initializer.
+ */
+public class UnionDesignator implements RValue {
+
+ private final String memberName;
+
+ private final RValue rValue;
+
+ public UnionDesignator(String memberName, RValue rValue) {
+ this.memberName = memberName;
+ this.rValue = rValue;
+ }
+
+ public String getMemberName() { return memberName; }
+
+ public RValue getMemberValue() {
+ return rValue;
+ }
+
+ @Override
+ public String toString(Program program) {
+ StringBuilder out = new StringBuilder();
+ out.append("{ ");
+ out.append(memberName);
+ out.append("=");
+ out.append(rValue.toString(program));
+ out.append(" }");
+ return out.toString();
+ }
+
+ @Override
+ public String toString() {
+ return toString(null);
+ }
+}
diff --git a/src/main/java/dk/camelot64/kickc/parser/CParser.java b/src/main/java/dk/camelot64/kickc/parser/CParser.java
index f56daca13..76b52a81c 100644
--- a/src/main/java/dk/camelot64/kickc/parser/CParser.java
+++ b/src/main/java/dk/camelot64/kickc/parser/CParser.java
@@ -106,6 +106,14 @@ public class CParser {
* The resource-file is copied to the output directory when compiling.
*/
public static final String PRAGMA_RESOURCE = "resource";
+ /**
+ * #pragma bank(...) changes the current bank. Functions and variables will be placed in the specified bank.
+ */
+ public static final String PRAGMA_BANK = "bank";
+ /**
+ * #pragma nobank Changes the current bank to the default/common/shared bank.
+ */
+ public static final String PRAGMA_NOBANK = "nobank";
/**
* The Program.
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
index e7a343ac6..a62082a72 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass0GenerateStatementSequence.java
@@ -16,7 +16,6 @@ import dk.camelot64.kickc.parser.KickCParserBaseVisitor;
import dk.camelot64.kickc.passes.utils.SizeOfConstants;
import org.antlr.v4.runtime.BufferedTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
-import org.antlr.v4.runtime.RuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
@@ -131,12 +130,12 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
+ initProc = new Procedure(SymbolRef.INIT_PROC_NAME, new SymbolTypeProcedure(SymbolType.VOID, new ArrayList<>()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL, Bank.COMMON);
initProc.setDeclaredInline(true);
initProc.setParameters(new ArrayList<>());
program.getScope().add(initProc);
program.createProcedureCompilation(initProc.getRef());
- program.getProcedureCompilation(initProc.getRef()).getStatementSequence().addStatement(new StatementProcedureBegin(initProc.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ program.getProcedureCompilation(initProc.getRef()).getStatementSequence().addStatement(new StatementProcedureBegin(initProc.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
}
return initProc;
}
@@ -180,29 +179,29 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL);
+ final Procedure startProcedure = new Procedure(SymbolRef.START_PROC_NAME, new SymbolTypeProcedure(SymbolType.VOID, new ArrayList<>()), program.getScope(), Scope.SEGMENT_CODE_DEFAULT, Scope.SEGMENT_DATA_DEFAULT, Procedure.CallingConvention.PHI_CALL, Bank.COMMON);
startProcedure.setParameters(new ArrayList<>());
program.getScope().add(startProcedure);
final ProcedureCompilation startProcedureCompilation = program.createProcedureCompilation(startProcedure.getRef());
final StatementSequence startSequence = startProcedureCompilation.getStatementSequence();
- startSequence.addStatement(new StatementProcedureBegin(startProcedure.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementProcedureBegin(startProcedure.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
if(initCompilation != null)
- startSequence.addStatement(new StatementCall(null, SymbolRef.INIT_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementCall(null, SymbolRef.INIT_PROC_NAME, new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
final Procedure mainProc = program.getScope().getLocalProcedure(SymbolRef.MAIN_PROC_NAME);
if(mainProc == null)
throw new CompileError("Required main() not defined in program.");
if(!SymbolType.VOID.equals(mainProc.getReturnType()) && !SymbolType.SWORD.equals(mainProc.getReturnType()))
throw new CompileError("return of main() must be 'void' or of type 'int'.", mainProc.getDefinitionSource());
if(mainProc.getParameterNames().size() == 0) {
- startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, new ArrayList<>(), StatementSource.NONE, Comment.NO_COMMENTS));
} else if(mainProc.getParameterNames().size() == 2) {
final List parameters = mainProc.getParameters();
final Variable argc = parameters.get(0);
@@ -214,15 +213,15 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor params = new ArrayList<>();
params.add(new ConstantInteger(0L, SymbolType.SWORD));
params.add(new ConstantPointer(0L, new SymbolTypePointer(SymbolType.BYTE)));
- startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, params, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementCall(null, SymbolRef.MAIN_PROC_NAME, params, StatementSource.NONE, Comment.NO_COMMENTS));
} else
throw new CompileError("main() has wrong number of parameters. It must have zero or 2 parameters.", mainProc.getDefinitionSource());
final Label startReturnLabel = startProcedure.addLabel(SymbolRef.PROCEXIT_BLOCK_NAME);
- startSequence.addStatement(new StatementLabel(startReturnLabel.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
- startSequence.addStatement(new StatementReturn(null, new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
- startSequence.addStatement(new StatementProcedureEnd(startProcedure.getRef(), new StatementSource(RuleContext.EMPTY), Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementLabel(startReturnLabel.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementReturn(null, StatementSource.NONE, Comment.NO_COMMENTS));
+ startSequence.addStatement(new StatementProcedureEnd(startProcedure.getRef(), StatementSource.NONE, Comment.NO_COMMENTS));
}
}
@@ -289,10 +288,24 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor effectiveDirectives = varDecl.getDeclDirectives();
final List declComments = varDecl.getDeclComments();
varDecl.exitVar();
- VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, false, effectiveType, effectiveDirectives, currentDataSegment, program.getTargetPlatform().getVariableBuilderConfig());
+ VariableBuilder varBuilder = new VariableBuilder(varName, getCurrentScope(), false, false, effectiveType, effectiveDirectives, currentSegmentData, program.getTargetPlatform().getVariableBuilderConfig());
Variable variable = varBuilder.build();
if(isStructMember && (initializer != null))
throw new CompileError("Initializer not supported inside structs " + effectiveType.toCDecl(), declSource);
@@ -1136,7 +1156,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor initValues = new ArrayList<>();
for(KickCParser.ExprContext initializer : ctx.expr()) {
RValue rValue = (RValue) visit(initializer);
- initValues.add(rValue);
- }
+ initValues.add(rValue);
+ }
return new ValueList(initValues);
}
@@ -2003,7 +2040,7 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor memberLValues = ((ValueList) lValue).getList();
- final StructVariableMemberUnwinding structVariableMemberUnwinding = getProgram().getStructVariableMemberUnwinding();
- final StructVariableMemberUnwinding.VariableUnwinding returnVarUnwinding = structVariableMemberUnwinding.getVariableUnwinding(returnVar.getRef());
- for(RValue memberLValue : memberLValues) {
-
- }
- for(int i = 0; i < structMemberVars.size(); i++) {
- final Variable memberVar = structMemberVars.get(i);
- final RValue memberValue = memberLValues.get(i);
- generateCallFinalize(memberValue, memberVar.getType(), source, comments, stmtIt);
- }
- */
}
}
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java b/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java
new file mode 100644
index 000000000..3935b5729
--- /dev/null
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass1FixProcedureParamSegment.java
@@ -0,0 +1,46 @@
+package dk.camelot64.kickc.passes;
+
+import dk.camelot64.kickc.model.Program;
+import dk.camelot64.kickc.model.Registers;
+import dk.camelot64.kickc.model.symbols.Procedure;
+import dk.camelot64.kickc.model.symbols.Scope;
+import dk.camelot64.kickc.model.symbols.Variable;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Ensure banked procedure parameters/return values in main memory are placed in the default data segment.
+ * This is needed to support banking, since it is otherwise impossible to access them across bank boundaries during calls.
+ */
+public class Pass1FixProcedureParamSegment extends Pass2SsaOptimization {
+
+ public Pass1FixProcedureParamSegment(Program program) {
+ super(program);
+ }
+
+ @Override
+ public boolean step() {
+ final Collection allVariables = getScope().getAllVariables(true);
+ for(Variable variable : allVariables) {
+ if(variable.isKindLoadStore() || variable.isKindPhiMaster() || variable.isKindIntermediate()) {
+ if(variable.getRegister() instanceof Registers.RegisterMainMem registerMainMem && registerMainMem.isAddressHardcoded())
+ continue;
+ if(variable.getDataSegment().equals(Scope.SEGMENT_DATA_DEFAULT))
+ continue;
+
+ final Scope scope = variable.getScope();
+ if(scope instanceof Procedure procedure) {
+ if(!procedure.getBank().isCommon()) {
+ List parameters = procedure.getParameters();
+ if(parameters.contains(variable) || variable.getLocalName().equals("return")) {
+ variable.setDataSegment(Scope.SEGMENT_DATA_DEFAULT);
+ getLog().append("Fixing banked procedure parameter/return value to default segment " + variable.getFullName());
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java
index df78a6bb4..bde8b4b30 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass2ConstantInlining.java
@@ -3,9 +3,7 @@ package dk.camelot64.kickc.passes;
import dk.camelot64.kickc.model.Program;
import dk.camelot64.kickc.model.iterator.ProgramValue;
import dk.camelot64.kickc.model.iterator.ProgramValueIterator;
-import dk.camelot64.kickc.model.symbols.ProgramScope;
-import dk.camelot64.kickc.model.symbols.Symbol;
-import dk.camelot64.kickc.model.symbols.Variable;
+import dk.camelot64.kickc.model.symbols.*;
import dk.camelot64.kickc.model.values.*;
import dk.camelot64.kickc.passes.utils.AliasReplacer;
@@ -55,10 +53,14 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
replaceInValues(inline);
// Replace all usages of the constants in the control flow graph or symbol table
replaceVariables(inline);
+ // Remove parameters
+ final Set inlineRefs = inline.keySet();
+ removeParameters(inlineRefs);
// Remove from symbol table
- deleteSymbols(getScope(), inline.keySet());
+ deleteSymbols(getScope(), inlineRefs);
- for(ConstantRef constantRef : inline.keySet()) {
+
+ for(ConstantRef constantRef : inlineRefs) {
getLog().append("Constant inlined " + constantRef.toString() + " = " + inline.get(constantRef).toString(getProgram()));
}
@@ -66,6 +68,30 @@ public class Pass2ConstantInlining extends Pass2SsaOptimization {
}
+ private void removeParameters(Set inlineRefs) {
+ for(ConstantRef inlineRef : inlineRefs) {
+ final Scope scope = getScope().getConstant(inlineRef).getScope();
+ final Procedure procedure = getProcedure(scope);
+ if(procedure!=null) {
+ final List parameters = procedure.getParameters();
+ final boolean modified = parameters.removeIf(param -> param.getRef().equals(inlineRef));
+ if(modified) {
+ procedure.setParameters(parameters);
+ getLog().append("Parameter inlined " + inlineRef.toString());
+ }
+ }
+ }
+ }
+
+ private static Procedure getProcedure(Scope scope) {
+ if(scope instanceof Procedure)
+ return (Procedure) scope;
+ else if(scope instanceof ProgramScope)
+ return null;
+ else
+ return getProcedure(scope.getScope());
+ }
+
/**
* Replace any aliases within the constant values themselves
*
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
index d2f3bc5a1..29000ba0b 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4CodeGeneration.java
@@ -115,7 +115,7 @@ public class Pass4CodeGeneration {
currentScope = block.getScope();
if (block.isProcedureEntry(program)) {
Procedure procedure = block.getProcedure(program);
- currentCodeSegmentName = procedure.getCodeSegment();
+ currentCodeSegmentName = procedure.getSegmentCode();
}
setCurrentSegment(currentCodeSegmentName, asm);
asm.startChunk(currentScope, null, block.getLabel().getFullName());
@@ -219,7 +219,7 @@ public class Pass4CodeGeneration {
}
/**
- * Generate a comment that describes the procedure signature and parameter transfer
+ * Generate a comment that describes the procedure signature and parameter transfer.
*
* @param asm The assembler program being generated
* @param procedure The procedure
@@ -240,6 +240,9 @@ public class Pass4CodeGeneration {
if (i > 0) {
asm.addComment(signature.toString(), false);
}
+ if(!procedure.getBank().isCommon()) {
+ asm.addComment(" " + procedure.getBank(), false);
+ }
}
/**
@@ -853,14 +856,15 @@ public class Pass4CodeGeneration {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.conditionalJump((StatementConditionalJump) statement, block, program), program);
} else if (statement instanceof StatementCall) {
StatementCall call = (StatementCall) statement;
- Procedure procedure = getScope().getProcedure(call.getProcedure());
- if (procedure.isDeclaredIntrinsic()) {
- if (Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4.equals(procedure.getFullName())) {
+ Procedure toProcedure = getScope().getProcedure(call.getProcedure());
+ Procedure fromProcedure = block.getProcedure(this.program); // We obtain from where the procedure is called, to validate the bank equality.
+ if (toProcedure.isDeclaredIntrinsic()) {
+ if (Pass1ByteXIntrinsicRewrite.INTRINSIC_MAKELONG4.equals(toProcedure.getFullName())) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.makelong4(call, program), program);
} else {
- throw new CompileError("Intrinsic procedure not supported " + procedure.toString(program));
+ throw new CompileError("Intrinsic procedure not supported " + toProcedure.toString(program));
}
- } else if (Procedure.CallingConvention.PHI_CALL.equals(procedure.getCallingConvention())) {
+ } else if (Procedure.CallingConvention.PHI_CALL.equals(toProcedure.getCallingConvention())) {
// Generate PHI transition
if (genCallPhiEntry) {
ControlFlowBlock callSuccessor = getGraph().getCallSuccessor(block);
@@ -872,17 +876,44 @@ public class Pass4CodeGeneration {
genBlockPhiTransition(asm, block, callSuccessor, block.getScope());
}
}
- asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
- } else if (Procedure.CallingConvention.STACK_CALL.equals(procedure.getCallingConvention())) {
- asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
+ final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
+ asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
+ } else {
+ AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.callBanked(toProcedure, callingDistance, program), program);
+ }
+ } else if (Procedure.CallingConvention.STACK_CALL.equals(toProcedure.getCallingConvention())) {
+ final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
+ asm.addInstruction("jsr", CpuAddressingMode.ABS, call.getProcedure().getFullName(), false);
+ } else {
+ throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
+ }
}
} else if (statement instanceof StatementCallExecute) {
StatementCallExecute call = (StatementCallExecute) statement;
- RValue procedureRVal = call.getProcedureRVal();
- // Generate ASM for a call
- AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
- if (!(procedureRVal instanceof ProcedureRef)) {
- asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
+ ProcedureRef procedureRef = call.getProcedure();
+ if(procedureRef != null) {
+ ProgramScope scope = getScope();
+ Procedure toProcedure = scope.getProcedure(procedureRef);
+ Procedure fromProcedure = block.getProcedure(this.program);
+ final Bank.CallingDistance callingDistance = Bank.CallingDistance.forCall(fromProcedure.getBank(), toProcedure.getBank());
+ if(Bank.CallingDistance.NEAR.equals(callingDistance)) {
+ AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
+ } else {
+ throw new CompileError("Stack Call procedure not supported in banked mode " + toProcedure.toString(program));
+ }
+ RValue procedureRVal = call.getProcedureRVal();
+ if (!(procedureRVal instanceof ProcedureRef)) {
+ asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
+ }
+ } else {
+ RValue procedureRVal = call.getProcedureRVal();
+ // Generate ASM for a call
+ AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.call(call, indirectCallCount++, program), program);
+ if (!(procedureRVal instanceof ProcedureRef)) {
+ asm.getCurrentChunk().setClobberOverwrite(CpuClobber.CLOBBER_ALL);
+ }
}
} else if (statement instanceof StatementExprSideEffect) {
AsmFragmentCodeGenerator.generateAsm(asm, AsmFragmentInstanceSpecBuilder.exprSideEffect((StatementExprSideEffect) statement, program), program);
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java b/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java
index 65974bb6f..7e26193d8 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4MemoryCoalesce.java
@@ -53,6 +53,7 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
return
canCoalesceNotEqual(ec1, ec2) &&
canCoalesceCompatible(ec1, ec2, program) &&
+ canCoalesceSegments(ec1, ec2, program) &&
canCoalesceVolatile(ec1, ec2, program) &&
canCoalesceThreads(ec1, ec2, threadHeads, program) &&
canCoalesceClobber(ec1, ec2, unknownFragments, program);
@@ -69,6 +70,21 @@ public abstract class Pass4MemoryCoalesce extends Pass2Base {
return !ec1.equals(ec2);
}
+ /**
+ * Determines if two live range equivalence classes are candidates for coalescing by ensuring they are not from different data segments.
+ * @param ec1 One equivalence class
+ * @param ec2 Another equivalence class
+ * @param program The program
+ * @return True if the two equivalence classes can be coalesced into one without problems.
+ */
+ private static boolean canCoalesceSegments(LiveRangeEquivalenceClass ec1, LiveRangeEquivalenceClass ec2, Program program) {
+ final VariableRef variableRef1 = ec1.getVariables().get(0);
+ final String dataSegment1 = program.getScope().getVar(variableRef1).getDataSegment();
+ final VariableRef variableRef2 = ec2.getVariables().get(0);
+ final String dataSegment2 = program.getScope().getVar(variableRef2).getDataSegment();
+ return dataSegment1.equals(dataSegment2);
+ }
+
/**
* Determines if two live range equivalence classes can be coalesced without cross-thread clobber.
* This is possible if they are both only called from the same thread head.
diff --git a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java
index 545eb23e9..59c1a1480 100644
--- a/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java
+++ b/src/main/java/dk/camelot64/kickc/passes/Pass4RegistersFinalize.java
@@ -212,7 +212,7 @@ public class Pass4RegistersFinalize extends Pass2Base {
reserved = false;
int candidateZp = currentZp;
for(int i=0;i pragmaBody = readBody(cTokenSource);
- final Token pragmaBodyStart = pragmaBody.get(0);
// Convert space-based pragma to parenthesis-based for easier parsing
// #pragma NAME XXX YYY \n => #pragma NAME ( XXX , YYY ) \n
- if(pragmaBodyStart.getType() != KickCLexer.PAR_BEGIN) {
+ if(pragmaBody.isEmpty() || pragmaBody.get(0).getType() != KickCLexer.PAR_BEGIN) {
ArrayList parenthesizedBody = new ArrayList<>();
parenthesizedBody.add(new CommonToken(KickCLexer.PAR_BEGIN, "("));
// Parenthesize the parameter list
diff --git a/src/main/kc/include/c128.h b/src/main/kc/include/c128.h
index f23967634..c1dce5163 100644
--- a/src/main/kc/include/c128.h
+++ b/src/main/kc/include/c128.h
@@ -8,3 +8,77 @@
#include
#include
#include
+
+/// Processor port data direction register
+char* const PROCPORT_DDR = (char*)0x00;
+/// Mask for PROCESSOR_PORT_DDR which allows only memory configuration to be written
+const char PROCPORT_DDR_MEMORY_MASK = 0b00000111;
+/// Processor Port Register controlling RAM/ROM configuration and the datasette
+char* const PROCPORT = (char*)0x01;
+/// RAM in all three areas 0xA000, 0xD000, 0xE000
+const char PROCPORT_RAM_ALL = 0b00000000;
+/// RAM in 0xA000, 0xE000 I/O in 0xD000
+const char PROCPORT_RAM_IO = 0b00000101;
+/// RAM in 0xA000, 0xE000 CHAR ROM in 0xD000
+const char PROCPORT_RAM_CHARROM = 0b00000001;
+/// RAM in 0xA000, I/O in 0xD000, KERNEL in 0xE000
+const char PROCPORT_KERNEL_IO = 0b00000110;
+/// BASIC in 0xA000, I/O in 0xD000, KERNEL in 0xE000
+const char PROCPORT_BASIC_KERNEL_IO = 0b00000111;
+
+/// The address of the CHARGEN character set
+char* const CHARGEN = (char*)0xd000;
+/// The SID MOS 6581/8580
+struct MOS6581_SID * const SID = (struct MOS6581_SID *)0xd400;
+/// The VIC-II MOS 6567/6569
+struct MOS6569_VICII* const VICII = (struct MOS6569_VICII*)0xd000;
+/// Color Ram
+char * const COLORRAM = (char*)0xd800;
+/// Color Ram
+char * const COLS = (char*)0xd800;
+
+/// Default address of screen character matrix
+char * const DEFAULT_SCREEN = (char*)0x0400;
+/// Default address of the chargen font (upper case)
+char * const DEFAULT_FONT_UPPER = (char*)0x1000;
+/// Default address of the chargen font (mixed case)
+char * const DEFAULT_FONT_MIXED = (char*)0x1800;
+
+/// The CIA#1: keyboard matrix, joystick #1/#2
+struct MOS6526_CIA * const CIA1 = (struct MOS6526_CIA *)0xdc00;
+/// The CIA#2: Serial bus, RS-232, VIC memory bank
+struct MOS6526_CIA * const CIA2 = (struct MOS6526_CIA *)0xdd00;
+/// CIA#1 Interrupt for reading in ASM
+char * const CIA1_INTERRUPT = (char*)0xdc0d;
+/// CIA#2 timer A&B as one single 32-bit value
+unsigned long* const CIA2_TIMER_AB = (unsigned long*)0xdd04;
+/// CIA#2 Interrupt for reading in ASM
+char * const CIA2_INTERRUPT = (char*)0xdd0d;
+
+/// Pointer to interrupt function
+typedef void (*IRQ_TYPE)(void);
+
+/// The vector used when the KERNAL serves IRQ interrupts
+IRQ_TYPE * const KERNEL_IRQ = (IRQ_TYPE*)0x0314;
+/// The vector used when the KERNAL serves NMI interrupts
+IRQ_TYPE * const KERNEL_NMI = (IRQ_TYPE*)0x0318;
+/// The vector used when the HARDWARE serves IRQ interrupts
+IRQ_TYPE * const HARDWARE_IRQ = (IRQ_TYPE*)0xfffe;
+
+/// The colors of the C64
+const char BLACK = 0x0;
+const char WHITE = 0x1;
+const char RED = 0x2;
+const char CYAN = 0x3;
+const char PURPLE = 0x4;
+const char GREEN = 0x5;
+const char BLUE = 0x6;
+const char YELLOW = 0x7;
+const char ORANGE = 0x8;
+const char BROWN = 0x9;
+const char PINK = 0xa;
+const char DARK_GREY= 0xb;
+const char GREY = 0xc;
+const char LIGHT_GREEN = 0xd;
+const char LIGHT_BLUE = 0xe;
+const char LIGHT_GREY = 0xf;
diff --git a/src/main/kc/include/conio.h b/src/main/kc/include/conio.h
index 269817f16..cb79ae3eb 100644
--- a/src/main/kc/include/conio.h
+++ b/src/main/kc/include/conio.h
@@ -4,7 +4,7 @@
/// Implements similar functions as conio.h from CC65 for compatibility
/// See https://github.com/cc65/cc65/blob/master/include/conio.h
//
-/// Currently C64/PLUS4/VIC20 platforms are supported
+/// Currently CX16/C64/PLUS4/VIC20 platforms are supported
/// clears the screen and moves the cursor to the upper left-hand corner of the screen.
void clrscr(void);
diff --git a/src/main/kc/include/cx16-bitmap.h b/src/main/kc/include/cx16-bitmap.h
index 0584218fe..d0c3482ac 100644
--- a/src/main/kc/include/cx16-bitmap.h
+++ b/src/main/kc/include/cx16-bitmap.h
@@ -4,7 +4,7 @@
/// Currently it can only plot on the first 256 x-positions.
/// Initialize the bitmap plotter tables for a specific bitmap
-void bitmap_init(byte layer, dword address);
+void bitmap_init(unsigned char layer, unsigned char bank, unsigned int offset);
/// Clear all graphics on the bitmap
void bitmap_clear();
diff --git a/src/main/kc/include/cx16-conio.h b/src/main/kc/include/cx16-conio.h
new file mode 100644
index 000000000..ebd65e8a3
--- /dev/null
+++ b/src/main/kc/include/cx16-conio.h
@@ -0,0 +1,6 @@
+#include
+
+// structure to hold operational variables to operate conio for the X16, and make it code efficient.
+
+void screenlayer0();
+void screenlayer1();
\ No newline at end of file
diff --git a/src/main/kc/include/cx16-kernal.h b/src/main/kc/include/cx16-kernal.h
index b815572ba..778aaa422 100644
--- a/src/main/kc/include/cx16-kernal.h
+++ b/src/main/kc/include/cx16-kernal.h
@@ -1,18 +1,21 @@
-/// @file
+/**
+ * @file cx16-kernal.h
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief CBM kernal API dialect and additions to the Commander X16 platform.
+ * Please refer to https://github.com/commanderx16/x16-docs/blob/master/X16%20Reference%20-%2004%20-%20KERNAL.md for the detailed list
+ * of APIs backward compatible with the C64.
+ *
+ * @version 1.0
+ * @date 2023-03-22
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+const unsigned int CX16_SCREEN_SET_CHARSET = 0xFF62; ///< CX16 Set character set.
+const unsigned int CX16_MACPTR = 0xFF44; ///< CX16 Faster loading from SDCARD.
-/// Kernal SETNAM function
-/// SETNAM. Set file name parameters.
-void setnam(char* filename);
+unsigned int cx16_k_macptr(unsigned char bytes, void* buffer);
+void cx16_k_screen_set_charset(char charset, char *offset);
-/// SETLFS. Set file parameters.
-void setlfs(char device);
-
-/// LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.)
-/// - verify: 0 = Load, 1-255 = Verify
-/// Returns a status, 0xff: Success other: Kernal Error Code
-char load(char* address, char verify);
-
-/// GETIN. Read a byte from the input channel
-/// return: next byte in buffer or 0 if buffer is empty.
-char getin();
diff --git a/src/main/kc/include/cx16-mouse.h b/src/main/kc/include/cx16-mouse.h
new file mode 100644
index 000000000..f8f901a3a
--- /dev/null
+++ b/src/main/kc/include/cx16-mouse.h
@@ -0,0 +1,18 @@
+// CX16 CBM Mouse Routines
+const word CX16_MOUSE_CONFIG = 0xFF68; // Mouse pointer configuration.
+const word CX16_MOUSE_SCAN = 0xFF71; // ISR routine to scan the mouse state.
+const word CX16_MOUSE_GET = 0xFF6B; // Get the mouse state;
+
+typedef struct {
+ int x;
+ int y;
+ int px;
+ int py;
+ unsigned char status;
+} cx16_mouse_t;
+
+extern __mem cx16_mouse_t cx16_mouse;
+
+void cx16_mouse_config(char visible, char scalex, char scaley);
+void cx16_mouse_scan();
+char cx16_mouse_get();
diff --git a/src/main/kc/include/cx16-typedefs.h b/src/main/kc/include/cx16-typedefs.h
new file mode 100644
index 000000000..d13d5397b
--- /dev/null
+++ b/src/main/kc/include/cx16-typedefs.h
@@ -0,0 +1,26 @@
+/**
+ * @file cx16.h
+ * @author Sven Van de Velde
+ * @brief Type definitions for the CX16 platform.
+ * @version 0.2
+ * @date 2022-10-13
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#ifndef __CX16__
+#error "Target platform must be cx16"
+#endif
+
+
+typedef void (*IRQ_TYPE)(void); ///< Pointer to interrupt function.
+
+typedef unsigned char bram_bank_t; ///< Represents a bank in banked ram.
+typedef unsigned char brom_bank_t; ///< Represents a bank in banked rom.
+typedef unsigned char vram_bank_t; ///< Represents a bank in vera ram.
+typedef unsigned char* ram_ptr_t; ///< Expresses a pointer to a location in main ram of the CX16..
+typedef unsigned char* bram_ptr_t; ///< Expresses a pointer location in banked ram of the CX16, excluding any bank information!
+typedef unsigned char* brom_ptr_t; ///< Expresses a pointer location in banked rom of the CX16, excluding any bank information!
+typedef unsigned int vram_offset_t; ///< Expresses an offset location in vera ram, excluding any bank information!
+
diff --git a/src/main/kc/include/cx16-vera.h b/src/main/kc/include/cx16-vera.h
index 76115069d..53b2de742 100644
--- a/src/main/kc/include/cx16-vera.h
+++ b/src/main/kc/include/cx16-vera.h
@@ -3,23 +3,9 @@
///
/// https://github.com/commanderx16/x16-docs/blob/master/VERA%20Programmer's%20Reference.md
-/// The colors of the CX16
-const char BLACK = 0x0;
-const char WHITE = 0x1;
-const char RED = 0x2;
-const char CYAN = 0x3;
-const char PURPLE = 0x4;
-const char GREEN = 0x5;
-const char BLUE = 0x6;
-const char YELLOW = 0x7;
-const char ORANGE = 0x8;
-const char BROWN = 0x9;
-const char PINK = 0xa;
-const char DARK_GREY = 0xb;
-const char GREY = 0xc;
-const char LIGHT_GREEN = 0xd;
-const char LIGHT_BLUE = 0xe;
-const char LIGHT_GREY = 0xf;
+// Location of default PETSCII character tiles in the VERA
+unsigned int const VERA_PETSCII_TILE = 0xF800;
+unsigned int const VERA_PETSCII_TILE_SIZE = 0x0800;
/// To access the VRAM (which is 128kB in size) an indirection mechanism is used.
/// First the address to be accessed needs to be set (ADDRx_L/ADDRx_M/ADDRx_H) and
@@ -31,69 +17,69 @@ const char LIGHT_GREY = 0xf;
/// See https://github.com/commanderx16/x16-emulator/wiki/(VERA-0.8)-Registers-$9F23-and-$9F24-(and-$9F25)
/// $9F20 VRAM Address (7:0)
-char * const VERA_ADDRX_L = (char*)0x9f20;
+char* const VERA_ADDRX_L = (char*)0x9f20;
/// $9F21 VRAM Address (15:8)
-char * const VERA_ADDRX_M = (char*)0x9f21;
+char* const VERA_ADDRX_M = (char*)0x9f21;
/// $9F22 VRAM Address (7:0)
/// Bit 4-7: Address Increment The following is the amount incremented per value value:increment
/// 0:0, 1:1, 2:2, 3:4, 4:8, 5:16, 6:32, 7:64, 8:128, 9:256, 10:512, 11:40, 12:80, 13:160, 14:320, 15:640
/// Bit 3: DECR Setting the DECR bit, will decrement instead of increment by the value set by the 'Address Increment' field.
/// Bit 0: VRAM Address (16)
-char * const VERA_ADDRX_H = (char*)0x9f22;
-const char VERA_INC_0 = 0x00;
-const char VERA_INC_1 = 0x10;
-const char VERA_INC_2 = 0x20;
-const char VERA_INC_4 = 0x30;
-const char VERA_INC_8 = 0x40;
-const char VERA_INC_16 = 0x50;
-const char VERA_INC_32 = 0x60;
-const char VERA_INC_64 = 0x70;
-const char VERA_INC_128 = 0x80;
-const char VERA_INC_256 = 0x90;
-const char VERA_INC_512 = 0xa0;
-const char VERA_INC_40 = 0xb0;
-const char VERA_INC_80 = 0xc0;
-const char VERA_INC_160 = 0xd0;
-const char VERA_INC_320 = 0xe0;
-const char VERA_INC_640 = 0xf0;
-const char VERA_DECR_0 = 0x08;
-const char VERA_DECR_1 = 0x18;
-const char VERA_DECR_2 = 0x28;
-const char VERA_DECR_4 = 0x38;
-const char VERA_DECR_8 = 0x48;
-const char VERA_DECR_16 = 0x58;
-const char VERA_DECR_32 = 0x68;
-const char VERA_DECR_64 = 0x78;
-const char VERA_DECR_128 = 0x88;
-const char VERA_DECR_256 = 0x98;
-const char VERA_DECR_512 = 0xa8;
-const char VERA_DECR_40 = 0xb8;
-const char VERA_DECR_80 = 0xc8;
-const char VERA_DECR_160 = 0xd8;
-const char VERA_DECR_320 = 0xe8;
-const char VERA_DECR_640 = 0xf8;
+char* const VERA_ADDRX_H = (char*)0x9f22;
+char const VERA_INC_0 = 0x00;
+char const VERA_INC_1 = 0x10;
+char const VERA_INC_2 = 0x20;
+char const VERA_INC_4 = 0x30;
+char const VERA_INC_8 = 0x40;
+char const VERA_INC_16 = 0x50;
+char const VERA_INC_32 = 0x60;
+char const VERA_INC_64 = 0x70;
+char const VERA_INC_128 = 0x80;
+char const VERA_INC_256 = 0x90;
+char const VERA_INC_512 = 0xa0;
+char const VERA_INC_40 = 0xb0;
+char const VERA_INC_80 = 0xc0;
+char const VERA_INC_160 = 0xd0;
+char const VERA_INC_320 = 0xe0;
+char const VERA_INC_640 = 0xf0;
+char const VERA_DECR_0 = 0x08;
+char const VERA_DECR_1 = 0x18;
+char const VERA_DECR_2 = 0x28;
+char const VERA_DECR_4 = 0x38;
+char const VERA_DECR_8 = 0x48;
+char const VERA_DECR_16 = 0x58;
+char const VERA_DECR_32 = 0x68;
+char const VERA_DECR_64 = 0x78;
+char const VERA_DECR_128 = 0x88;
+char const VERA_DECR_256 = 0x98;
+char const VERA_DECR_512 = 0xa8;
+char const VERA_DECR_40 = 0xb8;
+char const VERA_DECR_80 = 0xc8;
+char const VERA_DECR_160 = 0xd8;
+char const VERA_DECR_320 = 0xe8;
+char const VERA_DECR_640 = 0xf8;
/// $9F23 DATA0 VRAM Data port 0
-char * const VERA_DATA0 = (char*)0x9f23;
+char* const VERA_DATA0 = (char*)0x9f23;
/// $9F24 DATA1 VRAM Data port 1
-char * const VERA_DATA1 = (char*)0x9f24;
+char* const VERA_DATA1 = (char*)0x9f24;
/// $9F25 CTRL Control
/// Bit 7: Reset
/// Bit 1: DCSEL
/// Bit 2: ADDRSEL
-char * const VERA_CTRL = (char*)0x9f25;
-const char VERA_DCSEL = 2;
-const char VERA_ADDRSEL = 1;
+char* const VERA_CTRL = (char*)0x9f25;
+char const VERA_DCSEL = 2;
+char const VERA_ADDRSEL = 1;
/// $9F26 IEN Interrupt Enable
/// Bit 7: IRQ line (8)
/// Bit 3: AFLOW
/// Bit 2: SPRCOL
/// Bit 1: LINE
/// Bit 0: VSYNC
-char * const VERA_IEN = (char*)0x9f26;
-const char VERA_AFLOW = 8;
-const char VERA_SPRCOL = 4;
-const char VERA_LINE = 2;
-const char VERA_VSYNC = 1;
+char* const VERA_IEN = (char*)0x9f26;
+char const VERA_AFLOW = 8;
+char const VERA_SPRCOL = 4;
+char const VERA_LINE = 2;
+char const VERA_VSYNC = 1;
/// $9F27 ISR Interrupt Status
/// Interrupts will be generated for the interrupt sources set in the lower 4 bits of IEN. ISR will indicate the interrupts that have occurred.
/// Writing a 1 to one of the lower 3 bits in ISR will clear that interrupt status. AFLOW can only be cleared by filling the audio FIFO for at least 1/4.
@@ -102,12 +88,12 @@ const char VERA_VSYNC = 1;
/// Bit 2: SPRCOL
/// Bit 1: LINE
/// Bit 0: VSYNC
-char * const VERA_ISR = (char*)0x9f27;
+char* const VERA_ISR = (char*)0x9f27;
/// $9F28 IRQLINE_L IRQ line (7:0)
/// IRQ_LINE specifies at which line the LINE interrupt will be generated.
/// Note that bit 8 of this value is present in the IEN register.
/// For interlaced modes the interrupt will be generated each field and the bit 0 of IRQ_LINE is ignored.
-char * const VERA_IRQLINE_L = (char*)0x9f28;
+char* const VERA_IRQLINE_L = (char*)0x9f28;
/// $9F29 DC_VIDEO (DCSEL=0)
/// Bit 7: Current Field Read-only bit which reflects the active interlaced field in composite and RGB modes. (0: even, 1: odd)
@@ -116,58 +102,61 @@ char * const VERA_IRQLINE_L = (char*)0x9f28;
/// Bit 4: Layer0 Enable Enable output from the Layer0 renderer
/// Bit 2: Chroma Disable Setting 'Chroma Disable' disables output of chroma in NTSC composite mode and will give a better picture on a monochrome display. (Setting this bit will also disable the chroma output on the S-video output.)
/// Bit 0-1: Output Mode 0: Video disabled, 1: VGA output, 2: NTSC composite, 3: RGB interlaced, composite sync (via VGA connector)
-char * const VERA_DC_VIDEO = (char*)0x9f29;
-const char VERA_SPRITES_ENABLE = 0x40;
-const char VERA_LAYER1_ENABLE = 0x20;
-const char VERA_LAYER0_ENABLE = 0x10;
-const char VERA_CROMA_DISABLE = 0x04;
-const char VERA_OUTPUT_DISABLE = 0x00;
-const char VERA_OUTPUT_VGA = 0x01;
-const char VERA_OUTPUT_NTSC = 0x02;
-const char VERA_OUTPUT_RGB = 0x03;
+char* const VERA_DC_VIDEO = (char*)0x9f29;
+char const VERA_SPRITES_ENABLE = 0x40;
+char const VERA_SPRITES_COLLISIONS = 0x04;
+char const VERA_LAYER1_ENABLE = 0x20;
+char const VERA_LAYER0_ENABLE = 0x10;
+char const VERA_CROMA_DISABLE = 0x04;
+char const VERA_OUTPUT_DISABLE = 0x00;
+char const VERA_OUTPUT_VGA = 0x01;
+char const VERA_OUTPUT_NTSC = 0x02;
+char const VERA_OUTPUT_RGB = 0x03;
/// $9F2A DC_HSCALE (DCSEL=0) Active Display H-Scale
-char * const VERA_DC_HSCALE = (char*)0x9f2a;
+char* const VERA_DC_HSCALE = (char*)0x9f2a;
/// $9F2B DC_VSCALE (DCSEL=0) Active Display V-Scale
-char * const VERA_DC_VSCALE = (char*)0x9f2b;
+char* const VERA_DC_VSCALE = (char*)0x9f2b;
/// $9F2C DC_BORDER (DCSEL=0) Border Color
-char * const VERA_DC_BORDER = (char*)0x9f2c;
+char* const VERA_DC_BORDER = (char*)0x9f2c;
/// $9F29 DC_HSTART (DCSEL=1) Active Display H-Start (9:2)
-char * const VERA_DC_HSTART = (char*)0x9f29;
+char* const VERA_DC_HSTART = (char*)0x9f29;
/// $9F2A DC_HSTOP (DCSEL=1) Active Display H-Stop (9:2)
-char * const VERA_DC_HSTOP = (char*)0x9f2a;
+char* const VERA_DC_HSTOP = (char*)0x9f2a;
/// $9F2B DC_VSTART (DCSEL=1) Active Display V-Start (8:1)
-char * const VERA_DC_VSTART = (char*)0x9f2b;
+char* const VERA_DC_VSTART = (char*)0x9f2b;
/// $9F2C DC_VSTOP (DCSEL=1) Active Display V-Stop (8:1)
-char * const VERA_DC_VSTOP = (char*)0x9f2c;
+char* const VERA_DC_VSTOP = (char*)0x9f2c;
/// Configuration work tables
/// Bit 4-5. Map Width (0:32 tiles, 1:64 tiles, 2:128 tiles, 3:256 tiles)
-byte const VERA_LAYER_WIDTH_32 = 0x00;
-byte const VERA_LAYER_WIDTH_64 = 0x10;
-byte const VERA_LAYER_WIDTH_128 = 0x20;
-byte const VERA_LAYER_WIDTH_256 = 0x30;
-byte const VERA_LAYER_WIDTH_MASK = 0x30;
-word const VERA_LAYER_WIDTH[4] = {32, 64, 128, 256};
+char const VERA_LAYER_WIDTH_32 = 0x00;
+char const VERA_LAYER_WIDTH_64 = 0x10;
+char const VERA_LAYER_WIDTH_128 = 0x20;
+char const VERA_LAYER_WIDTH_256 = 0x30;
+char const VERA_LAYER_WIDTH_MASK = 0x30;
+unsigned int const VERA_LAYER_WIDTH[4] = {32, 64, 128, 256};
/// Bit 6-7: Map Height (0:32 tiles, 1:64 tiles, 2:128 tiles, 3:256 tiles)
-byte const VERA_LAYER_HEIGHT_32 = 0x00;
-byte const VERA_LAYER_HEIGHT_64 = 0x40;
-byte const VERA_LAYER_HEIGHT_128 = 0x80;
-byte const VERA_LAYER_HEIGHT_256 = 0xC0;
-byte const VERA_LAYER_HEIGHT_MASK = 0xC0;
-word const VERA_LAYER_HEIGHT[4] = {32, 64, 128, 256};
+char const VERA_LAYER_HEIGHT_32 = 0x00;
+char const VERA_LAYER_HEIGHT_64 = 0x40;
+char const VERA_LAYER_HEIGHT_128 = 0x80;
+char const VERA_LAYER_HEIGHT_256 = 0xC0;
+char const VERA_LAYER_HEIGHT_MASK = 0xC0;
+unsigned int const VERA_LAYER_HEIGHT[4] = {32, 64, 128, 256};
+
+const unsigned int VERA_LAYER_SKIP[4] = {64, 128, 256, 512};
/// Bit 0-1: Color Depth (0: 1 bpp, 1: 2 bpp, 2: 4 bpp, 3: 8 bpp)
-byte const VERA_LAYER_COLOR_DEPTH_1BPP = 0x00;
-byte const VERA_LAYER_COLOR_DEPTH_2BPP = 0x01;
-byte const VERA_LAYER_COLOR_DEPTH_4BPP = 0x02;
-byte const VERA_LAYER_COLOR_DEPTH_8BPP = 0x03;
-byte const VERA_LAYER_COLOR_DEPTH_MASK = 0x03;
-byte const VERA_LAYER_COLOR_DEPTH[4] = {1, 2, 4, 8};
+char const VERA_LAYER_COLOR_DEPTH_1BPP = 0x00;
+char const VERA_LAYER_COLOR_DEPTH_2BPP = 0x01;
+char const VERA_LAYER_COLOR_DEPTH_4BPP = 0x02;
+char const VERA_LAYER_COLOR_DEPTH_8BPP = 0x03;
+char const VERA_LAYER_COLOR_DEPTH_MASK = 0x03;
+char const VERA_LAYER_COLOR_DEPTH[4] = {1, 2, 4, 8};
/// $9F2D L0_CONFIG Layer 0 Configuration
-char * const VERA_L0_CONFIG = (char*)0x9f2d;
+char* const VERA_L0_CONFIG = (char*)0x9f2d;
/// Bit 2: Bitmap Mode (0:tile mode, 1: bitmap mode)
char const VERA_LAYER_CONFIG_MODE_TILE = 0x00;
char const VERA_LAYER_CONFIG_MODE_BITMAP = 0x04;
@@ -175,71 +164,73 @@ char const VERA_LAYER_CONFIG_MODE_BITMAP = 0x04;
char const VERA_LAYER_CONFIG_16C = 0x00;
char const VERA_LAYER_CONFIG_256C = 0x08;
/// $9F2E L0_MAPBASE Layer 0 Map Base Address (16:9)
-char * const VERA_L0_MAPBASE = (char*)0x9f2e;
+char* const VERA_L0_MAPBASE = (char*)0x9f2e;
/// $9F2F L0_TILEBASE Layer 0 Tile Base
/// Bit 2-7: Tile Base Address (16:11)
/// Bit 1: Tile Height (0:8 pixels, 1:16 pixels)
-byte const VERA_TILEBASE_WIDTH_8 = 0x00;
-byte const VERA_TILEBASE_WIDTH_16 = 0x01;
-byte const VERA_TILEBASE_WIDTH_MASK = 0x01;
-byte const VERA_TILEBASE_HEIGHT_8 = 0x00;
-byte const VERA_TILEBASE_HEIGHT_16 = 0x02;
-byte const VERA_TILEBASE_HEIGHT_MASK = 0x02;
-byte const VERA_LAYER_TILEBASE_MASK = 0xfC;
+char const VERA_TILEBASE_WIDTH_8 = 0x00;
+char const VERA_TILEBASE_WIDTH_16 = 0x01;
+char const VERA_TILEBASE_WIDTH_MASK = 0x01;
+char const VERA_TILEBASE_HEIGHT_8 = 0x00;
+char const VERA_TILEBASE_HEIGHT_16 = 0x02;
+char const VERA_TILEBASE_HEIGHT_MASK = 0x02;
+char const VERA_LAYER_TILEBASE_MASK = 0xfC;
/// Bit 0: Tile Width (0:8 pixels, 1:16 pixels)
-char * const VERA_L0_TILEBASE = (char*)0x9f2f;
+char* const VERA_L0_TILEBASE = (char*)0x9f2f;
/// $9F30 L0_HSCROLL_L Layer 0 H-Scroll (7:0)
-char * const VERA_L0_HSCROLL_L = (char*)0x9f30;
+char* const VERA_L0_HSCROLL_L = (char*)0x9f30;
/// $9F31 L0_HSCROLL_H Layer 0 H-Scroll (11:8)
-char * const VERA_L0_HSCROLL_H = (char*)0x9f31;
+char* const VERA_L0_HSCROLL_H = (char*)0x9f31;
/// $9F32 L0_VSCROLL_L Layer 0 V-Scroll (7:0)
-char * const VERA_L0_VSCROLL_L = (char*)0x9f32;
+char* const VERA_L0_VSCROLL_L = (char*)0x9f32;
/// $9F33 L0_VSCROLL_H Layer 0 V-Scroll (11:8)
-char * const VERA_L0_VSCROLL_H = (char*)0x9f33;
+char* const VERA_L0_VSCROLL_H = (char*)0x9f33;
/// $9F34 L1_CONFIG Layer 1 Configuration
-char * const VERA_L1_CONFIG = (char*)0x9f34;
+char* const VERA_L1_CONFIG = (char*)0x9f34;
/// $9F35 L1_MAPBASE Layer 1 Map Base Address (16:9)
-char * const VERA_L1_MAPBASE = (char*)0x9f35;
+char* const VERA_L1_MAPBASE = (char*)0x9f35;
/// $9F36 L1_TILEBASE Layer 1 Tile Base
/// Bit 2-7: Tile Base Address (16:11)
/// Bit 1: Tile Height (0:8 pixels, 1:16 pixels)
/// Bit 0: Tile Width (0:8 pixels, 1:16 pixels)
-char * const VERA_L1_TILEBASE = (char*)0x9f36;
+char* const VERA_L1_TILEBASE = (char*)0x9f36;
/// $9F37 L1_HSCROLL_L Layer 1 H-Scroll (7:0)
-char * const VERA_L1_HSCROLL_L = (char*)0x9f37;
+char* const VERA_L1_HSCROLL_L = (char*)0x9f37;
/// $9F38 L1_HSCROLL_H Layer 1 H-Scroll (11:8)
-char * const VERA_L1_HSCROLL_H = (char*)0x9f38;
+char* const VERA_L1_HSCROLL_H = (char*)0x9f38;
/// $9F39 L1_VSCROLL_L Layer 1 V-Scroll (7:0)
-char * const VERA_L1_VSCROLL_L = (char*)0x9f39;
+char* const VERA_L1_VSCROLL_L = (char*)0x9f39;
/// $9F3A L1_VSCROLL_H Layer 1 V-Scroll (11:8)
-char * const VERA_L1_VSCROLL_H = (char*)0x9f3a;
+char* const VERA_L1_VSCROLL_H = (char*)0x9f3a;
/// $9F3B AUDIO_CTRL
/// Bit 7: FIFO Full / FIFO Reset
/// Bit 5: 16-Bit
/// Bit 4: Stereo
/// Bit 0-3: PCM Volume
-char * const VERA_AUDIO_CTRL = (char*)0x9f3b;
+char* const VERA_AUDIO_CTRL = (char*)0x9f3b;
/// $9F3C AUDIO_RATE PCM Sample Rate
-char * const VERA_AUDIO_RATE = (char*)0x9f3c;
+char* const VERA_AUDIO_RATE = (char*)0x9f3c;
/// $9F3D AUDIO_DATA Audio FIFO data (write-only)
-char * const VERA_AUDIO_DATA = (char*)0x9f3d;
+char* const VERA_AUDIO_DATA = (char*)0x9f3d;
/// $9F3E SPI_DATA SPI Data
-char * const VERA_SPI_DATA = (char*)0x9f3e;
+char* const VERA_SPI_DATA = (char*)0x9f3e;
/// $9F3F SPI_CTRL SPI Control
/// Bit 7: Busy
/// Bit 1: Slow clock
/// Bit 0: Select
-char * const VERA_SPI_CTRL = (char*)0x9f3f;
+char* const VERA_SPI_CTRL = (char*)0x9f3f;
-/// VERA Palette address in VRAM $1FA00 - $1FBFF
-/// 256 entries of 2 bytes
-/// byte 0 bits 4-7: Green
-/// byte 0 bits 0-3: Blue
-/// byte 1 bits 0-3: Red
-const unsigned long VERA_PALETTE = 0x1fa00;
+// VERA Palette address in VRAM $1FA00 - $1FBFF
+// 256 entries of 2 bytes
+// byte 0 bits 4-7: Green
+// byte 0 bits 0-3: Blue
+// byte 1 bits 0-3: Red
+char const VERA_PALETTE_BANK = 0x1;
+char* const VERA_PALETTE_PTR = (char*)0xFA00;
+const unsigned long VERA_PALETTE = 0x1FA00;
/// Sprite Attributes address in VERA VRAM $1FC00 - $1FFFF
-const unsigned long VERA_SPRITE_ATTR = 0x1fc00;
+const unsigned long VERA_SPRITE_ATTR = 0x1FC00;
/// The VERA structure of a sprite (8 bytes)
/// 128*8 bytes located at $1FC00-$1FFFF
@@ -265,7 +256,37 @@ struct VERA_SPRITE {
char CTRL2;
};
-/// 4BPP sprite mode (add to VERA_SPRITE.ADDR to enable)
-const unsigned int VERA_SPRITE_4BPP = 0x0000;
-/// 8BPP sprite mode (add to VERA_SPRITE.ADDR to enable)
-const unsigned int VERA_SPRITE_8BPP = 0x8000;
+// xBPP sprite modes
+#define VERA_SPRITE_4BPP 0x00
+#define VERA_SPRITE_8BPP 0x80
+#define VERA_SPRITE_MASKBPP 0x80
+
+// Sprite flip
+#define VERA_SPRITE_HFLIP 0x01 // Horizontal flip of sprite
+#define VERA_SPRITE_VFLIP 0x02 // Vertical flip of sprite
+#define VERA_SPRITE_NFLIP 0x00 // No flip of sprite
+
+// Sprite ZDepth
+#define VERA_SPRITE_ZDEPTH_DISABLED 0x00
+#define VERA_SPRITE_ZDEPTH_BETWEEN_BACKGROUND_AND_LAYER0 0x04
+#define VERA_SPRITE_ZDEPTH_BETWEEN_LAYER0_AND_LAYER1 0x08
+#define VERA_SPRITE_ZDEPTH_IN_FRONT 0x0C
+#define VERA_SPRITE_ZDEPTH_MASK 0x0C
+
+// Sprite width
+#define VERA_SPRITE_WIDTH_8 0x00
+#define VERA_SPRITE_WIDTH_16 0x10
+#define VERA_SPRITE_WIDTH_32 0x20
+#define VERA_SPRITE_WIDTH_64 0x30
+#define VERA_SPRITE_WIDTH_MASK 0x30
+
+// Sprite height
+#define VERA_SPRITE_HEIGHT_8 0x00
+#define VERA_SPRITE_HEIGHT_16 0x40
+#define VERA_SPRITE_HEIGHT_32 0x80
+#define VERA_SPRITE_HEIGHT_64 0xC0
+#define VERA_SPRITE_HEIGHT_MASK 0xC0
+
+char const VERA_SPRITE_PALETTE_OFFSET_MASK = 0x0F;
+
+char const VERA_SPRITE_COLLISION_MASK = 0xF0;
diff --git a/src/main/kc/include/cx16-veramem.h b/src/main/kc/include/cx16-veramem.h
new file mode 100644
index 000000000..438112433
--- /dev/null
+++ b/src/main/kc/include/cx16-veramem.h
@@ -0,0 +1,50 @@
+// Implements functions for static and dynamic memory management for VERA VRAM memory.
+
+const byte VERA_HEAP_STATIC = 0;
+const byte VERA_HEAP_DYNAMIC = 1;
+
+struct vera_heap {
+ word address;
+ word size;
+ struct vera_heap *next;
+ struct vera_heap *prev;
+};
+
+struct vera_heap_segment {
+ dword size;
+ dword ceil_address;
+ dword next_address;
+ dword base_address;
+ struct vera_heap *head_block;
+ struct vera_heap *tail_block;
+ struct vera_heap *ceil_block;
+};
+
+word const VERA_HEAP_EMPTY = 0x0001;
+word const VERA_HEAP_ADDRESS_16 = 0x0002;
+word const VERA_HEAP_SIZE_16 = 0x0004;
+
+word const VERA_HEAP_SIZE_MASK = 0xFFE0;
+
+// byte vera_block_malloc(dword address, dword size);
+// byte vera_block_free(byte block);
+
+dword vera_heap_segment_init( byte segmentid, dword base, dword size );
+dword vera_heap_segment_ceiling(byte segmentid);
+
+void vera_heap_base_address_set(struct vera_heap_segment *segment, dword base_address);
+void vera_heap_ceil_address_set(struct vera_heap_segment *segment, dword ceil_address);
+dword vera_heap_address(struct vera_heap_segment *segment, dword size);
+dword vera_heap_block_address_get(struct vera_heap *block);
+dword vera_heap_block_size_get(struct vera_heap *block);
+word vera_heap_block_is_empty(struct vera_heap *block);
+void vera_heap_block_address_set(struct vera_heap *block, dword *address);
+void vera_heap_block_size_set(struct vera_heap *block, dword *size);
+void vera_heap_block_empty_set(struct vera_heap *block, byte empty);
+void vera_heap_ram_bank_set(byte ram_bank);
+
+struct vera_heap *vera_heap_block_find(struct vera_heap_segment *segment, struct vera_heap *block);
+struct vera_heap *vera_heap_block_free_find(struct vera_heap_segment *segment, dword size);
+
+dword vera_heap_malloc(byte segmentid, word size);
+dword vera_heap_free(byte segmentid, struct vera_heap *block);
\ No newline at end of file
diff --git a/src/main/kc/include/cx16.h b/src/main/kc/include/cx16.h
index e5ff96098..e8ab9fc8c 100644
--- a/src/main/kc/include/cx16.h
+++ b/src/main/kc/include/cx16.h
@@ -1,39 +1,58 @@
-/// @file
-/// Commander X16
-///
-/// https://www.commanderx16.com/forum/index.php?/about-faq/
-/// https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+/**
+ * @file cx16.h
+ * @author Jesper Gravgaard / Sven Van de Velde
+ * @brief Contains functions to control the features of the Commander X16.
+ * Commander X16 Functions.
+ * https://www.commanderx16.com/forum/index.php?/about-faq/
+ * https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+ * @version 0.2
+ * @date 2022-01-29
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+
+
#ifndef __CX16__
#error "Target platform must be cx16"
#endif
-#include
+
+#include
#include
-/// The VIA#1: ROM/RAM Bank Control
-/// Port A Bits 0-7 RAM bank
-/// Port B Bits 0-2 ROM bank
-/// Port B Bits 3-7 [TBD]
-struct MOS6522_VIA * const VIA1 = (struct MOS6522_VIA *)0x9f60;
-/// The VIA#2: Keyboard/Joy/Mouse
-/// Port A Bit 0 KBD PS/2 DAT
-/// Port A Bit 1 KBD PS/2 CLK
-/// Port A Bit 2 [TBD]
-/// Port A Bit 3 JOY1/2 LATCH
-/// Port A Bit 4 JOY1 DATA
-/// Port A Bit 5 JOY1/2 CLK
-/// Port A Bit 6 JOY2 DATA
-/// Port A Bit 7 [TBD]
-/// Port B Bit 0 MOUSE PS/2 DAT
-/// Port B Bit 1 MOUSE PS/2 CLK
-/// Port B Bits 2-7 [TBD]
-/// NOTE: The pin assignment of the NES/SNES controller is likely to change.
-struct MOS6522_VIA * const VIA2 = (struct MOS6522_VIA *)0x9f70;
+/**
+ * @brief The VIA#1: ROM/RAM Bank Control
+ * Port A Bits 0-7 RAM bank
+ * Port B Bits 0-2 ROM bank
+ * Port B Bits 3-7 [TBD] * * * * *
+ */
+struct MOS6522_VIA * const VIA1 = (struct MOS6522_VIA*)0x9f60;
+
+/**
+ * @brief The VIA#2: Peripherals control
+ * Port A Bit 0 KBD PS/2 DAT
+ * Port A Bit 1 KBD PS/2 CLK
+ * Port A Bit 2 [TBD]
+ * Port A Bit 3 JOY1/2 LATCH
+ * Port A Bit 4 JOY1 DATA
+ * Port A Bit 5 JOY1/2 CLK
+ * Port A Bit 6 JOY2 DATA
+ * Port A Bit 7 [TBD]
+ * Port B Bit 0 MOUSE PS/2 DAT
+ * Port B Bit 1 MOUSE PS/2 CLK
+ * Port B Bits 2-7 [TBD]
+ * kNOTE: The pin assignment of the NES/SNES controller is likely to change.
+ */
+struct MOS6522_VIA * const VIA2 = (struct MOS6522_VIA*)0x9f70;
+
+__export volatile __address(0x00) unsigned char BRAM = 0;
+__export volatile __address(0x01) unsigned char BROM = 4;
/// Interrupt Vectors
/// https://github.com/commanderx16/x16-emulator/wiki/(ASM-Programming)-Interrupts-and-interrupt-handling
-/// Pointer to interrupt function
-typedef void (*IRQ_TYPE)(void);
+// The vector used when the KERNAL serves IRQ interrupts
/// $FFFE (ROM) Universal interrupt vector - The vector used when the HARDWARE serves IRQ interrupts
IRQ_TYPE* const HARDWARE_IRQ = (IRQ_TYPE*)0xfffe;
@@ -42,74 +61,53 @@ IRQ_TYPE* const KERNEL_IRQ = (IRQ_TYPE*)0x0314;
/// $0316 (RAM) BRK vector - The vector used when the KERNAL serves IRQ caused by a BRK
IRQ_TYPE* const KERNEL_BRK = (IRQ_TYPE*)0x0316;
+void cx16_kernal_irq(IRQ_TYPE irq);
+
+byte const CX16_ROM_KERNAL = 0;
+byte const CX16_ROM_BASIC = 4;
/// VRAM Address of the default screen
-char * const DEFAULT_SCREEN = (char*)0x0000;
+vram_offset_t DEFAULT_SCREEN = (vram_offset_t)0xB000;
/// VRAM Bank (0/1) of the default screen
char * const DEFAULT_SCREEN_VBANK = (char*)0;
-/// Put a single byte into VRAM.
-/// Uses VERA DATA0
-/// @param vbank Which 64K VRAM bank to put data into (0/1)
-/// @param vaddr The address in VRAM
-/// @param data The data to put into VRAM
-void vpoke(char vbank, char* vaddr, char data);
-/// Read a single byte from VRAM.
-/// Uses VERA DATA0
-/// @param bank Which 64K VRAM bank to put data into (0/1)
-/// @param addr The address in VRAM
-/// @param returns The data to put into VRAM
-char vpeek(char vbank, char* vaddr);
+/// The colors of the C64
+const char BLACK = 0x0;
+const char WHITE = 0x1;
+const char RED = 0x2;
+const char CYAN = 0x3;
+const char PURPLE = 0x4;
+const char GREEN = 0x5;
+const char BLUE = 0x6;
+const char YELLOW = 0x7;
+const char ORANGE = 0x8;
+const char BROWN = 0x9;
+const char PINK = 0xa;
+const char DARK_GREY= 0xb;
+const char GREY = 0xc;
+const char LIGHT_GREEN = 0xd;
+const char LIGHT_BLUE = 0xe;
+const char LIGHT_GREY = 0xf;
-/// Copy block of memory (from RAM to VRAM)
-/// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM.
-/// @param vbank Which 64K VRAM bank to put data into (0/1)
-/// @param vdest The destination address in VRAM
-/// @param src The source address in RAM
-/// @param num The number of bytes to copy
-void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num );
-/// Copy block of memory (from banked RAM to VRAM)
-/// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM.
-/// @param vdest absolute address in VRAM
-/// @param src absolute address in the banked RAM of the CX16.
-/// @param num dword of the number of bytes to copy
-/// Note: This function can switch RAM bank during copying to copy data from multiple RAM banks.
-void memcpy_bank_to_vram(unsigned long vdest, unsigned long src, unsigned long num );
+inline void bank_push_set_bram(bram_bank_t bank);
+inline void bank_push_bram();
+inline void bank_set_bram(bram_bank_t bank);
+inline void bank_pull_bram();
+inline bram_bank_t bank_get_bram();
+inline bram_ptr_t bank_bram_ptr_inc(char bank, char* sptr, unsigned int inc);
+void bank_set_brom(brom_bank_t bank);
+inline brom_bank_t bank_get_brom();
-/// Copy block of memory (from VRAM to VRAM)
-/// Copies the values from the location pointed by src to the location pointed by dest.
-/// The method uses the VERA access ports 0 and 1 to copy data from and to in VRAM.
-/// @param src_bank 64K VRAM bank number to copy from (0/1).
-/// @param src pointer to the location to copy from. Note that the address is a 16 bit value!
-/// @param src_increment the increment indicator, VERA needs this because addressing increment is automated by VERA at each access.
-/// @param dest_bank 64K VRAM bank number to copy to (0/1).
-/// @param dest pointer to the location to copy to. Note that the address is a 16 bit value!
-/// @param dest_increment the increment indicator, VERA needs this because addressing increment is automated by VERA at each access.
-/// @param num The number of bytes to copy
-void memcpy_in_vram(char dest_bank, void *dest, char dest_increment, char src_bank, void *src, char src_increment, unsigned int num );
+void vpoke(vram_bank_t vbank, vram_offset_t vaddr, char data);
+char vpeek(vram_bank_t vbank, vram_offset_t vaddr);
-/// Set block of memory in VRAM to a value .
-/// Sets num bytes to a value to the memory block pointed to by destination in VRAM.
-/// @param vbank Which 64K VRAM bank to put data into (0/1)
-/// @param vdest The destination address in VRAM
-/// @param data The value to set the vram with.
-/// @param num The number of bytes to set
-void memset_vram(char vbank, void* vdest, char data, unsigned long num );
-
-/// Set block of memory in VRAM to a word value .
-/// Sets num words to a value to the memory block pointed to by destination in VRAM.
-/// @param vbank Which 64K VRAM bank to put data into (0/1)
-/// @param vdest The destination address in VRAM
-/// @param data The value to set the vram with.
-/// @param num The number of bytes to set
-void memset_vram_word(char vbank, void* vdest, unsigned int data, unsigned long num );
-
-/// Load a file into one of the 256 8KB RAM banks.
-/// @param device The device to load from
-/// @param filename The file name
-/// @param address: The absolute address in banked memory to load the file too
-/// @return 0xff: Success, other: Kernal Error Code (https://commodore.ca/manuals/pdfs/commodore_error_messages.pdf)
-/// Note: This function only works if the entire file fits within the selected bank. The function cannot load to multiple banks.
-char load_to_bank( char device, char* filename, unsigned long address);
\ No newline at end of file
+void memcpy_vram_ram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, ram_ptr_t sptr_ram, unsigned int num);
+void memcpy_ram_vram(ram_ptr_t dptr, vram_bank_t sbank_vram, vram_offset_t soffset_vram, unsigned int num);
+void memcpy_vram_bram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, bram_bank_t sbank_bram, bram_ptr_t sptr_bram, unsigned int num);
+void memcpy8_vram_vram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, vram_bank_t sbank_vram, vram_offset_t soffset_vram, unsigned char num8);
+inline void memcpy_vram_bram_fast(vram_bank_t dbank_vram, vram_offset_t doffset_vram, bram_bank_t sbank_bram, bram_ptr_t sptr_bram, unsigned char num);
+void memcpy_vram_vram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, vram_bank_t sbank_vram, vram_offset_t soffset_vram, unsigned int num16);
+void memcpy_vram_vram_inc(vram_bank_t dbank_vram, vram_offset_t doffset_vram, unsigned char dinc, vram_bank_t sbank_vram, vram_offset_t soffset_vram, unsigned char sinc, unsigned int num );
+void memset_vram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, unsigned char data, unsigned int num);
diff --git a/src/main/kc/include/errno.h b/src/main/kc/include/errno.h
new file mode 100644
index 000000000..939f5a0fa
--- /dev/null
+++ b/src/main/kc/include/errno.h
@@ -0,0 +1,17 @@
+/**
+ * @file errno.h
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief Contains the POSIX implementation of errno, which contains the last error detected.
+ * @version 0.1
+ * @date 2023-03-18
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+/// @brief We POSIX standard specifies errno to be an int. We refer to it as part of the header file.
+/// However, for practical purposes we don't keep errno but we keep a char array containing the last meaningful message.
+/// Having the translate the error from errno would be too much memory consuming.
+extern char __errno_error[32];
+
+extern int __errno;
\ No newline at end of file
diff --git a/src/main/kc/include/kernal.h b/src/main/kc/include/kernal.h
new file mode 100644
index 000000000..80934be8a
--- /dev/null
+++ b/src/main/kc/include/kernal.h
@@ -0,0 +1,47 @@
+/**
+ * @file kernal.h
+ * @author your name (you@domain.com)
+ * @brief Most common CBM Kernal calls with it's dialects in the different CBM kernal family platforms.
+ * Please refer to http://sta.c64.org/cbm64krnfunc.html for the list of standard CBM C64 kernal functions.
+ *
+ * @version 1.0
+ * @date 2023-03-22
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+const unsigned int CBM_SETNAM = 0xFFBD; ///< Set the name of a file.
+const unsigned int CBM_SETLFS = 0xFFBA; ///< Set the logical file.
+const unsigned int CBM_OPEN = 0xFFC0; ///< Open the file for the current logical file.
+const unsigned int CBM_CHKIN = 0xFFC6; ///< Set the logical channel for input.
+const unsigned int CBM_READST = 0xFFB7; ///< Check I/O errors.
+const unsigned int CBM_CHRIN = 0xFFCF; ///< Read a character from the current channel for input.
+const unsigned int CBM_GETIN = 0xFFE4; ///< Scan a character from the keyboard.
+const unsigned int CBM_CLOSE = 0xFFC3; ///< Close a logical file.
+const unsigned int CBM_CLRCHN = 0xFFCC; ///< Close all logical files.
+const unsigned int CBM_LOAD = 0xFFD5; ///< Load a logical file.
+const unsigned int CBM_PLOT = 0xFFF0; ///< Set or get current cursor location.
+const unsigned int CBM_CHROUT = 0xFFD2; ///< Output a character.
+
+
+/* inline */ void cbm_k_setlfs(char channel, char device, char command);
+/* inline */ void cbm_k_setnam(char* filename);
+/* inline */ void cbm_k_open();
+/* inline */ void cbm_k_close(char channel);
+/* inline */ unsigned char cbm_k_chkin(char channel);
+/* inline */ unsigned char cbm_k_chrin();
+/* inline */ void cbm_k_clrchn();
+/* inline */ unsigned char cbm_k_getin();
+/* inline */ unsigned char cbm_k_readst();
+/* inline */ unsigned char cbm_k_load(char* address, char verify);
+/* inline */ unsigned int cbm_k_plot_get();
+/* inline */ void cbm_k_plot_set(unsigned char x, unsigned char y);
+/* inline */ void cbm_k_chrout(char c);
+
+
+
+
+#if defined(__CX16__)
+#include
+#endif
diff --git a/src/main/kc/include/pet-kernal.h b/src/main/kc/include/pet-kernal.h
new file mode 100644
index 000000000..03a110c2e
--- /dev/null
+++ b/src/main/kc/include/pet-kernal.h
@@ -0,0 +1,10 @@
+/**
+ * @file pet-kernal.h
+ * @author your name (you@domain.com)
+ * @brief
+ * @version 0.1
+ * @date 2022-12-13
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
\ No newline at end of file
diff --git a/src/main/kc/include/pet.h b/src/main/kc/include/pet.h
new file mode 100644
index 000000000..f096c4fdd
--- /dev/null
+++ b/src/main/kc/include/pet.h
@@ -0,0 +1,32 @@
+/// @file
+/// Commodore 64 Registers and Constants
+#ifndef __PET8032__
+#error "Target platform must be PET"
+#endif
+#include
+#include
+#include
+
+
+/// Default address of screen character matrix
+char * const DEFAULT_SCREEN = (char*)0x8000;
+/// Default address of the chargen font (upper case)
+char * const DEFAULT_FONT_UPPER = (char*)0x1000;
+/// Default address of the chargen font (mixed case)
+char * const DEFAULT_FONT_MIXED = (char*)0x1800;
+
+/// Pointer to interrupt function
+typedef void (*IRQ_TYPE)(void);
+
+/// The vector used when the KERNAL serves IRQ interrupts
+IRQ_TYPE * const KERNEL_IRQ = (IRQ_TYPE*)0x0314;
+/// The vector used when the KERNAL serves NMI interrupts
+IRQ_TYPE * const KERNEL_NMI = (IRQ_TYPE*)0x0318;
+/// The vector used when the HARDWARE serves IRQ interrupts
+IRQ_TYPE * const HARDWARE_IRQ = (IRQ_TYPE*)0xfffe;
+
+/// The colors of the C64
+const char BLACK = 0x0;
+const char WHITE = 0x1;
+
+
diff --git a/src/main/kc/include/stdio.h b/src/main/kc/include/stdio.h
index bf0e98238..dc284b7cb 100644
--- a/src/main/kc/include/stdio.h
+++ b/src/main/kc/include/stdio.h
@@ -2,5 +2,37 @@
/// Functions for performing input and output.
#include
+#include
#include
-#include
\ No newline at end of file
+#include
+
+#if defined(__CX16__) // For the moment only supported for the CX16 ...
+
+ #ifndef __STDIO_FILELEN
+ #define __STDIO_FILELEN 32
+ #endif
+
+ #ifndef __STDIO_ERRORLEN
+ #define __STDIO_ERRORLEN 32
+ #endif
+
+ #ifndef __STDIO_FILECOUNT
+ #define __STDIO_FILECOUNT 4
+ #endif
+
+ typedef struct {
+ char filename[__STDIO_FILECOUNT*__STDIO_FILELEN];
+ char channel[__STDIO_FILECOUNT];
+ char device[__STDIO_FILECOUNT];
+ char secondary[__STDIO_FILECOUNT];
+ char status[__STDIO_FILECOUNT];
+ } FILE;
+
+
+
+ FILE *fopen(const char *path, const char *mode);
+ int fclose(FILE *stream);
+ unsigned int fgets(char *ptr, unsigned int size, FILE *stream);
+ int ferror(FILE *stream);
+ void perror(char* prefix);
+#endif
\ No newline at end of file
diff --git a/src/main/kc/include/string.h b/src/main/kc/include/string.h
index 8cd076d1f..cb78cc204 100644
--- a/src/main/kc/include/string.h
+++ b/src/main/kc/include/string.h
@@ -3,10 +3,12 @@
///
/// Functions to manipulate C strings and arrays.
#include
+#include
/// Copy block of memory (forwards)
/// Copies the values of num chars 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 );
+char* memcpy_fast(char* destination, char* source, unsigned char num );
/// Move block of memory
/// Copies the values of num chars 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.
@@ -14,6 +16,7 @@ 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);
+char* memset_fast(char* str, char c, unsigned char num);
/// Compares the first n bytes of memory area str1 and memory area str2.
/// @param str1 This is the pointer to a block of memory.
@@ -27,6 +30,9 @@ int memcmp(const void *str1, const void *str2, size_t n);
/// 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 );
+/// Concatenates the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
+char* strcat( char* destination, char* source );
+
/// Copies up to n characters from the string pointed to, by src to dest.
/// In a case where the length of src is less than that of n, the remainder of dest will be padded with null bytes.
/// @param dst − This is the pointer to the destination array where the content is to be copied.
@@ -60,4 +66,18 @@ int strcmp(const char *str1, const char *str2);
/// @return if Return value < 0 then it indicates str1 is less than str2.
/// if Return value > 0 then it indicates str2 is less than str1.
/// if Return value = 0 then it indicates str1 is equal to str2.
-int strncmp(const char *str1, const char *str2, size_t n);
\ No newline at end of file
+int strncmp(const char *str1, const char *str2, size_t n);
+
+
+/**
+ * @brief The string-error function, strerror,
+ * is a C/C++ function which translates an error code,
+ * usually stored in the global variable errno,
+ * to a human-readable error message.
+ *
+ * However, the POSIX standard is not followed in kickc. strerror accepts the errno parameter, but it is not used.
+ * Instead strerror returns the last known error.
+ * This is done for performance reasons and pragmatism, not to make error handling too memory intensive.
+ *
+ */
+char* strerror(int errnum);
diff --git a/src/main/kc/lib/conio-c128.c b/src/main/kc/lib/conio-c128.c
new file mode 100644
index 000000000..be02b2733
--- /dev/null
+++ b/src/main/kc/lib/conio-c128.c
@@ -0,0 +1,63 @@
+// Commodore 64 conio.h implementation
+#include
+#include
+
+// The screen width
+#define CONIO_WIDTH 40
+// The screen height
+#define CONIO_HEIGHT 25
+// The text screen address
+#ifndef CONIO_SCREEN_TEXT
+#define CONIO_SCREEN_TEXT DEFAULT_SCREEN
+#endif
+// The color screen address
+#ifndef CONIO_SCREEN_COLORS
+#define CONIO_SCREEN_COLORS COLORRAM
+#endif
+// The default text color
+#ifndef CONIO_TEXTCOLOR_DEFAULT
+#define CONIO_TEXTCOLOR_DEFAULT LIGHT_BLUE
+#endif
+
+// Use the shared CMB flat memory implementation
+#include "conio-cbm-shared.c"
+
+// Initializer for conio.h on C128
+#pragma constructor_for(conio_c128_init, cputc, clrscr, cscroll)
+
+// Set initial cursor position
+void conio_c128_init() {
+ // Position cursor at current line
+ char * const BASIC_CURSOR_LINE = (char*)0xD6;
+ char line = *BASIC_CURSOR_LINE;
+ if(line>=CONIO_HEIGHT) line=CONIO_HEIGHT-1;
+ gotoxy(0, line);
+}
+
+// Return true if there's a key waiting, return false if not
+unsigned char kbhit (void) {
+ // CIA#1 Port A: keyboard matrix columns and joystick #2
+ char* const CIA1_PORT_A = (char*)0xdc00;
+ // CIA#1 Port B: keyboard matrix rows and joystick #1.
+ char* const CIA1_PORT_B = (char*)0xdc01;
+ *CIA1_PORT_A = 0;
+ return ~*CIA1_PORT_B;
+}
+
+// Set the color for the background. The old color setting is returned.
+unsigned char bgcolor(unsigned char color) {
+ // The background color register address
+ char * const CONIO_BGCOLOR = (char*)0xd021;
+ char old = *CONIO_BGCOLOR;
+ *CONIO_BGCOLOR = color;
+ return old;
+}
+
+// Set the color for the border. The old color setting is returned.
+unsigned char bordercolor(unsigned char color) {
+ // The border color register address
+ char * const CONIO_BORDERCOLOR = (char*)0xd020;
+ char old = *CONIO_BORDERCOLOR;
+ *CONIO_BORDERCOLOR = color;
+ return old;
+}
diff --git a/src/main/kc/lib/conio-cbm-shared.c b/src/main/kc/lib/conio-cbm-shared.c
index 9b74bd8b3..05029fb5d 100644
--- a/src/main/kc/lib/conio-cbm-shared.c
+++ b/src/main/kc/lib/conio-cbm-shared.c
@@ -17,8 +17,12 @@ __ma char conio_cursor_x = 0;
__ma char conio_cursor_y = 0;
// The current text cursor line start
__ma char *conio_line_text = CONIO_SCREEN_TEXT;
+
+#ifndef __PET8032__
// The current color cursor line start
__ma char *conio_line_color = CONIO_SCREEN_COLORS;
+#endif
+
// The current text color
__ma char conio_textcolor = CONIO_TEXTCOLOR_DEFAULT;
// Is a cursor whown when waiting for input (0: no, other: yes)
@@ -30,19 +34,27 @@ __ma char conio_scroll_enable = 1;
// clears the screen and moves the cursor to the upper left-hand corner of the screen.
void clrscr(void) {
char* line_text = CONIO_SCREEN_TEXT;
+ #ifndef __PET8032__
char* line_cols = CONIO_SCREEN_COLORS;
+ #endif
for( char l=0;l
-#include
-#include
-
-// The screen width
-#define CONIO_WIDTH conio_screen_width
-// The screen height
-#define CONIO_HEIGHT conio_screen_height
-// The text screen base address, which is a 16:0 bit value in VERA VRAM.
-// That is 128KB addressable space, thus 17 bits in total.
-// CONIO_SCREEN_TEXT contains bits 15:0 of the address.
-// CONIO_SCREEN_BANK contains bit 16, the the 64K memory bank in VERA VRAM (the upper 17th bit).
-// !!! note that these values are not const for the cx16!
-// This conio implements the two layers of VERA, which can be layer 0 or layer 1.
-// Configuring conio to output to a different layer, will change these fields to the address base
-// configured using VERA_L0_MAPBASE = 0x9f2e or VERA_L1_MAPBASE = 0x9f35.
-// Using the function setscreenlayer(layer) will re-calculate using CONIO_SCREEN_TEXT and CONIO_SCREEN_BASE
-// based on the values of VERA_L0_MAPBASE or VERA_L1_MAPBASE, mapping the base address of the selected layer.
-// The function setscreenlayermapbase(layer,mapbase) allows to configure bit 16:9 of the
-// mapbase address of the time map in VRAM of the selected layer VERA_L0_MAPBASE or VERA_L1_MAPBASE.
-char* CONIO_SCREEN_TEXT = DEFAULT_SCREEN;
-char CONIO_SCREEN_BANK = 0; // Default screen of the CX16 emulator uses memory bank 0 for text.
-// The default text color
-#ifndef CONIO_TEXTCOLOR_DEFAULT
-#define CONIO_TEXTCOLOR_DEFAULT WHITE
-#endif
-// The default back color
-#ifndef CONIO_BACKCOLOR_DEFAULT
-#define CONIO_BACKCOLOR_DEFAULT BLUE
-#endif
-
-
-// This requires the following constants to be defined
-// - CONIO_WIDTH - The screen width
-// - CONIO_HEIGHT - The screen height
-// - CONIO_SCREEN_TEXT - The text screen address
-// - CONIO_SCREEN_COLORS - The color screen address
-// - CONIO_TEXTCOLOR_DEFAULT - The default text color
-
-#include
-
-// The number of bytes on the screen
-#define CONIO_BYTES CONIO_HEIGHT*CONIO_WIDTH
-
-// The current cursor x-position
-unsigned byte conio_cursor_x[2] = {0,0};
-// The current cursor y-position
-unsigned byte conio_cursor_y[2] = {0,0};
-// The current text cursor line start
-unsigned word conio_line_text[2] = {0x0000,0x0000};
-// Is a cursor whown when waiting for input (0: no, other: yes)
-__ma unsigned byte conio_display_cursor = 0;
-// Is scrolling enabled when outputting beyond the end of the screen (1: yes, 0: no).
-// If disabled the cursor just moves back to (0,0) instead
-unsigned byte conio_scroll_enable[2] = {1,1};
-// Variable holding the screen width;
-__ma unsigned byte conio_screen_width = 0;
-// Variable holding the screen height;
-__ma unsigned byte conio_screen_height = 0;
-// Variable holding the screen layer on the VERA card with which conio interacts;
-__ma unsigned byte conio_screen_layer = 1;
-
-// Variables holding the current map width and map height of the layer.
-__ma word conio_width = 0;
-__ma word conio_height = 0;
-__ma byte conio_rowshift = 0;
-__ma word conio_rowskip = 0;
-
-// Initializer for conio.h on X16 Commander.
-#pragma constructor_for(conio_x16_init, cputc, clrscr, cscroll)
-
-// Set initial cursor position
-void conio_x16_init() {
- // Position cursor at current line
- char * const BASIC_CURSOR_LINE = (char*)0xD6;
- char line = *BASIC_CURSOR_LINE;
- vera_layer_mode_text(1,(dword)0x00000,(dword)0x0F800,128,64,8,8,16);
- screensize(&conio_screen_width, &conio_screen_height);
- screenlayer(1);
- vera_layer_set_textcolor(1, WHITE);
- vera_layer_set_backcolor(1, BLUE);
- vera_layer_set_mapbase(0,0x20);
- vera_layer_set_mapbase(1,0x00);
- if(line>=CONIO_HEIGHT) line=CONIO_HEIGHT-1;
- gotoxy(0, line);
-}
-
-// Return true if there's a key waiting, return false if not
-unsigned char kbhit(void) {
-
- char ch = 0;
- char* const chptr = &ch;
-
- char* const IN_DEV = (char*)$028A; // Current input device number
- char* const GETIN = (char*)$FFE4; // CBM GETIN API
-
- kickasm(uses chptr, uses IN_DEV, uses GETIN) {{
-
- jsr _kbhit
- bne L3
-
- jmp continue1
-
- .var via1 = $9f60 //VIA#1
- .var d1pra = via1+1
-
- _kbhit:
- ldy d1pra // The count of keys pressed is stored in RAM bank 0.
- stz d1pra // Set d1pra to zero to access RAM bank 0.
- lda $A00A // Get number of characters from this address in the ROM of the CX16 (ROM 38).
- sty d1pra // Set d1pra to previous value.
- rts
-
- L3:
- ldy IN_DEV // Save current input device
- stz IN_DEV // Keyboard
- phy
- jsr GETIN // Read char, and return in .A
- ply
- sta chptr // Store the character read in ch
- sty IN_DEV // Restore input device
- ldx #>$0000
- rts
-
- continue1:
- nop
- }}
-
- return ch;
-}
-
-// clears the screen and moves the cursor to the upper left-hand corner of the screen.
-void clrscr(void) {
- char* line_text = CONIO_SCREEN_TEXT;
- char color = ( vera_layer_get_backcolor(conio_screen_layer) << 4 ) | vera_layer_get_textcolor(conio_screen_layer);
- for( char l=0;lCONIO_HEIGHT) y = 0;
- if(x>=CONIO_WIDTH) x = 0;
- conio_cursor_x[conio_screen_layer] = x;
- conio_cursor_y[conio_screen_layer] = y;
- unsigned int line_offset = (unsigned int)y << conio_rowshift;
- conio_line_text[conio_screen_layer] = line_offset;
-}
-
-// Return the current screen size.
-void screensize(unsigned byte* x, unsigned byte* y) {
- // VERA returns in VERA_DC_HSCALE the value of 128 when 80 columns is used in text mode,
- // and the value of 64 when 40 columns is used in text mode.
- // Basically, 40 columns mode in the VERA is a double scan mode.
- // Same for the VERA_DC_VSCALE mode, but then the subdivision is 60 or 30 rows.
- // I still need to test the other modes, but this will suffice for now for the pure text modes.
- char hscale = (*VERA_DC_HSCALE) >> 7;
- *x = 40 << hscale;
- char vscale = (*VERA_DC_VSCALE) >> 7;
- *y = 30 << vscale;
- //printf("%u, %u\n", *x, *y);
-}
-
-// Return the current screen size X width.
-inline unsigned byte screensizex() {
- return conio_screen_width;
-}
-
-// Return the current screen size Y height.
-inline unsigned byte screensizey() {
- return conio_screen_height;
-}
-
-// Return the X position of the cursor
-inline unsigned byte wherex(void) {
- return conio_cursor_x[conio_screen_layer];
-}
-
-// Return the Y position of the cursor
-inline unsigned byte wherey(void) {
- return conio_cursor_y[conio_screen_layer];
-}
-
-// Output one character at the current cursor position
-// Moves the cursor forward. Scrolls the entire screen if needed
-void cputc(char c) {
- char color = vera_layer_get_color( conio_screen_layer);
- char* conio_addr = CONIO_SCREEN_TEXT + conio_line_text[conio_screen_layer];
-
- conio_addr += conio_cursor_x[conio_screen_layer] << 1;
- if(c=='\n') {
- cputln();
- } else {
- // Select DATA0
- *VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
- *VERA_ADDRX_L = BYTE0(conio_addr);
- *VERA_ADDRX_M = BYTE1(conio_addr);
- *VERA_ADDRX_H = CONIO_SCREEN_BANK | VERA_INC_1;
- *VERA_DATA0 = c;
- *VERA_DATA0 = color;
-
- conio_cursor_x[conio_screen_layer]++;
- byte scroll_enable = conio_scroll_enable[conio_screen_layer];
- if(scroll_enable) {
- if(conio_cursor_x[conio_screen_layer] == CONIO_WIDTH)
- cputln();
- } else {
- if((unsigned int)conio_cursor_x[conio_screen_layer] == conio_width)
- cputln();
- }
- }
-}
-
-// Print a newline
-void cputln() {
- // TODO: This needs to be optimized! other variations don't compile because of sections not available!
- word temp = conio_line_text[conio_screen_layer];
- temp += conio_rowskip;
- conio_line_text[conio_screen_layer] = temp;
- conio_cursor_x[conio_screen_layer] = 0;
- conio_cursor_y[conio_screen_layer]++;
- cscroll();
-}
-
-void clearline() {
- // Select DATA0
- *VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
- byte* addr = CONIO_SCREEN_TEXT + conio_line_text[conio_screen_layer];
- *VERA_ADDRX_L = BYTE0(addr);
- *VERA_ADDRX_M = BYTE1(addr);
- *VERA_ADDRX_H = VERA_INC_1;
- char color = vera_layer_get_color( conio_screen_layer);
- for( unsigned int c=0;c0; i--) {
- unsigned int line = (conio_cursor_y[conio_screen_layer] + i - 1) << conio_rowshift;
- unsigned char* start = CONIO_SCREEN_TEXT + line;
- memcpy_in_vram(0, start+conio_rowskip, VERA_INC_1, 0, start, VERA_INC_1, width);
- }
- clearline();
-}
-
-// Insert a new line, and scroll the upper part of the screen up.
-void insertup() {
- unsigned byte cy = conio_cursor_y[conio_screen_layer];
- unsigned byte width = CONIO_WIDTH * 2;
- for(unsigned byte i=1; i<=cy; i++) {
- unsigned int line = (i-1) << conio_rowshift;
- unsigned char* start = CONIO_SCREEN_TEXT + line;
- memcpy_in_vram(0, start, VERA_INC_1, 0, start+conio_rowskip, VERA_INC_1, width);
- }
- clearline();
-}
-
-// Scroll the entire screen if the cursor is beyond the last line
-void cscroll() {
- if(conio_cursor_y[conio_screen_layer]>=CONIO_HEIGHT) {
- if(conio_scroll_enable[conio_screen_layer]) {
- insertup();
- gotoxy( 0, CONIO_HEIGHT-1);
- } else {
- if(conio_cursor_y[conio_screen_layer]>=conio_height) {
- //gotoxy(0,0);
- }
- }
- }
-}
-
-
-// Output a NUL-terminated string at the current cursor position
-void cputs(const char* s) {
- char c;
- while(c=*s++)
- cputc(c);
-}
-
-// Move cursor and output one character
-// Same as "gotoxy (x, y); cputc (c);"
-void cputcxy(unsigned byte x, unsigned byte y, char c) {
- gotoxy(x, y);
- cputc(c);
-}
-
-// Move cursor and output a NUL-terminated string
-// Same as "gotoxy (x, y); puts (s);"
-void cputsxy(unsigned byte x, unsigned byte y, const char* s) {
- gotoxy(x, y);
- cputs(s);
-}
-
-// If onoff is 1, a cursor is displayed when waiting for keyboard input.
-// If onoff is 0, the cursor is hidden when waiting for keyboard input.
-// The function returns the old cursor setting.
-unsigned byte cursor(unsigned byte onoff) {
- char old = conio_display_cursor;
- conio_display_cursor = onoff;
- return old;
-}
-
-// If onoff is 1, scrolling is enabled when outputting past the end of the screen
-// If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0)
-// The function returns the old scroll setting.
-unsigned byte scroll(unsigned byte onoff) {
- char old = conio_scroll_enable[conio_screen_layer];
- conio_scroll_enable[conio_screen_layer] = onoff;
- return old;
-}
-
-// --- Defined in cx16.c and cx16-vera.h ---
-
-// --- layer management in VERA ---
-
-// Set the layer with which the conio will interact.
-// - layer: value of 0 or 1.
-void screenlayer(unsigned byte layer) {
- conio_screen_layer = layer;
- CONIO_SCREEN_BANK = vera_layer_get_mapbase_bank(conio_screen_layer);
- CONIO_SCREEN_TEXT = (char*)vera_layer_get_mapbase_offset(conio_screen_layer);
- conio_width = vera_layer_get_width(conio_screen_layer);
- conio_rowshift = vera_layer_get_rowshift(conio_screen_layer);
- conio_rowskip = vera_layer_get_rowskip(conio_screen_layer);
- conio_height = vera_layer_get_height(conio_screen_layer);
-}
-
-
-// Set the front color for text output. The old front text color setting is returned.
-// - color: a 4 bit value ( decimal between 0 and 15).
-// This will only work when the VERA is in 16 color mode!
-// Note that on the VERA, the transparent color has value 0.
-inline char textcolor(char color) {
- return vera_layer_set_textcolor(conio_screen_layer, color);
-}
-
-// Set the back color for text output. The old back text color setting is returned.
-// - color: a 4 bit value ( decimal between 0 and 15).
-// This will only work when the VERA is in 16 color mode!
-// Note that on the VERA, the transparent color has value 0.
-inline char bgcolor(char color) {
- return vera_layer_set_backcolor(conio_screen_layer, color);
-}
-
-// Set the color for the border. The old color setting is returned.
-char bordercolor(unsigned char color) {
- // The border color register address
- char old = *VERA_DC_BORDER;
- *VERA_DC_BORDER = color;
- return old;
-}
-
diff --git a/src/main/kc/lib/conio.c b/src/main/kc/lib/conio.c
index c0e3c8823..fc3e7fe70 100644
--- a/src/main/kc/lib/conio.c
+++ b/src/main/kc/lib/conio.c
@@ -7,6 +7,8 @@
#if defined(__C64__)
#include "conio-c64.c"
+#elif defined(__C128__)
+#include "conio-c128.c"
#elif defined(__PLUS4__)
#include "conio-plus4.c"
#elif defined(__VIC20__)
@@ -18,7 +20,9 @@
#elif defined(__ATARIXL__)
#include "conio-atarixl.c"
#elif defined(__CX16__)
-#include "conio-cx16.c"
+#include "cx16-conio.c"
+#elif defined(__PET8032__)
+#include "pet-conio.c"
#else
#error "Target platform does not support conio.h"
#endif
diff --git a/src/main/kc/lib/cx16-bitmap.c b/src/main/kc/lib/cx16-bitmap.c
index 475f5ae42..d7750bc91 100644
--- a/src/main/kc/lib/cx16-bitmap.c
+++ b/src/main/kc/lib/cx16-bitmap.c
@@ -1,120 +1,159 @@
// Plot and line drawing routines for HIRES bitmaps
// Currently it can only plot on the first 256 x-positions.
+#include
#include
#include
#include
-// Tables for the plotter - initialized by calling bitmap_draw_init();
-const word __bitmap_plot_x[640];
-const dword __bitmap_plot_y[480];
-const byte __bitmap_plot_bitmask[640];
-const byte __bitmap_plot_bitshift[640];
+typedef struct {
+ // Tables for the plotter - initialized by calling bitmap_draw_init();
+ unsigned int plot_x[640];
+ unsigned long plot_y[480];
+ unsigned char plot_bitmask[640];
+ unsigned char plot_bitshift[640];
-__ma dword __bitmap_address = 0;
-__ma byte __bitmap_layer = 0;
-__ma byte __bitmap_hscale = 0;
-__ma byte __bitmap_vscale = 0;
-__ma byte __bitmap_color_depth = 0;
+ unsigned long address;
+ unsigned char layer;
+ unsigned char hscale;
+ unsigned char vscale;
+ unsigned char color_depth;
+} bitmap_t;
-word hdeltas[16] = {
+bitmap_t __bitmap;
+
+
+unsigned int hdeltas[16] = {
0, 80, 40, 20, // 1 BPP
0, 160, 80, 40, // 2 BPP
0, 320, 160, 80, // 4 BPP
0, 640, 320, 160 // 8 BPP
};
-const word vdeltas[4] = {0, 480, 240, 160};
-const byte bitmasks[5] = {$80, $C0, $F0, $FF};
-const signed byte bitshifts[5] = {7, 6, 4, 0};
+const unsigned int vdeltas[4] = {0, 480, 240, 160};
+const unsigned char bitmasks[5] = {0x80, 0xC0, 0xF0, 0xFF};
+const signed char bitshifts[5] = {7, 6, 4, 0};
+
+
+unsigned char bitmap_hscale()
+{
+ unsigned char hscale[4] = {0,128,64,32};
+ unsigned char scale = 0;
+ for(char s=1;s<=3;s++) {
+ if(*VERA_DC_HSCALE==hscale[s]) {
+ scale = s;
+ break;
+ }
+ }
+ return scale;
+}
+
+unsigned char bitmap_vscale()
+{
+ unsigned char vscale[4] = {0,128,64,32};
+ unsigned char scale = 0;
+ for(char s=1;s<=3;s++) {
+ if(*VERA_DC_VSCALE==vscale[s]) {
+ scale = s;
+ break;
+ }
+ }
+ return scale;
+}
// Initialize the bitmap plotter tables for a specific bitmap
-void bitmap_init(byte layer, dword address) {
- __bitmap_address = address;
- __bitmap_layer = layer;
- __bitmap_color_depth = vera_layer_get_color_depth(__bitmap_layer);
- __bitmap_hscale = vera_display_get_hscale(); // Returns 1 when 640 and 2 when 320.
- __bitmap_vscale = vera_display_get_vscale(); // Returns 1 when 480 and 2 when 240.
+void bitmap_init(unsigned char layer, unsigned char bank, unsigned int offset)
+{
+ __bitmap.address = MAKELONG(offset, bank);
+ __bitmap.layer = layer;
+ if(layer) {
+ __bitmap.color_depth = (*VERA_L1_CONFIG & VERA_LAYER_COLOR_DEPTH_MASK);
+ } else {
+ __bitmap.color_depth = (*VERA_L0_CONFIG & VERA_LAYER_COLOR_DEPTH_MASK);
+ }
+ __bitmap.hscale = bitmap_hscale(); // Returns 1 when 640 and 2 when 320, 3 when 160.
+ __bitmap.vscale = bitmap_vscale(); // Returns 1 when 480 and 2 when 240, 3 when 160.
- byte bitmask = bitmasks[__bitmap_color_depth];
- signed byte bitshift = bitshifts[__bitmap_color_depth];
+ unsigned char bitmask = bitmasks[__bitmap.color_depth];
+ signed char bitshift = bitshifts[__bitmap.color_depth];
- for(word x : 0..639) {
+ for(unsigned int x=0; x<630; x++) {
// 1 BPP
- if(__bitmap_color_depth==0) {
- __bitmap_plot_x[x] = (x >> 3);
- __bitmap_plot_bitmask[x] = bitmask;
- __bitmap_plot_bitshift[x] = (byte)bitshift;
+ if(__bitmap.color_depth==0) {
+ __bitmap.plot_x[x] = (x >> 3);
+ __bitmap.plot_bitmask[x] = bitmask;
+ __bitmap.plot_bitshift[x] = (unsigned char)bitshift;
bitshift -= 1;
bitmask >>= 1;
}
// 2 BPP
- if(__bitmap_color_depth==1) {
- __bitmap_plot_x[x] = (x >> 2);
- __bitmap_plot_bitmask[x] = bitmask;
- __bitmap_plot_bitshift[x] = (byte)bitshift;
+ if(__bitmap.color_depth==1) {
+ __bitmap.plot_x[x] = (x >> 2);
+ __bitmap.plot_bitmask[x] = bitmask;
+ __bitmap.plot_bitshift[x] = (unsigned char)bitshift;
bitshift -= 2;
bitmask >>= 2;
}
// 4 BPP
- if(__bitmap_color_depth==2) {
- __bitmap_plot_x[x] = (x >> 1);
- __bitmap_plot_bitmask[x] = bitmask;
- __bitmap_plot_bitshift[x] = (byte)bitshift;
+ if(__bitmap.color_depth==2) {
+ __bitmap.plot_x[x] = (x >> 1);
+ __bitmap.plot_bitmask[x] = bitmask;
+ __bitmap.plot_bitshift[x] = (unsigned char)bitshift;
bitshift -= 4;
bitmask >>= 4;
}
// 8 BPP
- if(__bitmap_color_depth==3) {
- __bitmap_plot_x[x] = x;
- __bitmap_plot_bitmask[x] = bitmask;
- __bitmap_plot_bitshift[x] = (byte)bitshift;
+ if(__bitmap.color_depth==3) {
+ __bitmap.plot_x[x] = x;
+ __bitmap.plot_bitmask[x] = bitmask;
+ __bitmap.plot_bitshift[x] = (unsigned char)bitshift;
}
if(bitshift<0) {
- bitshift = bitshifts[__bitmap_color_depth];
+ bitshift = bitshifts[__bitmap.color_depth];
}
if(bitmask==0) {
- bitmask = bitmasks[__bitmap_color_depth];
+ bitmask = bitmasks[__bitmap.color_depth];
}
}
// This sets the right delta to skip a whole line based on the scale, depending on the color depth.
- word hdelta = hdeltas[(__bitmap_color_depth<<2)+__bitmap_hscale];
- // We start at the bitmap address; The plot_y contains the bitmap address embedded so we know where a line starts.
- dword yoffs = __bitmap_address;
- for(word y : 0..479) {
- __bitmap_plot_y[y] = yoffs;
+ unsigned int hdelta = hdeltas[(__bitmap.color_depth<<2)+__bitmap.hscale];
+ // We start at the bitmap offset; The plot_y contains the bitmap offset embedded so we know where a line starts.
+ unsigned long yoffs = __bitmap.address;
+ for(unsigned int y=0; y<479; y++) {
+ __bitmap.plot_y[y] = yoffs;
yoffs = yoffs + hdelta;
}
}
// Clear all graphics on the bitmap
void bitmap_clear() {
- byte bitmask = bitmasks[__bitmap_color_depth];
- word vdelta = vdeltas[__bitmap_vscale];
- word hdelta = hdeltas[(__bitmap_color_depth<<2)+__bitmap_hscale];
- dword count = mul16u(hdelta,vdelta);
- char vbank = BYTE2(__bitmap_address);
- void* vdest = (void*) WORD0(__bitmap_address);
- memset_vram(vbank, vdest, 0, count);
+ unsigned char bitmask = bitmasks[__bitmap.color_depth];
+ unsigned int vdelta = vdeltas[__bitmap.vscale];
+ unsigned int hdelta = hdeltas[(__bitmap.color_depth<<2)+__bitmap.hscale];
+ hdelta = hdelta >> 1;
+ unsigned int count = (unsigned int)mul16u(hdelta,vdelta);
+ vram_bank_t vbank = BYTE3(__bitmap.address);
+ vram_offset_t vdest = WORD0(__bitmap.address);
+ memset_vram(vbank, vdest, 0, count); // TODO: check this out if it still works properly.
}
-void bitmap_plot(word x, word y, byte c) {
+void bitmap_plot(unsigned int x, unsigned int y, unsigned char c) {
// Needs unsigned int arrays arranged as two underlying char arrays to allow char* plotter_x = plot_x[x]; - and eventually - char* plotter = plot_x[x] + plot_y[y];
- dword plot_x = __bitmap_plot_x[x];
- dword plot_y = __bitmap_plot_y[y];
- dword plotter = plot_x+plot_y;
- byte bitshift = __bitmap_plot_bitshift[x];
+ unsigned long plot_x = __bitmap.plot_x[x];
+ unsigned long plot_y = __bitmap.plot_y[y];
+ unsigned long plotter = plot_x+plot_y;
+ unsigned char bitshift = __bitmap.plot_bitshift[x];
c = bitshift?c<<(bitshift):c;
- vera_vram_address0(plotter,VERA_INC_0);
- *VERA_DATA0 = (*VERA_DATA0 & ~__bitmap_plot_bitmask[x]) | c;
+ vera_vram_data0_address(plotter,VERA_INC_0);
+ *VERA_DATA0 = (*VERA_DATA0 & ~__bitmap.plot_bitmask[x]) | c;
}
// Draw a line on the bitmap
-void bitmap_line(word x0, word x1, word y0, word y1, byte c) {
- word xd;
- word yd;
+void bitmap_line(unsigned int x0, unsigned int x1, unsigned int y0, unsigned int y1, unsigned char c) {
+ unsigned int xd;
+ unsigned int yd;
if(x0>1;
+void bitmap_line_xdyi(unsigned int x, unsigned int y, unsigned int x1, unsigned int xd, unsigned int yd,unsigned char c) {
+ unsigned int e = yd>>1;
do {
bitmap_plot(x,y,c);
x++;
@@ -165,8 +204,8 @@ void bitmap_line_xdyi(word x, word y, word x1, word xd, word yd,byte c) {
} while (x!=(x1+1));
}
-void bitmap_line_xdyd(word x, word y, word x1, word xd, word yd, byte c) {
- word e = yd>>1;
+void bitmap_line_xdyd(unsigned int x, unsigned int y, unsigned int x1, unsigned int xd, unsigned int yd, unsigned char c) {
+ unsigned int e = yd>>1;
do {
bitmap_plot(x,y,c);
x++;
@@ -178,8 +217,8 @@ void bitmap_line_xdyd(word x, word y, word x1, word xd, word yd, byte c) {
} while (x!=(x1+1));
}
-void bitmap_line_ydxi(word y, word x, word y1, word yd, word xd, byte c) {
- word e = xd>>1;
+void bitmap_line_ydxi(unsigned int y, unsigned int x, unsigned int y1, unsigned int yd, unsigned int xd, unsigned char c) {
+ unsigned int e = xd>>1;
do {
bitmap_plot(x,y,c);
y++;
@@ -191,8 +230,8 @@ void bitmap_line_ydxi(word y, word x, word y1, word yd, word xd, byte c) {
} while (y!=(y1+1));
}
-void bitmap_line_ydxd(word y, word x, word y1, word yd, word xd, byte c) {
- word e = xd>>1;
+void bitmap_line_ydxd(unsigned int y, unsigned int x, unsigned int y1, unsigned int yd, unsigned int xd, unsigned char c) {
+ unsigned int e = xd>>1;
do {
bitmap_plot(x,y,c);
y = y++;
diff --git a/src/main/kc/lib/cx16-conio.c b/src/main/kc/lib/cx16-conio.c
new file mode 100644
index 000000000..a237dc257
--- /dev/null
+++ b/src/main/kc/lib/cx16-conio.c
@@ -0,0 +1,390 @@
+/**
+ * @file cx16-conio.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief conio for the cx16. These methods allow to print and get information from the console.
+ *
+ * Important notes:
+ *
+ * - There is a pre-compile option __CONIO_BSOUT which if set,
+ * will output every conio operation to the standard output using the kernal API BSOUT,
+ * instead of directly posting to the vera. This is useful to log information in the emulator terminal while running.
+ *
+ * @version 0.1
+ * @date 2022-10-15
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#define CONIO_TEXTCOLOR_DEFAULT WHITE // The default text color
+#define CONIO_BACKCOLOR_DEFAULT BLUE // The default back color
+
+typedef struct {
+ unsigned char cursor_x; ///< current cursor x-position
+ unsigned char cursor_y; ///< current cursor y-position
+ unsigned char layer;
+ unsigned int mapbase_offset; // Base pointer to the tile map base of the conio screen.
+ char mapbase_bank; // Default screen of the CX16 emulator uses memory bank 0 for text.
+
+ unsigned char width; ///< the screen width;
+ unsigned char height; ///< the screen height;
+ unsigned char mapwidth; ///< the map width;
+ unsigned char mapheight; ///< the map height;
+ unsigned int rowskip; ///< the amount of vram bytes needed to skip a row.
+ unsigned char cursor; ///< is a cursor whown when waiting for input (0: no, other: yes)
+ unsigned char color; ///< color of the foreground and background
+ unsigned char bordercolor; ///< color of the border
+ /// Is scrolling enabled when outputting beyond the end of the screen (1: yes, 0: no).
+ /// If disabled the cursor just moves back to (0,0) instead
+ unsigned char scroll[2];
+ unsigned char hscroll[2];
+ unsigned int offset; ///< The current offset
+ unsigned int offsets[61]; ///< Calculated offsets per line according the mapbase and the row width (scale).
+} cx16_conio_t;
+
+cx16_conio_t __conio;
+
+
+/// Initializer for conio.h on X16 Commander.
+#pragma constructor_for(conio_x16_init, cputc, clrscr, cscroll)
+
+/// Set initial screen values.
+void conio_x16_init() {
+
+ screenlayer1();
+
+ textcolor(CONIO_TEXTCOLOR_DEFAULT);
+ bgcolor(CONIO_BACKCOLOR_DEFAULT);
+
+ cursor(0);
+
+ __conio.cursor_x = BYTE1(cbm_k_plot_get());
+ __conio.cursor_y = BYTE0(cbm_k_plot_get());
+ gotoxy(__conio.cursor_x, __conio.cursor_y);
+
+ __conio.scroll[0] = 1;
+ __conio.scroll[1] = 1;
+}
+
+// Returns a value if a key is pressed.
+inline unsigned char kbhit(void)
+{
+ cbm_k_clrchn();
+ return cbm_k_getin();
+}
+
+// clears the screen and moves the cursor to the upper left-hand corner of the screen.
+void clrscr(void)
+{
+ unsigned int line_text = __conio.mapbase_offset;
+
+ *VERA_CTRL &= ~VERA_ADDRSEL;
+ *VERA_ADDRX_H = __conio.mapbase_bank | VERA_INC_1;
+
+ unsigned char l = __conio.mapheight;
+ do {
+ unsigned int ch = line_text;
+ // Set address
+ *VERA_ADDRX_L = BYTE0(ch);
+ *VERA_ADDRX_M = BYTE1(ch);
+
+ unsigned char c = __conio.mapwidth;
+ do{
+ *VERA_DATA0 = ' ';
+ *VERA_DATA0 = __conio.color;
+ c--;
+ } while(c);
+
+ line_text += __conio.rowskip;
+ l--;
+ } while(l);
+
+ __conio.cursor_x = 0;
+ __conio.cursor_y = 0;
+ __conio.offset = __conio.mapbase_offset;
+}
+
+// Set the cursor to the specified position
+void gotoxy(unsigned char x, unsigned char y)
+{
+#ifndef __CONIO_BSOUT
+ __conio.cursor_x = (x>=__conio.width)?__conio.width:x;
+ __conio.cursor_y = (y>=__conio.height)?__conio.height:y;
+ __conio.offset = __conio.offsets[y] + __conio.cursor_x << 1;
+#endif
+}
+
+// Return the current screen size.
+void screensize(unsigned char* x, unsigned char* y) {
+ // VERA returns in VERA_DC_HSCALE the value of 128 when 80 columns is used in text mode,
+ // and the value of 64 when 40 columns is used in text mode.
+ // Basically, 40 columns mode in the VERA is a double scan mode.
+ // Same for the VERA_DC_VSCALE mode, but then the subdivision is 60 or 30 rows.
+ // I still need to test the other modes, but this will suffice for now for the pure text modes.
+ char hscale = (*VERA_DC_HSCALE) >> 7;
+ *x = (40 << hscale)-1;
+ char vscale = (*VERA_DC_VSCALE) >> 7;
+ *y = (30 << vscale)-1;
+ //printf("%u, %u\n", *x, *y);
+}
+
+// Return the current screen size x width.
+unsigned char screensizex() {
+ return __conio.width;
+}
+
+// Return the current screen size y height.
+unsigned char screensizey() {
+ return __conio.height;
+}
+
+// Return the x position of the cursor
+unsigned char wherex(void) {
+ return __conio.cursor_x;
+}
+
+// Return the y position of the cursor
+unsigned char wherey(void) {
+ return __conio.cursor_y;
+}
+
+// Output one character at the current cursor position
+// Moves the cursor forward. Scrolls the entire screen if needed
+void cputc(char c) {
+
+ if(c=='\n') {
+ cputln();
+ } else {
+
+#ifdef __CONIO_BSOUT
+ cbm_k_plot_set(0,0);
+ cbm_k_chrout(c);
+#endif
+
+#ifndef __CONIO_BSOUT
+ *VERA_CTRL &= ~VERA_ADDRSEL;
+ *VERA_ADDRX_L = BYTE0(__conio.offset);
+ *VERA_ADDRX_M = BYTE1(__conio.offset);
+ *VERA_ADDRX_H = __conio.mapbase_bank | VERA_INC_1;
+ *VERA_DATA0 = c;
+ *VERA_DATA0 = __conio.color;
+#endif
+ if(!__conio.hscroll[__conio.layer]) {
+ if(__conio.cursor_x >= __conio.width)
+ cputln();
+ else {
+ __conio.cursor_x++;
+ __conio.offset++;
+ __conio.offset++;
+ }
+ } else {
+ if(__conio.cursor_x >= __conio.mapwidth)
+ cputln();
+ else
+ __conio.cursor_x++;
+ __conio.offset++;
+ __conio.offset++;
+ }
+ }
+}
+
+// Print a newline
+void cputln() {
+ __conio.cursor_x = 0;
+ __conio.cursor_y++;
+ __conio.offset = __conio.offsets[__conio.cursor_y];
+ if(__conio.scroll[__conio.layer]) {
+ cscroll();
+ }
+#ifdef __CONIO_BSOUT
+ cbm_k_plot_set(0,0);
+ cbm_k_chrout(13);
+#endif
+}
+
+void clearline() {
+#ifndef __CONIO_BSOUT
+ unsigned int addr = __conio.offsets[__conio.cursor_y];
+ *VERA_CTRL &= ~VERA_ADDRSEL;
+ *VERA_ADDRX_L = BYTE0(addr);
+ *VERA_ADDRX_M = BYTE1(addr);
+ *VERA_ADDRX_H = __conio.mapbase_bank | VERA_INC_1;
+ register unsigned char c=__conio.width;
+ do {
+ *VERA_DATA0 = ' ';
+ *VERA_DATA0 = __conio.color;
+ c--;
+ } while(c);
+#endif
+}
+
+// Insert a new line, and scroll the lower part of the screen down.
+void insertdown(unsigned char rows) {
+ if(__conio.cursor_y>=0 && __conio.cursor_y <=__conio.height-1) {
+#ifndef __CONIO_BSOUT
+ // {asm{.byte $db}}
+ unsigned char width = (__conio.width+1) * 2;
+ for(unsigned char y=__conio.height - __conio.cursor_y + 1; y>__conio.cursor_y; y--) {
+ memcpy8_vram_vram(__conio.mapbase_bank, __conio.offsets[y], __conio.mapbase_bank, __conio.offsets[y-1], width);
+ }
+ clearline();
+#endif
+ }
+}
+
+// Insert a new line, and scroll the upper part of the screen up.
+void insertup(unsigned char rows) {
+#ifndef __CONIO_BSOUT
+ // {asm{.byte $db}}
+ unsigned char width = (__conio.width+1) * 2;
+ for(unsigned char y=0; y<__conio.cursor_y; y++) {
+ memcpy8_vram_vram(__conio.mapbase_bank, __conio.offsets[y], __conio.mapbase_bank, __conio.offsets[y+1], width);
+ }
+ clearline();
+#endif
+}
+
+// Scroll the entire screen if the cursor is beyond the last line
+void cscroll() {
+#ifndef __CONIO_BSOUT
+ if(__conio.cursor_y>__conio.height) {
+ if(__conio.scroll[__conio.layer]) {
+ insertup(1);
+ gotoxy( 0, __conio.height);
+ clearline();
+ } else {
+ if(__conio.cursor_y>__conio.height) {
+ gotoxy(0,0);
+ }
+ }
+ }
+#endif
+}
+
+
+// Output a NUL-terminated string at the current cursor position
+void cputs(const char* s) {
+#ifndef __CONIO_BSOUT
+ char c;
+ while(c=*s++)
+ cputc(c);
+#endif
+}
+
+// Move cursor and output one character
+// Same as "gotoxy (x, y); cputc (c);"
+void cputcxy(unsigned char x, unsigned char y, char c) {
+#ifndef __CONIO_BSOUT
+ gotoxy(x, y);
+ cputc(c);
+#endif
+}
+
+// Move cursor and output a NUL-terminated string
+// Same as "gotoxy (x, y); puts (s);"
+void cputsxy(unsigned char x, unsigned char y, const char* s) {
+#ifndef __CONIO_BSOUT
+ gotoxy(x, y);
+ cputs(s);
+#endif
+}
+
+// If onoff is 1, a cursor is displayed when waiting for keyboard input.
+// If onoff is 0, the cursor is hidden when waiting for keyboard input.
+// The function returns the old cursor setting.
+unsigned char cursor(unsigned char onoff) {
+ // not supported in CX16
+ char old = __conio.cursor;
+ __conio.cursor = onoff;
+ return old;
+}
+
+// If onoff is 1, scrolling is enabled when outputting past the end of the screen
+// If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0)
+// The function returns the old scroll setting.
+unsigned char scroll(unsigned char onoff) {
+ char old = __conio.scroll[__conio.layer];
+ __conio.scroll[__conio.layer] = onoff;
+ return old;
+}
+
+// If onoff is 1, scrolling is enabled when outputting past the end of the screen
+// If onoff is 0, scrolling is disabled and the cursor instead moves to (0,0)
+// The function returns the old scroll setting.
+unsigned char hscroll(unsigned char onoff) {
+ char old = __conio.hscroll[__conio.layer];
+ __conio.hscroll[__conio.layer] = onoff;
+ return old;
+}
+
+// --- Defined in cx16.c and cx16-vera.h ---
+
+// --- layer management in VERA ---
+
+
+
+void screenlayer(char layer, char mapbase, char config)
+{
+ unsigned char const VERA_LAYER_DIM[4] = {31, 63, 127, 255};
+ unsigned int const VERA_LAYER_SKIP[4] = {64, 128, 256, 512};
+
+ __mem char vera_dc_hscale_temp = *VERA_DC_HSCALE;
+ __mem char vera_dc_vscale_temp = *VERA_DC_VSCALE;
+
+ __conio.layer = 0;
+ __conio.mapbase_bank = mapbase >> 7;
+ __conio.mapbase_offset = MAKEWORD((mapbase)<<1,0);
+ __conio.mapwidth = VERA_LAYER_DIM[ (config & VERA_LAYER_WIDTH_MASK) >> 4];
+ __conio.mapheight = VERA_LAYER_DIM[ (config & VERA_LAYER_HEIGHT_MASK) >> 6];
+ // __conio.rowshift = ((config & VERA_LAYER_WIDTH_MASK)>>4)+6;
+ __conio.rowskip = VERA_LAYER_SKIP[(config & VERA_LAYER_WIDTH_MASK)>>4];
+ __conio.width = (40 << (char)(vera_dc_hscale_temp == 0x80))-1;
+ __conio.height = (30 << (char)(vera_dc_vscale_temp == 0x80))-1;
+
+ unsigned int mapbase_offset = __conio.mapbase_offset;
+ for(register char y=0; y<=__conio.height; y++) {
+ __conio.offsets[y] = mapbase_offset;
+ mapbase_offset += __conio.rowskip;
+ }
+}
+
+// Set the layer with which the conio will interact.
+// - layer: value of 0 or 1.
+void screenlayer0() {
+ screenlayer(0, *VERA_L0_MAPBASE, *VERA_L0_CONFIG);
+}
+
+
+// Set the layer with which the conio will interact.
+void screenlayer1() {
+ screenlayer(1, *VERA_L1_MAPBASE, *VERA_L1_CONFIG);
+}
+
+
+// Set the front color for text output. The old front text color setting is returned.
+// - color: a 4 bit value ( decimal between 0 and 15).
+// This will only work when the VERA is in 16 color mode!
+// Note that on the VERA, the transparent color has value 0.
+char textcolor(char color) {
+ return __conio.color = __conio.color & 0xF0 | color;
+}
+
+// Set the back color for text output.
+// - color: a 4 bit value ( decimal between 0 and 15).
+// This will only work when the VERA is in 16 color mode!
+// Note that on the VERA, the transparent color has value 0.
+char bgcolor(char color) {
+ return __conio.color = __conio.color & 0x0F | color << 4;
+}
+
+// Set the color for the border.
+char bordercolor(unsigned char color) {
+ return __conio.bordercolor = *VERA_DC_BORDER;
+}
+
diff --git a/src/main/kc/lib/cx16-kernal.c b/src/main/kc/lib/cx16-kernal.c
index 45cb67928..9bdbbb140 100644
--- a/src/main/kc/lib/cx16-kernal.c
+++ b/src/main/kc/lib/cx16-kernal.c
@@ -1,62 +1,67 @@
+/**
+ * @file cx16-kernal.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief
+ * Please refer to http://sta.c64.org/cbm64krnfunc.html for the list of standard CBM C64 kernal functions.
+ * Please refer to https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md for the detailed list
+ * of APIs backward compatible with the C64.
+
+ * @version 0.1
+ * @date 2022-01-29
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include
#include
-#include
-// Kernal SETNAM function
-// SETNAM. Set file name parameters.
-void setnam(char* filename) {
- char filename_len = (char)strlen(filename);
- asm {
- // Kernal SETNAM function
- // SETNAM. Set file name parameters.
- // Input: A = File name length; X/Y = Pointer to file name.
- lda filename_len
- ldx filename
- ldy filename+1
- jsr $ffbd
- }
+
+/**
+ * @brief Read a number of bytes from the sdcard using kernal macptr call.
+ * BRAM bank needs to be set properly before the load between adressed A000 and BFFF.
+ *
+ * @return x the size of bytes read
+ * @return y the size of bytes read
+ * @return if carry is set there is an error
+ */
+unsigned int cx16_k_macptr(unsigned char bytes, void* buffer)
+{
+ unsigned int bytes_read;
+ {asm {
+ lda bytes
+ ldx buffer
+ ldy buffer+1
+
+ clc // needed from R42 of the CX16 commander rom to ensure MACPTR is progressing the read address.
+ // .byte $db
+ jsr CX16_MACPTR
+ stx bytes_read
+ sty bytes_read+1
+ bcc !+
+ lda #$FF
+ sta bytes_read
+ sta bytes_read+1
+ !:
+ }}
+ return bytes_read;
}
-// SETLFS. Set file parameters.
-void setlfs(char device) {
- asm {
- // SETLFS. Set file parameters.
- // Input: A = Logical number; X = Device number; Y = Secondary address.
- ldx device
- lda #1
- ldy #0
- jsr $ffba
- }
-}
-// LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.)
-// - verify: 0 = Load, 1-255 = Verify
-//
-// Returns a status, 0xff: Success other: Kernal Error Code
-char load(char* address, char verify) {
- char status;
- asm {
- //LOAD. Load or verify file. (Must call SETLFS and SETNAM beforehands.)
- // Input: A: 0 = Load, 1-255 = Verify; X/Y = Load address (if secondary address = 0).
- // Output: Carry: 0 = No errors, 1 = Error; A = KERNAL error code (if Carry = 1); X/Y = Address of last byte loaded/verified (if Carry = 0).
- ldx address
- ldy address+1
- lda verify
- jsr $ffd5
- bcs error
- lda #$ff
- error:
- sta status
- }
- return status;
-}
-// GETIN. Read a byte from the input channel
-// return: next byte in buffer or 0 if buffer is empty.
-char getin() {
- char ch;
- asm {
- jsr $ffe4
- sta ch
- }
- return ch;
+/**
+ * @brief Sets the [character set](https://github.com/commanderx16/x16-docs/blob/master/X16%20Reference%20-%2004%20-%20KERNAL.md#function-name-screen_set_charset).
+ *
+ * @param charset The code of the charset to copy.
+ * @param offset The offset of the character set in ram.
+ */
+inline void cx16_k_screen_set_charset(char charset, char *offset) {
+
+
+ {asm {
+ lda charset
+ ldx offset
+ jsr CX16_SCREEN_SET_CHARSET
+ }}
}
diff --git a/src/main/kc/lib/cx16-mouse.c b/src/main/kc/lib/cx16-mouse.c
new file mode 100644
index 000000000..bb9a4b133
--- /dev/null
+++ b/src/main/kc/lib/cx16-mouse.c
@@ -0,0 +1,94 @@
+/**
+ * @file cx16-mouse.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief See documentation of the [mouse pointer](https://github.com/commanderx16/x16-docs/blob/master/X16%20Reference%20-%2004%20-%20KERNAL.md#mouse) in the commander X16 manual:
+ *
+ * @note Compatible ONLY with the commander X16 version R39 ROM.
+ *
+ * @version 0.1
+ * @date 2022-03-31
+ *
+ * @copyright Copyright (c) 2022
+ *
+ */
+
+#include
+
+// The mouse work area.
+
+__mem cx16_mouse_t cx16_mouse;
+
+/**
+ * @brief Configures the mouse pointer.
+ *
+ *
+ * @param visible Turn the mouse pointer on or off. Provide a value of 0xFF to set your own mouse pointer graphic (sprite 0).
+ * @param scalex Specify x axis screen resolution in 8 pixel increments.
+ * @param scaley Specify y axis screen resolution in 8 pixel increments.
+ *
+ */
+void cx16_mouse_config(char visible, char scalex, char scaley)
+{
+ asm {
+ //.byte $db
+ lda visible
+ ldx scalex
+ ldy scaley
+ jsr CX16_MOUSE_CONFIG
+ }
+}
+
+/**
+ * @brief Scan the mouse
+ *
+ */
+void cx16_mouse_scan()
+{
+ asm {
+ // .byte $db
+ jsr CX16_MOUSE_SCAN
+ }
+}
+
+/**
+ * @brief Retrieves the status of the mouse pointer and will fill the mouse position in the defined mouse registers.
+ *
+ * @return char Current mouse status.
+ *
+ * The pre-defined variables cx16_mousex and cx16_mousey contain the position of the mouse pointer.
+ *
+ * volatile int cx16_mousex = 0;
+ * volatile int cx16_mousey = 0;
+ *
+ * The state of the mouse buttons is returned:
+ *
+ * |Bit|Description|
+ * |---|-----------|
+ * |0|Left Button|
+ * |1|Right Button|
+ * |2|Middle Button|
+ *
+ * If a button is pressed, the corresponding bit is set.
+ */
+char cx16_mouse_get()
+{
+ __mem char status;
+ __address(0xfc) int x;
+ __address(0xfe) int y;
+
+ cx16_mouse.px = cx16_mouse.x;
+ cx16_mouse.py = cx16_mouse.y;
+
+ asm {
+ // .byte $db
+ ldx #$fc
+ jsr CX16_MOUSE_GET
+ sta status
+ }
+
+ cx16_mouse.x = x;
+ cx16_mouse.y = y;
+ cx16_mouse.status = status;
+
+ return status;
+}
diff --git a/src/main/kc/lib/cx16.c b/src/main/kc/lib/cx16.c
index a994da477..c8c1e1ed1 100644
--- a/src/main/kc/lib/cx16.c
+++ b/src/main/kc/lib/cx16.c
@@ -1,35 +1,230 @@
-// Commander X16 Functions
-// https://www.commanderx16.com/forum/index.php?/about-faq/
-// https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+
+/**
+ * @file cx16.c
+ * @author Jesper Gravgaard / Sven Van de Velde
+ * @brief Contains functions to control the features of the Commander X16.
+ * Commander X16 Functions.
+ * https://www.commanderx16.com/forum/index.php?/about-faq/
+ * https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+ * @version 0.1
+ * @date 2021-06-13
+ *
+ * @copyright Copyright (c) 2021
+ *
+ */
+
+#ifndef __CX16__
+#error "Target platform must be cx16"
+#endif
#include
-#include
+#include
+#include
+#include
+
+// Initializer for X16 Commander interrupt vector
+#pragma constructor_for(cx16_init, cx16_kernal_irq)
+
+__mem __export word isr_vsync = 0x0314;
+
+void cx16_init()
+{
+ isr_vsync = *(word *)0x0314;
+}
+
+void cx16_kernal_irq(IRQ_TYPE irq)
+{
+ *KERNEL_IRQ = irq;
+}
+
+/**
+ * @brief Push the old bank on the stack and set the active bank of banked ram on the X16.
+ * Banked ram is the memory location between 0xA000 and 0xBFFF.
+ *
+ * @param bank Switch to this bank.
+ */
+inline void bank_push_set_bram(bram_bank_t bank)
+{
+ asm {
+ lda $00
+ pha
+ }
+ BRAM = bank;
+}
+
+/**
+ * @brief Set the active bank of banked ram on the X16.
+ * Banked ram is the memory location between 0xA000 and 0xBFFF.
+ *
+ * @param bank Switch to this bank.
+ */
+inline void bank_set_bram(bram_bank_t bank)
+{
+ BRAM = bank;
+}
+
+/**
+ * @brief Set the active bank of banked ram on the X16.
+ * Banked ram is the memory location between 0xA000 and 0xBFFF.
+ * The old bank is pushed on the stack, and must be retrieved with bank_pop_bram!!!
+ *
+ * @param bank Switch to this bank.
+ */
+inline void bank_push_bram()
+{
+ asm {
+ lda $00
+ pha
+ }
+}
+
+/**
+ * @brief Get the active bank of banked ram on the X16.
+ * Banked ram is the memory location between 0xA000 and 0xBFFF.
+ *
+ * @return unsigned char The current active bank.
+ */
+inline unsigned char bank_get_bram()
+{
+ return BRAM;
+}
+
+/**
+ * @brief Get the old bank of banked ram on the X16 from the stack.
+ * Banked ram is the memory location between 0xA000 and 0xBFFF.
+ * The old bank was set with bank_push_bram()!!!
+ */
+inline void bank_pull_bram()
+{
+ asm {
+ pla
+ sta $00
+ }
+}
+
+/**
+ * @brief Set the active banked rom on the X16.
+ *
+ * There are several banked roms available between 0xC000 and 0xFFFF.
+ *
+ * Bank Name Description
+ * 0 KERNAL character sets (uploaded into VRAM), MONITOR, KERNAL
+ * 1 KEYBD Keyboard layout tables
+ * 2 CBDOS The computer-based CBM-DOS for FAT32 SD cards
+ * 3 GEOS GEOS KERNAL
+ * 4 BASIC BASIC interpreter
+ * 5 MONITOR Machine Language Monitor
+ *
+ * Detailed documentation in the CX16 programmers reference:
+ * https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+ *
+ * Note: This method will change when R39 is released,
+ * as the bank is modified using zero page 0x01, instead of the VIA.
+ *
+ * @param bank Switch to this bank.
+ */
+inline void bank_set_brom(brom_bank_t bank)
+{
+ BROM = bank;
+}
+
+/**
+ * @brief Get the active banked rom on the X16.
+ * There are several banked roms available between 0xC000 and 0xFFFF.
+ *
+ * Bank Name Description
+ * 0 KERNAL character sets (uploaded into VRAM), MONITOR, KERNAL
+ * 1 KEYBD Keyboard layout tables
+ * 2 CBDOS The computer-based CBM-DOS for FAT32 SD cards
+ * 3 GEOS GEOS KERNAL
+ * 4 BASIC BASIC interpreter
+ * 5 MONITOR Machine Language Monitor
+ *
+ * Detailed documentation in the CX16 programmers reference:
+ * https://github.com/commanderx16/x16-docs/blob/master/Commander%20X16%20Programmer's%20Reference%20Guide.md
+ *
+ * Note: This method will change when R39 is released,
+ * as the bank is modified using zero page 0x01, instead of the VIA.
+ *
+ * @return unsigned char The current active bank.
+ */
+brom_bank_t bank_get_brom()
+{
+#ifdef X16_R38
+ return VIA1->PORT_B;
+#else
+ return BROM;
+#endif
+}
+
+/**
+ * Call a far routine in a bank.
+ *
+ */
+void call__far(bram_bank_t bank_func, bram_ptr_t ptr_func)
+{
+
+}
+
+// Increase a cx16 banked pointer, so that the bank setting evolves with the increment.
+/**
+ * @brief Increase a banked pointer, located between 0xA000 and 0xBFFF,
+ * so that the bank setting evolves with the increment, increasing the bank and restaring at 0xA000
+ * once the 0xBFFF boundary has been reached.
+ *
+ * @param bank Bank on which the pointer is mapped.
+ * @param sptr The pointer to increment.
+ * @param inc The increment.
+ * @return bram_ptr_t The new calculated pointer.
+ */
+bram_ptr_t bank_bram_ptr_inc(char bank, char *sptr, unsigned int inc)
+{
+
+ char banks = BYTE1(inc) >> 5; // This returns the number of banks the increment will cover.
+
+ sptr -= 0xA000;
+ unsigned int rptr = ((unsigned int)sptr + (inc & 0x1FFF));
+ char diff = BYTE1(rptr) >> 5; // if the inc crosses the 0x2000 boundary, then this bit will be set.
+
+ bank = bank + banks + diff;
+ bank_set_bram(bank);
+
+ rptr = (rptr & 0x1FFF) + 0xA000;
+
+ return (bram_ptr_t)rptr;
+}
+
+/**
+ * @brief Put a single byte into VRAM.
+ * Uses VERA DATA0.
+ *
+ * @param vbank Which 64K VRAM bank to put data into (0/1).
+ * @param vaddr The address in VRAM.
+ * @param data The data to put into VRAM.
+ */
+void vpoke(vram_bank_t vbank, vram_offset_t vaddr, char data)
+{
-// Put a single byte into VRAM.
-// Uses VERA DATA0
-// - bank: Which 64K VRAM bank to put data into (0/1)
-// - addr: The address in VRAM
-// - data: The data to put into VRAM
-void vpoke(char vbank, char* vaddr, char data) {
- // Select DATA0
*VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
*VERA_ADDRX_L = BYTE0(vaddr);
*VERA_ADDRX_M = BYTE1(vaddr);
*VERA_ADDRX_H = VERA_INC_0 | vbank;
- // Set data
+
*VERA_DATA0 = data;
}
-// Read a single byte from VRAM.
-// Uses VERA DATA0
-// - bank: Which 64K VRAM bank to put data into (0/1)
-// - addr: The address in VRAM
-// - returns: The data to put into VRAM
-char vpeek(char vbank, char* vaddr) {
- // Select DATA0
+/**
+ * @brief Read a single byte from VRAM.
+ * Uses VERA DATA0.
+ *
+ * @param vbank Which 64K VRAM bank to put data into (0/1).
+ * @param vaddr The address in VRAM.
+ * @return char The data to put into VRAM.
+ */
+char vpeek(vram_bank_t vbank, vram_offset_t vaddr)
+{
+
*VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
*VERA_ADDRX_L = BYTE0(vaddr);
*VERA_ADDRX_M = BYTE1(vaddr);
*VERA_ADDRX_H = VERA_INC_0 | vbank;
@@ -37,139 +232,389 @@ char vpeek(char vbank, char* vaddr) {
return *VERA_DATA0;
}
-// Copy block of memory (from RAM to VRAM)
-// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM.
-// - vbank: Which 64K VRAM bank to put data into (0/1)
-// - vdest: The destination address in VRAM
-// - src: The source address in RAM
-// - num: The number of bytes to copy
-void memcpy_to_vram(char vbank, void* vdest, void* src, unsigned int num ) {
- // Select DATA0
+/**
+ * @brief Copy block of memory from ram to vram.
+ * Copies num bytes from the ram source pointer to the vram bank/offset.
+ *
+ * @param dbank_vram Destination vram bank.
+ * @param doffset_vram The destination vram offset, 0x0000 till 0xFFFF)
+ * @param sptr_ram Source pointer in ram.
+ * @param num Amount of bytes to copy.
+ */
+void memcpy_vram_ram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, ram_ptr_t sptr_ram, unsigned int num)
+{
+
*VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
- *VERA_ADDRX_L = BYTE0(vdest);
- *VERA_ADDRX_M = BYTE1(vdest);
- *VERA_ADDRX_H = VERA_INC_1 | vbank;
+ *VERA_ADDRX_L = BYTE0(doffset_vram);
+ *VERA_ADDRX_M = BYTE1(doffset_vram);
+ *VERA_ADDRX_H = dbank_vram | VERA_INC_1;
+
// Transfer the data
- char *end = (char*)src+num;
- for(char *s = src; s!=end; s++)
+ unsigned char *end = (unsigned char *)sptr_ram + num;
+ for (char *s = sptr_ram; s != end; s++)
*VERA_DATA0 = *s;
}
-// Copy block of memory (from banked RAM to VRAM)
-// Copies the values of num bytes from the location pointed to by source directly to the memory block pointed to by destination in VRAM.
-// - vdest: absolute address in VRAM
-// - src: absolute address in the banked RAM of the CX16.
-// - num: dword of the number of bytes to copy
-// Note: This function can switch RAM bank during copying to copy data from multiple RAM banks.
-void memcpy_bank_to_vram(unsigned long vdest, unsigned long src, unsigned long num ) {
- // Select DATA0
+/**
+ * @brief Copy block of memory from vram to ram.
+ * Copies num bytes from the source vram bank/offset to the ram destination pointer.
+ *
+ * @param dptr Destination vram pointer.
+ * @param sbank_vram Source vram bank.
+ * @param soffset_vram Source vram offset.
+ * @param num Amount of bytes to copy.
+ */
+void memcpy_ram_vram(ram_ptr_t dptr, vram_bank_t sbank_vram, vram_offset_t soffset_vram, unsigned int num)
+{
+
*VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
- *VERA_ADDRX_L = BYTE0(vdest);
- *VERA_ADDRX_M = BYTE1(vdest);
- *VERA_ADDRX_H = BYTE2(vdest);
- *VERA_ADDRX_H |= VERA_INC_1;
+ *VERA_ADDRX_L = BYTE0(soffset_vram);
+ *VERA_ADDRX_M = BYTE1(soffset_vram);
+ *VERA_ADDRX_H = sbank_vram | VERA_INC_1;
- unsigned long beg = src;
- unsigned long end = src+num;
-
- char bank = BYTE2(beg)<<3 | BYTE1(beg)>>5 ; // (byte)(((((word)<(>beg)<<8)|>(>5)+((word)<(>beg)<<3));
- char* addr = (char*)(WORD0(beg)&0x1FFF); // stip off the top 3 bits, which are representing the bank of the word!
- addr += 0xA000;
-
- VIA1->PORT_A = (char)bank; // select the bank
- for(unsigned long pos=beg; posPORT_A = (char)++bank; // select the bank
- addr = (char*)0xA000;
- }
- *VERA_DATA0 = *addr;
- addr++;
- }
+ // Get the data
+ unsigned char *end = (unsigned char *)dptr + num;
+ for (unsigned char *s = dptr; s != end; s++)
+ *s = *VERA_DATA0;
}
-// Set block of memory to a value in VRAM.
-// Sets num bytes to a value to the memory block pointed to by destination in VRAM.
-// - vbank: Which 64K VRAM bank to put data into (0/1)
-// - vdest: The destination address in VRAM
-// - data: The value to set the vram with.
-// - num: The number of bytes to set
-void memset_vram(char vbank, void* vdest, char data, unsigned long num ) {
- // Select DATA0
- *VERA_CTRL &= ~VERA_ADDRSEL;
- // Set address
- *VERA_ADDRX_L = BYTE0(vdest);
- *VERA_ADDRX_M = BYTE1(vdest);
- *VERA_ADDRX_H = VERA_INC_1 | vbank;
- // Transfer the data
- for(unsigned long i = 0; i>5; //(byte)(((((word)<(>address)<<8)|>(>5)+((word)<(>address)<<3));
- char* addr = (char*)(WORD0(address)&0x1FFF); // stip off the top 3 bits, which are representing the bank of the word!
- addr += 0xA000;
- VIA1->PORT_A = (char)bank; // select the bank
- return load(addr, 0);
+
+/**
+ * @brief Fast initialization of an area pointed by a destination memory address to one value c.
+ * Since the amount of bytes to be initialized is a byte long, it can be executed very fast.
+ * The parameter num can have a value 0, which in case is equal to 256,
+ * which allows 256 bytes to be copied using one single byte counter!
+ * Depending on the optimization of the compiler, this implementation can
+ * result in very fast code, but it should be inlined!
+ *
+ * @param destination The destination memory address as the start of the memory area.
+ * @param c The byte value initializing the memory area..
+ * @param num The amount of bytes to be copied. A value of 0 will set an area of 256 bytes!!!
+ * @return void* The resulting destination memory address.
+
+/**
+ * @brief Fast and inline copy of memory from bram to vram.
+ * Copies num bytes (max 256) from the source bram bank/pointer to the destination vram bank/offset.
+ * Since the amount of bytes to be initialized is a byte long, it can be executed very fast.
+ * The parameter num can have a value 0, which in case is equal to 256,
+ * which allows 256 bytes to be copied using one single byte counter!
+ * Depending on the optimization of the compiler, this implementation can
+ * result in very fast code, but it should be inlined!
+ * NOTE! sptr_bram + amount of bytes to be copied must be between BRAM page boundaries!
+ *
+ * @param dbank_vram Destination vram bank between 0 and 1.
+ * @param doffset_vram Destination vram offset between 0x0000 and 0xFFFF.
+ * @param sbank_vram Source bram bank between 0 and 255 (Depending on banked ram availability, maxima can be 63, 127, 191 or 255).
+ * @param sptr_bram Source bram pointer between 0xA000 and 0xBFFF.
+ * @param num Amount of bytes to copy.
+ */
+inline void memcpy_vram_bram_fast(vram_bank_t dbank_vram, vram_offset_t doffset_vram, bram_bank_t sbank_bram, bram_ptr_t sptr_bram, unsigned char num)
+{
+ bank_push_set_bram(sbank_bram);
+
+ *VERA_CTRL &= ~VERA_ADDRSEL;
+ *VERA_ADDRX_L = BYTE0(doffset_vram);
+ *VERA_ADDRX_M = BYTE1(doffset_vram);
+ *VERA_ADDRX_H = dbank_vram | VERA_INC_1;
+
+ char add = 0;
+ do {
+ *VERA_DATA0 = sptr_bram[add];
+ add++;
+ num--;
+ } while(num);
+
+ bank_pull_bram();
+}
+
+
+
+/**
+ * @brief Copy block of memory from bram to vram.
+ * Copies num bytes from the source bram bank/pointer to the destination vram bank/offset.
+ *
+ * @param dbank_vram Destination vram bank between 0 and 1.
+ * @param doffset_vram Destination vram offset between 0x0000 and 0xFFFF.
+ * @param sbank_vram Source bram bank between 0 and 255 (Depending on banked ram availability, maxima can be 63, 127, 191 or 255).
+ * @param sptr_bram Source bram pointer between 0xA000 and 0xBFFF.
+ * @param num Amount of bytes to copy.
+ */
+void memcpy_vram_bram(vram_bank_t dbank_vram, vram_offset_t doffset_vram, bram_bank_t sbank_bram, bram_ptr_t sptr_bram, unsigned int num)
+{
+
+ byte bank = bank_get_bram();
+ bank_set_bram(sbank_bram);
+
+ *VERA_CTRL &= ~VERA_ADDRSEL;
+ *VERA_ADDRX_L = BYTE0(doffset_vram);
+ *VERA_ADDRX_M = BYTE1(doffset_vram);
+ *VERA_ADDRX_H = dbank_vram | VERA_INC_1;
+
+
+ // byte* ptr = (byte*)sptr_bram;
+ // for(unsigned int i=0; i
+#include
+#include
+
+// The screen width
+#define CONIO_WIDTH 80
+// The screen height
+#define CONIO_HEIGHT 25
+// The text screen address
+#ifndef CONIO_SCREEN_TEXT
+#define CONIO_SCREEN_TEXT DEFAULT_SCREEN
+#endif
+
+// The default text color
+#ifndef CONIO_TEXTCOLOR_DEFAULT
+#define CONIO_TEXTCOLOR_DEFAULT WHITE
+#endif
+
+// Use the shared CMB flat memory implementation
+#include "conio-cbm-shared.c"
+
+// Initializer for conio.h on C64
+#pragma constructor_for(conio_cpet_init, cputc, clrscr, cscroll)
+
+// Set initial cursor position
+void conio_cpet_init() {
+ // // Position cursor at current line
+ // char * const BASIC_CURSOR_LINE = (char*)0xD6;
+ // char line = *BASIC_CURSOR_LINE;
+ // if(line>=CONIO_HEIGHT) line=CONIO_HEIGHT-1;
+ // gotoxy(0, line);
+}
+
+// Return true if there's a key waiting, return false if not
+unsigned char kbhit (void) {
+ // // CIA#1 Port A: keyboard matrix columns and joystick #2
+ // char* const CIA1_PORT_A = (char*)0xdc00;
+ // // CIA#1 Port B: keyboard matrix rows and joystick #1.
+ // char* const CIA1_PORT_B = (char*)0xdc01;
+ // *CIA1_PORT_A = 0;
+ // return ~*CIA1_PORT_B;
+ return 0;
+}
+
+// Set the color for the background. The old color setting is returned.
+unsigned char bgcolor(unsigned char color) {
+ return 0;
+}
+
+// Set the color for the border. The old color setting is returned.
+unsigned char bordercolor(unsigned char color) {
+ return 0;
+}
+
+// Get a charakter from the keyboard and return it.
+unsigned char getch() {
+ return cbm_k_getin();
+}
diff --git a/src/main/kc/lib/sprintf.c b/src/main/kc/lib/sprintf.c
index 94d7176be..012d83175 100644
--- a/src/main/kc/lib/sprintf.c
+++ b/src/main/kc/lib/sprintf.c
@@ -23,10 +23,10 @@ __intrinsic int sprintf( char * s, const char * format, ... );
/// The capacity of the buffer (n passed to snprintf())
/// Used to hold state while printing
-volatile size_t __snprintf_capacity;
+__mem volatile size_t __snprintf_capacity;
// The number of chars that would have been filled when printing without capacity. Grows even after size>capacity.
/// Used to hold state while printing
-volatile size_t __snprintf_size;
+__mem volatile size_t __snprintf_size;
/// Current position in the buffer being filled ( initially *s passed to snprintf()
/// Used to hold state while printing
char * __snprintf_buffer;
diff --git a/src/main/kc/lib/stdio.c b/src/main/kc/lib/stdio.c
new file mode 100644
index 000000000..895f3c75f
--- /dev/null
+++ b/src/main/kc/lib/stdio.c
@@ -0,0 +1,340 @@
+
+#include
+#include
+
+#if defined(__CX16__) // For the moment only supported for the CX16 ...
+
+#include
+
+volatile FILE __stdio_file;
+volatile unsigned char __stdio_filecount = 0;
+
+#define __filename (&__stdio_file.filename[sp * __STDIO_FILECOUNT])
+#define __logical (__stdio_file.channel[sp])
+#define __device (__stdio_file.device[sp])
+#define __channel (__stdio_file.secondary[sp])
+#define __status (__stdio_file.status[sp])
+
+/**
+ * @brief Load a file to banked ram located between address 0xA000 and 0xBFFF incrementing the banks.
+ *
+ * @param channel Input channel.
+ * @param device Input device.
+ * @param secondary Secondary channel.
+ * @param filename Name of the file to be loaded.
+ * @return
+ * - 0x0000: Something is wrong! Kernal Error Code (https://commodore.ca/manuals/pdfs/commodore_error_messages.pdf)
+ * - other: OK! The last pointer between 0xA000 and 0xBFFF is returned. Note that the last pointer is indicating the first free byte.
+ */
+FILE *fopen(const char *path, const char *mode) {
+
+ unsigned char sp = __stdio_filecount;
+ FILE *stream = (FILE *)((unsigned int)sp | 0x8000); // We set bit 7 of the high byte, to differentiate from NULL.
+
+ // Parse path
+ char pathstep = 0;
+ char *pathtoken = path;
+ char pathlen = 0;
+ char pathpos = sp * __STDIO_FILECOUNT;
+
+ __logical = 0;
+ __device = 0;
+ __channel = 0;
+
+ char num;
+
+ // Iterate while path is not \0.
+ do {
+ if (*pathtoken == ',' || *pathtoken == '\0') {
+ if (pathstep > 0) {
+ char pathcmp = *path;
+ switch (pathcmp) {
+ case 'D':
+ case 'L':
+ case 'C':
+ num = (char)atoi(path + 1);
+ path = pathtoken + 1;
+ }
+ switch (pathcmp) {
+ case 'L':
+ __logical = num;
+ break;
+ case 'D':
+ __device = num;
+ break;
+ case 'C':
+ __channel = num;
+ break;
+ }
+ } else {
+ __stdio_file.filename[pathpos] = '\0';
+ path = pathtoken + 1;
+ }
+ pathstep++;
+ } else {
+ if (pathstep == 0) {
+ __stdio_file.filename[pathpos] = *pathtoken;
+ pathpos++;
+ }
+ }
+ pathtoken++;
+ } while (*(pathtoken - 1));
+
+ __status = 0;
+
+ if(!__logical)
+ __logical = __stdio_filecount+1;
+ if(!__device)
+ __device = 8;
+ if(!__channel)
+ __channel = __stdio_filecount+2;
+
+#ifdef __DEBUG_FILE
+ printf("open file, l=%u, d=%u, c=%u, f=%s", __logical, __device, __channel, __filename);
+#endif
+
+ cbm_k_setnam(__filename);
+ cbm_k_setlfs(__logical, __device, __channel);
+
+ cbm_k_open();
+
+ __status = cbm_k_readst();
+
+ if (ferror(stream)) {
+ // The POSIX standard specifies that in case of file not found, NULL is returned.
+ // However, the error needs to be cleared from the device.
+ // This needs to be done using ferror, but this function needs a FILE* stream.
+ // As fopen returns NULL in case file not found, the ferror must be called before return
+ // to clear the error from the device. Otherwise the device is left with a red blicking led.
+ cbm_k_close(__logical);
+ return NULL;
+ }
+
+ __stdio_filecount++;
+
+#ifdef __DEBUG_FILE
+ while(!kbhit());
+#endif
+
+
+ return (FILE *)stream;
+}
+
+/**
+ * @brief Load a file to ram or (banked ram located between address 0xA000 and 0xBFFF), incrementing the banks.
+ * This function uses the new CX16 macptr kernal API at address $FF44.
+ *
+ * @param sptr The pointer between 0xA000 and 0xBFFF in banked ram.
+ * @param size The amount of bytes to be read.
+ * @param filename Name of the file to be loaded.
+ * @return ptr the pointer advanced to the point where the stream ends.
+ */
+unsigned int fgets(char *ptr, unsigned int size, FILE *stream) {
+ unsigned char sp = (unsigned char)stream;
+
+#ifdef __DEBUG_FILE
+ printf("load file, l=%u, d=%u, c=%u, b=%x, p=%p, si=%u", __logical, __device, __channel, bank_get_bram(), ptr, size);
+#endif
+
+ unsigned int read = 0;
+ unsigned int remaining = size;
+
+ cbm_k_chkin(__logical);
+ __status = cbm_k_readst();
+#ifdef __DEBUG_FILE
+ printf(", chkin s=%u", __status);
+#endif
+ if (__status)
+ return 0;
+
+ unsigned int bytes = 0;
+ do {
+ if (!size) {
+#ifdef __DEBUG_FILE
+ printf(", reading max ptr=%p", ptr);
+#endif
+ bytes = cx16_k_macptr(0, ptr);
+ } else {
+ if (remaining >= 128) {
+#ifdef __DEBUG_FILE
+ printf(", reading 128 ptr=%p", ptr);
+#endif
+ bytes = cx16_k_macptr(128, ptr);
+ } else {
+#ifdef __DEBUG_FILE
+ printf(", reading remaining=%u ptr=%p", remaining, ptr);
+#endif
+ bytes = cx16_k_macptr(remaining, ptr);
+ }
+ }
+
+ __status = cbm_k_readst();
+#ifdef __DEBUG_FILE
+ printf(", macptr s=%u", __status);
+#endif
+ if (__status & 0xBF) {
+#ifdef __DEBUG_FILE
+ printf("macptr error s=%u", __status);
+#endif
+ return 0;
+ }
+
+ if (bytes == 0xFFFF) {
+#ifdef __DEBUG_FILE
+ printf("read error in file %s, s=%u, bank=%u, ptr=%p\n", __filename, __status, bank_get_bram(), ptr);
+#endif
+ return 0;
+ }
+
+#ifdef __DEBUG_FILE
+ printf(", bytes=%u", bytes);
+#endif
+
+ read += bytes;
+ ptr += bytes;
+
+ if (BYTE1(ptr) == 0xC0)
+ ptr -= 0x2000;
+ remaining -= bytes;
+
+#ifdef __DEBUG_FILE
+ printf(", size=%u, remaining=%u, read=%u", size, remaining, read);
+#endif
+
+ } while ((__status == 0) && ((size && remaining) || !size));
+
+#ifdef __DEBUG_FILE
+ printf(", read bytes r=%u, s=%u\n", read, __status);
+#endif
+
+#ifdef __DEBUG_FILE
+ while (!kbhit())
+ ;
+#endif
+
+ return read;
+}
+
+/**
+ * @brief Close a file.
+ *
+ * @param fp The FILE pointer.
+ * @return
+ * - 0x0000: Something is wrong! Kernal Error Code (https://commodore.ca/manuals/pdfs/commodore_error_messages.pdf)
+ * - other: OK! The last pointer between 0xA000 and 0xBFFF is returned. Note that the last pointer is indicating the first free byte.
+ */
+int fclose(FILE *stream) {
+
+ unsigned char sp = (unsigned char)stream;
+
+#ifdef __DEBUG_FILE
+ printf("close file, l=%u", __logical);
+#endif
+
+ cbm_k_chkin(__logical);
+
+ __status = cbm_k_readst();
+
+#ifdef __DEBUG_FILE
+ printf(", chkin s=%u", __status);
+#endif
+ if (__status)
+ return 0;
+
+ cbm_k_close(__logical);
+ __status = cbm_k_readst();
+
+#ifdef __DEBUG_FILE
+ printf(", close s=%u", __status);
+#endif
+
+ if (__status)
+ return -1;
+
+ // cbm_k_clrchn();
+ // #ifdef __DEBUG_FILE
+ // printf(", status=%u\n", __stdio_file.status);
+ // #endif
+
+#ifdef __DEBUG_FILE
+ // cbm_k_chkin(0);
+ // while(!kbhit());
+#endif
+
+ __logical = 0;
+ __device = 0;
+ __channel = 0;
+ *__filename = '\0';
+
+ __stdio_filecount--;
+
+ return 0;
+}
+
+/**
+ * @brief POSIX equivalent of ferror for the CBM C language.
+ * This routine reads from secondary 15 the error message from the device!
+ * The result is an error string, including the error code, message, track, sector.
+ * The error string can be a maximum of 32 characters.
+ *
+ * @param stream FILE* stream.
+ * @return int Contains a non-zero value if there is an error.
+ */
+int ferror(FILE *stream) {
+
+ unsigned char sp = (unsigned char)stream;
+
+ cbm_k_setlfs(15, 8, 15);
+ cbm_k_setnam("");
+ cbm_k_open();
+ cbm_k_chkin(15);
+
+ unsigned char st;
+ unsigned char errno_parsed = 0;
+ register char errno_len = 0;
+
+ char ch = cbm_k_chrin();
+ while (!(st = cbm_k_readst())) {
+ if (!errno_parsed) {
+ if (ch == ',') {
+ errno_parsed++;
+ char temp[4];
+ strncpy(temp, __errno_error, errno_len+1);
+ __errno = atoi(temp);
+ }
+ }
+ __errno_error[errno_len] = ch;
+ errno_len++;
+ ch = cbm_k_chrin();
+ // {asm {.byte $DB}}
+ }
+ __status = st;
+ cbm_k_close(15);
+
+#ifdef __DEBUG_FILE
+ printf("error: %s ", __errno_error);
+#endif
+
+ return __errno;
+}
+
+/**
+ * @brief The POSIX error function,
+ * [perror](https://en.wikibooks.org/wiki/C_Programming/stdio.h/perror),
+ * is used in C and C++ to print an error message to stderr,
+ * based on the error state stored in errno.[1]It prints str and an implementation-defined error message corresponding to the global variable errno.
+ *
+ *
+ * @param prefix If the parameter prefix is non-NULL, perror will first print prefix followed by a colon and a space to standard error.
+ * Then, it will print the result of strerror to standard error, followed by a newline character.
+ */
+void perror(char *prefix) {
+ if (prefix) {
+ cputs(prefix);
+ cputs(": ");
+ }
+ cputs(__errno_error);
+ cputc('\n');
+}
+
+#endif
\ No newline at end of file
diff --git a/src/main/kc/lib/stdlib.c b/src/main/kc/lib/stdlib.c
index feaac76c8..554b68437 100644
--- a/src/main/kc/lib/stdlib.c
+++ b/src/main/kc/lib/stdlib.c
@@ -4,7 +4,7 @@
#include
// Top of the heap used by malloc()
-unsigned char* HEAP_TOP = (unsigned char*)0xa000;
+unsigned char* HEAP_TOP = (char*)0xa000;
// Head of the heap. Moved backward each malloc()
unsigned char* heap_head = HEAP_TOP;
@@ -260,7 +260,7 @@ int atoi(const char *str) {
i++;
}
// Iterate through all digits and update the result
- for (; str[i]; ++i)
+ for (; str[i]>='0' && str[i]<='9'; ++i)
res = res * 10 + str[i] - '0';
// Return result with sign
if(negative)
@@ -286,7 +286,7 @@ inline long labs(long x) {
}
// The random state variable
-unsigned int rand_state = 1;
+volatile unsigned int rand_state = 1;
// Returns a pseudo-random number in the range of 0 to RAND_MAX (65535)
// Uses an xorshift pseudorandom number generator that hits all different values
diff --git a/src/main/kc/lib/string.c b/src/main/kc/lib/string.c
index dafe5b58d..f0b111bc4 100644
--- a/src/main/kc/lib/string.c
+++ b/src/main/kc/lib/string.c
@@ -3,6 +3,28 @@
#include
#include
+/**
+ * @brief Fast copy of data from a source to a destination memory address.
+ * Since the amount of bytes to be copied is a byte long, it can be executed very fast.
+ * The parameter num can have a value 0, which in case is equal to 256,
+ * which allows 256 bytes to be copied using one single byte counter!
+ * Depending on the optimization of the compiler, this implementation can
+ * result in very fast code, but it should be inlined!
+ *
+ * @param destination The memory address as the destination.
+ * @param source The memory address as the source.
+ * @param num The amount of bytes to be copied. A value of 0 will copy 256 bytes!!!
+ * @return void* The resulting destination memory address.
+ */
+char* memcpy_fast(char* destination, char* source, unsigned char num) {
+ do {
+ *(destination+num) = *(source+num);
+ num--;
+ } while(num);
+
+ return destination;
+}
+
// 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 ) {
@@ -37,6 +59,28 @@ void *memset(void *str, char c, size_t num) {
return str;
}
+/**
+ * @brief Fast initialization of an area pointed by a destination memory address to one value c.
+ * Since the amount of bytes to be initialized is a byte long, it can be executed very fast.
+ * The parameter num can have a value 0, which in case is equal to 256,
+ * which allows 256 bytes to be copied using one single byte counter!
+ * Depending on the optimization of the compiler, this implementation can
+ * result in very fast code, but it should be inlined!
+ *
+ * @param destination The destination memory address as the start of the memory area.
+ * @param c The byte value initializing the memory area..
+ * @param num The amount of bytes to be copied. A value of 0 will set an area of 256 bytes!!!
+ * @return void* The resulting destination memory address.
+ */
+inline char* memset_fast(char* destination, char c, unsigned char num) {
+ do {
+ *(destination+num) = c;
+ num--;
+ } while(num);
+
+ return destination;
+}
+
// 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 ) {
char* src = source;
@@ -61,6 +105,16 @@ char *strncpy(char *dst, const char *src, size_t n) {
return dst;
}
+// Concatenates the C string pointed by source into the array pointed by destination, including the terminating null character (and stopping at that point).
+char* strcat( char* destination, char* source ) {
+ char* src = source;
+ char* dst = destination + strlen(destination);
+ while(*src) *dst++ = *src++;
+ *dst = 0;
+ return destination;
+}
+
+
// Converts a string to uppercase.
char * strupr(char *str) {
char * src = str;
@@ -142,4 +196,24 @@ int strncmp(const char *str1, const char *str2, size_t n) {
s1++; s2++;
}
return (int)(signed char)(*s1-*s2);
-}
\ No newline at end of file
+}
+
+/**
+ * @brief The string-error function, strerror,
+ * is a C/C++ function which translates an error code,
+ * usually stored in the global variable errno,
+ * to a human-readable error message.
+ *
+ * However, the POSIX standard is not followed in kickc. strerror accepts the errno parameter, but it is not used.
+ * Instead strerror returns the last known error.
+ * This is done for performance reasons and pragmatism, not to make error handling too memory intensive.
+ *
+ *
+ * @param errnum This variable is not used in the function, but kept for POSIX compatibility.
+ * @return char* the pointer to __errno_error, declared in errno.h (POSIX standard).
+ */
+char* strerror(int errnum) {
+ return __errno_error;
+}
+
+
diff --git a/src/test/kc/examples/cx16/cx16-bankload.ld b/src/main/kc/target/c128.ld
similarity index 54%
rename from src/test/kc/examples/cx16/cx16-bankload.ld
rename to src/main/kc/target/c128.ld
index 4ffbe5232..4c6920def 100644
--- a/src/test/kc/examples/cx16/cx16-bankload.ld
+++ b/src/main/kc/target/c128.ld
@@ -1,10 +1,8 @@
-// Create a bunch of files
+// Commodore 128 PRG executable file
.file [name="%O", type="prg", segments="Program"]
-.file [name="SPRITE", type="bin", segments="Sprite"]
.segmentdef Program [segments="Basic, Code, Data"]
-.segmentdef Basic [start=$0801]
+.segmentdef Basic [start=$1c01]
.segmentdef Code [start=%P]
.segmentdef Data [startAfter="Code"]
.segment Basic
-:BasicUpstart(%E)
-.segmentdef Sprite
+:BasicUpstart(%E)
\ No newline at end of file
diff --git a/src/main/kc/target/c128.tgt b/src/main/kc/target/c128.tgt
new file mode 100644
index 000000000..8267260be
--- /dev/null
+++ b/src/main/kc/target/c128.tgt
@@ -0,0 +1,13 @@
+{
+ "description": "Commodore 128 PRG executable file.",
+ "extension": "prg",
+ "link": "c128.ld",
+ "start_address": "0x1c0d",
+ "cpu": "MOS6502X",
+ "interrupt": "rom_min_c64",
+ "zp_reserve": [ "0xfc..0xff" ],
+ "emulator": "x128",
+ "defines": {
+ "__C128__": 1
+ }
+}
diff --git a/src/main/kc/target/cx16.ld b/src/main/kc/target/cx16.ld
index 91922d13f..baa955af7 100644
--- a/src/main/kc/target/cx16.ld
+++ b/src/main/kc/target/cx16.ld
@@ -1,4 +1,4 @@
-// Commodore 64 PRG executable file
+// Commander X16 PRG executable file
.file [name="%O", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
diff --git a/src/main/kc/target/pet8032.ld b/src/main/kc/target/pet8032.ld
new file mode 100644
index 000000000..61a0b7e8c
--- /dev/null
+++ b/src/main/kc/target/pet8032.ld
@@ -0,0 +1,8 @@
+// Commodore PET 8032 PRG executable file
+.file [name="%O", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0401]
+.segmentdef Code [start=%P]
+.segmentdef Data [startAfter="Code"]
+.segment Basic
+:BasicUpstart(%E)
\ No newline at end of file
diff --git a/src/main/kc/target/pet8032.tgt b/src/main/kc/target/pet8032.tgt
new file mode 100644
index 000000000..b83cdebe1
--- /dev/null
+++ b/src/main/kc/target/pet8032.tgt
@@ -0,0 +1,13 @@
+{
+ "description": "Commodore PET 8032 PRG executable file.",
+ "extension": "prg",
+ "link": "pet8032.ld",
+ "start_address": "0x040d",
+ "cpu": "MOS6502X",
+ "interrupt": "rom_min_pet_8032",
+ "zp_reserve": [ "0xfc..0xff" ],
+ "emulator": "xpet",
+ "defines": {
+ "__PET8032__": 1
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java
index c6cb04fe1..9962eb7e9 100644
--- a/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java
+++ b/src/test/java/dk/camelot64/kickc/test/TestProgramsFast.java
@@ -374,17 +374,33 @@ public class TestProgramsFast extends TestPrograms {
public void testStructUnwinding2() throws IOException {
compileAndCompare("struct-unwinding-2.c");
}
-
@Test
public void testStructUnwinding1() throws IOException {
compileAndCompare("struct-unwinding-1.c");
}
- //@Test
- //public void testVarCall5() throws IOException {
- // compileAndCompare("varcall-5.c", log().verboseCreateSsa().verboseStructUnwind());
- //}
+ @Test
+ public void testVarCall9() throws IOException {
+ compileAndCompare("varcall-9.c");
+ }
+ @Test
+ public void testVarCall8() throws IOException {
+ compileAndCompare("varcall-8.c");
+ }
+
+ @Test
+ public void testVarCall7() throws IOException {
+ compileAndCompare("varcall-7.c");
+ }
+ @Test
+ public void testVarCall6() throws IOException {
+ compileAndCompare("varcall-6.c");
+ }
+ @Test
+ public void testVarCall5() throws IOException {
+ compileAndCompare("varcall-5.c");
+ }
@Test
public void testVarCall4() throws IOException {
compileAndCompare("varcall-4.c");
@@ -530,6 +546,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("pragma-unknown.c");
}
+ @Test
+ public void testPragmaNoParametersNoParenthesis() throws IOException {
+ compileAndCompare("pragma-noparam-noparen.c");
+ }
+
@Test
public void testErrorFormatter() throws IOException {
// Error on a char
@@ -735,6 +756,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("examples/rom/rom.c");
}
+ @Test
+ public void testMemFast() throws IOException {
+ compileAndCompare("examples/memfast/memfast.c");
+ }
+
@Test
public void testNesDxycp() throws IOException {
compileAndCompare("examples/nes/nes-dxycp.c");
@@ -746,6 +772,11 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("examples/cx16/cx16-rasterbars.c");
}
+ //@Test
+ //public void testCx16Banking() throws IOException {
+ // compileAndCompare("examples/cx16/banking/cx16-banking.c");
+ //}
+
@Test
public void testMega65Camelot1536Dots() throws IOException {
compileAndCompare("examples/mega65/camelot-1536dots.c");
@@ -1495,6 +1526,83 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("declared-memory-var-0.c");
}
+ @Test
+ public void testBankedPhiCase1Near0() throws IOException {
+ compileAndCompare("call-banked-phi-case-1-near-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase1Near1() throws IOException {
+ compileAndCompare("call-banked-phi-case-1-near-1.c");
+ }
+
+ @Test
+ public void testBankedPhiCase2Close0() throws IOException {
+ compileAndCompare("call-banked-phi-case-2-close-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase2Close1() throws IOException {
+ compileAndCompare("call-banked-phi-case-2-close-1.c");
+ }
+
+ @Test
+ public void testBankedPhiCase3Near0() throws IOException {
+ compileAndCompare("call-banked-phi-case-3-near-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase3Near1() throws IOException {
+ compileAndCompare("call-banked-phi-case-3-near-1.c");
+ }
+
+ @Test
+ public void testBankedPhiCase4Near0() throws IOException {
+ compileAndCompare("call-banked-phi-case-4-near-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase4Near1() throws IOException {
+ compileAndCompare("call-banked-phi-case-4-near-1.c");
+ }
+
+ @Test
+ public void testBankedPhiCase5Far0() throws IOException {
+ compileAndCompare("call-banked-phi-case-5-far-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase5Far1() throws IOException {
+ compileAndCompare("call-banked-phi-case-5-far-1.c");
+ }
+
+ @Test
+ public void testBankedPhiCase6Close0() throws IOException {
+ compileAndCompare("call-banked-phi-case-6-close-0.c");
+ }
+
+ @Test
+ public void testBankedPhiCase6Close1() throws IOException {
+ compileAndCompare("call-banked-phi-case-6-close-1.c");
+ }
+
+ @Test
+ public void testBankedPhiMemvars() throws IOException {
+ compileAndCompare("call-banked-phi-memvars.c");
+ }
+
+
+ @Test
+ public void testBankedStackCase2Close0() throws IOException {
+ assertError("call-banked-stack-case-2-close-0.c", "Stack Call procedure not supported in banked mode");
+ }
+
+ @Test
+ public void testBankedStackCase5Far0() throws IOException {
+ assertError("call-banked-stack-case-5-far-0.c", "Stack Call procedure not supported in banked mode");
+ }
+
+
@Test
public void testProcedureCallingConventionStack13() throws IOException {
compileAndCompare("procedure-callingconvention-stack-13.c");
@@ -2541,6 +2649,31 @@ public class TestProgramsFast extends TestPrograms {
compileAndCompare("weeip-bbslist.c");
}
+ @Test
+ public void testUnion13() throws IOException {
+ compileAndCompare("union-13.c");
+ }
+
+ @Test
+ public void testUnion12() throws IOException {
+ compileAndCompare("union-12.c");
+ }
+
+ @Test
+ public void testUnion11() throws IOException {
+ compileAndCompare("union-11.c");
+ }
+
+ @Test
+ public void testUnion10() throws IOException {
+ compileAndCompare("union-10.c");
+ }
+
+ @Test
+ public void testUnion9() throws IOException {
+ compileAndCompare("union-9.c");
+ }
+
@Test
public void testUnion8() throws IOException {
compileAndCompare("union-8.c");
diff --git a/src/test/kc/call-banked-phi-case-1-near-0.c b/src/test/kc/call-banked-phi-case-1-near-0.c
new file mode 100644
index 000000000..07b4a9513
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-1-near-0.c
@@ -0,0 +1,41 @@
+/**
+ * @file call-banked-phi-case-1-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // near call
+ SCREEN[1] = plus('1', 6); // near call
+}
+
+#pragma code_seg(Code)
+char plus(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-1-near-1.c b/src/test/kc/call-banked-phi-case-1-near-1.c
new file mode 100644
index 000000000..7b5b79ef6
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-1-near-1.c
@@ -0,0 +1,46 @@
+/**
+ * @file call-banked-phi-case-1-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // near call
+ SCREEN[1] = plus('1', 6); // near call
+}
+
+#pragma code_seg(Code)
+char plus(char a, char b) {
+ return add(a, b); // near call
+}
+
+#pragma code_seg(Code)
+char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-2-close-0.c b/src/test/kc/call-banked-phi-case-2-close-0.c
new file mode 100644
index 000000000..ed836b407
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-2-close-0.c
@@ -0,0 +1,42 @@
+/**
+ * @file call-banked-phi-case-2-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+__bank(cx16_ram,1) char plus(char a, char b) {
+ return a+b;
+}
\ No newline at end of file
diff --git a/src/test/kc/call-banked-phi-case-2-close-1.c b/src/test/kc/call-banked-phi-case-2-close-1.c
new file mode 100644
index 000000000..038007c95
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-2-close-1.c
@@ -0,0 +1,43 @@
+/**
+ * @file call-banked-phi-case-2-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char plus(char a, char b) {
+ return a+b;
+}
\ No newline at end of file
diff --git a/src/test/kc/call-banked-phi-case-3-near-0.c b/src/test/kc/call-banked-phi-case-3-near-0.c
new file mode 100644
index 000000000..76812ead5
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-3-near-0.c
@@ -0,0 +1,50 @@
+/**
+ * @file call-banked-phi-case-3-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+__bank(cx16_ram,1) char plus(char a, char b) {
+ return add(a, b); // near call
+}
+
+#pragma code_seg(Code)
+#pragma nobank
+char add(char a, char b) {
+ return a+b;
+}
+
+
diff --git a/src/test/kc/call-banked-phi-case-3-near-1.c b/src/test/kc/call-banked-phi-case-3-near-1.c
new file mode 100644
index 000000000..25bce37f7
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-3-near-1.c
@@ -0,0 +1,51 @@
+/**
+ * @file call-banked-phi-case-3-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char plus(char a, char b) {
+ return add(a, b); // near call
+}
+
+#pragma code_seg(Code)
+#pragma nobank
+char add(char a, char b) {
+ return a+b;
+}
+
+
diff --git a/src/test/kc/call-banked-phi-case-4-near-0.c b/src/test/kc/call-banked-phi-case-4-near-0.c
new file mode 100644
index 000000000..5c7ffc1f0
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-4-near-0.c
@@ -0,0 +1,47 @@
+/**
+ * @file call-banked-phi-case-4-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+char __bank(cx16_ram, 1) plus(char a, char b) {
+ return add(a, b); // near call
+}
+
+#pragma code_seg(RAM_Bank1)
+char __bank(cx16_ram, 1) add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-4-near-1.c b/src/test/kc/call-banked-phi-case-4-near-1.c
new file mode 100644
index 000000000..319ac2483
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-4-near-1.c
@@ -0,0 +1,49 @@
+/**
+ * @file call-banked-phi-case-4-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char plus(char a, char b) {
+ return add(a, b); // near call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-5-far-0.c b/src/test/kc/call-banked-phi-case-5-far-0.c
new file mode 100644
index 000000000..dceba3f63
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-5-far-0.c
@@ -0,0 +1,47 @@
+/**
+ * @file call-banked-phi-case-5-far-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+__bank(cx16_ram, 1) char plus(char a, char b) {
+ return add(a, b); // far call
+}
+
+#pragma code_seg(RAM_Bank2)
+__bank(cx16_ram, 2) char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-5-far-1.c b/src/test/kc/call-banked-phi-case-5-far-1.c
new file mode 100644
index 000000000..754dd1402
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-5-far-1.c
@@ -0,0 +1,49 @@
+/**
+ * @file call-banked-phi-case-5-far-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char plus(char a, char b) {
+ return add(a, b); // far call
+}
+
+#pragma code_seg(RAM_Bank2)
+#pragma bank(cx16_ram, 2)
+char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-6-close-0.c b/src/test/kc/call-banked-phi-case-6-close-0.c
new file mode 100644
index 000000000..8fada9193
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-6-close-0.c
@@ -0,0 +1,47 @@
+/**
+ * @file call-banked-phi-case-6-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+__bank(cx16_ram, 1) char plus(char a, char b) {
+ return add(a, b); // close call
+}
+
+#pragma code_seg(ROM_Bank1)
+__bank(cx16_rom, 1) char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-case-6-close-1.c b/src/test/kc/call-banked-phi-case-6-close-1.c
new file mode 100644
index 000000000..5f8141443
--- /dev/null
+++ b/src/test/kc/call-banked-phi-case-6-close-1.c
@@ -0,0 +1,49 @@
+/**
+ * @file call-banked-phi-case-6-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+ SCREEN[1] = plus('1', 6); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+char plus(char a, char b) {
+ return add(a, b); // close call
+}
+
+#pragma code_seg(ROM_Bank1)
+#pragma bank(cx16_rom, 1)
+char add(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-phi-memvars.c b/src/test/kc/call-banked-phi-memvars.c
new file mode 100644
index 000000000..420b2796f
--- /dev/null
+++ b/src/test/kc/call-banked-phi-memvars.c
@@ -0,0 +1,30 @@
+/**
+ * Test banked calls with memory variables.
+ * The parameters & return should end up in the shared/common bank.
+ */
+
+#pragma link("call-banked-phi.ld")
+#pragma var_model(mem)
+
+int* const SCREEN = (int*)0x0400;
+
+#pragma code_seg(Code)
+#pragma nobank
+void main(void) {
+ for(char i=0;i<5; i++) {
+ SCREEN[i] = plus(100, (int)i);
+ SCREEN[10+i] = plus(200, (int)i);
+ }
+}
+
+#pragma code_seg(RAM_Bank1)
+#pragma data_seg(RAM_Bank1)
+#pragma bank(cx16_ram, 1)
+int plus(int a, int b) {
+ int r = 2;
+ r += a;
+ r += b;
+ r += a;
+ r += b;
+ return r;
+}
diff --git a/src/test/kc/call-banked-phi.ld b/src/test/kc/call-banked-phi.ld
new file mode 100644
index 000000000..de9bdab5d
--- /dev/null
+++ b/src/test/kc/call-banked-phi.ld
@@ -0,0 +1,13 @@
+.file [name="%O", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=%P]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(%E)
+.segment Code
+.segment Data
+
diff --git a/src/test/kc/call-banked-stack-case-2-close-0.c b/src/test/kc/call-banked-stack-case-2-close-0.c
new file mode 100644
index 000000000..91f688bee
--- /dev/null
+++ b/src/test/kc/call-banked-stack-case-2-close-0.c
@@ -0,0 +1,42 @@
+/**
+ * @file call-banked-stack-case-2-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2
+ * The compiler will throw an error because the far call is a __stackcall
+ * and this is not (yet) implemented and supported.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-stack.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close stack call
+}
+
+#pragma code_seg(Bank1)
+__stackcall __bank(cx16_ram, 1) char plus(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-stack-case-5-far-0.c b/src/test/kc/call-banked-stack-case-5-far-0.c
new file mode 100644
index 000000000..a5b7567f3
--- /dev/null
+++ b/src/test/kc/call-banked-stack-case-5-far-0.c
@@ -0,0 +1,47 @@
+/**
+ * @file call-banked-stack-case-5-far-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * The compiler will throw an error because the far call is a __stackcall
+ * and this is not (yet) implemented and supported.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+
+#pragma link("call-banked-phi.ld")
+
+char* const SCREEN = (char*)0x0400;
+
+#pragma code_seg(Code)
+void main(void) {
+ SCREEN[0] = plus('0', 7); // close call
+}
+
+#pragma code_seg(RAM_Bank1)
+__bank(cx16_ram, 1) char plus(char a, char b) {
+ return min(a, b); // far call
+}
+
+#pragma code_seg(RAM_Bank2)
+__stackcall __bank(cx16_ram, 2) char min(char a, char b) {
+ return a+b;
+}
diff --git a/src/test/kc/call-banked-stack.ld b/src/test/kc/call-banked-stack.ld
new file mode 100644
index 000000000..de9bdab5d
--- /dev/null
+++ b/src/test/kc/call-banked-stack.ld
@@ -0,0 +1,13 @@
+.file [name="%O", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=%P]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(%E)
+.segment Code
+.segment Data
+
diff --git a/src/test/kc/examples/c128/sprites.c b/src/test/kc/examples/c128/sprites.c
new file mode 100644
index 000000000..d2559501d
--- /dev/null
+++ b/src/test/kc/examples/c128/sprites.c
@@ -0,0 +1,404 @@
+/**
+ * @file sprites.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief This program is a little exercise we did in retro computer
+ * initiation in school on the Commodore 128 using the KICKC compiler!
+ *
+ * We play with sprites on the Commodore 128.
+ * The reason I chose the Commodore 128 for this exercise is because
+ * this machine contains commands in BASIC that help define sprites and
+ * that you can float around.
+ * However, this is all in BASIC and those commands are made for simple users,
+ * and these were only introduced very late by Commodore in the BASIC language.
+ * The Commodore 64 does not have these BASIC instructions.
+ *
+ * We are now going to learn how to use the C language to control the sprites ourselves.
+ * We do this by directly controlling the registers of the VIC II chip,
+ * who draws the screen on the Commodore 128 and in the Commodore 64.
+ *
+ * Follow the link below for a full description of the VIC II chip and its registers.
+ * It's all very technical, but in class we will see that it is not so bad and
+ * that it is very nice after you have practiced a bit!
+ * [VIC II chip registers](https://handwiki.org/wiki/Engineering:MOS_Technology_VIC-II).
+ *
+ * As mentioned, we work with sprites today.
+ * This link [sprites](https://codebase64.org/doku.php?id=base:spriteintro) explains how we control sprites in the VIC II chip. We learn how they are turned on and off.
+ * We position them on the x-axis and y-axis. We indicate where the bitmap of the sprite is located in the internet memory.
+ * We play with sprites. In class we will go over this explanation together.
+ *
+ * In this lesson we will learn:
+ * - What registers the VICII has for sprite operations.
+ * - How these registries work.
+ * - We learn to address them binary (with &, |, ~ operators).
+ * - We learn how to build C-functions to edit the sprite registers in a simple way.
+ * - We play with our C functions and learn to move sprites across the screen.
+ * - We learn how to make a scan line interrupt and how to make very smooth sprite movements.
+ * - We learn to animate sprites.
+ * - We learn all kinds of other properties of sprites.
+ *
+ * We create the following features and we learn how they work:
+ *
+ * inline void screen_color(char color)
+ * inline void border_color(char color)
+ * inline void sprite_enable(char sprite)
+ * inline void sprite_position_x(char sprite, unsigned int x)
+ * inline void sprite_position_y(char sprite, char y)
+ * inline void sprite_color(char sprite, char color)
+ * inline void sprite_bitmap(char sprite, char* bitmap)
+ *
+ * Note that you will type in your program yourself, but we make the exercises together, because it is all new.
+ * So don't worry, you will learn a lot and later you will be able to play with this yourself :-).
+ *
+ *
+ * EXERCISE 15.1: We give the screen a different color.
+ * - We use VIC II register 0xD020 to color the edge of the screen.
+ * - We use VIC II register 0xD021 to color the screen.
+ * - We complete functions screen_color and border_color.
+ *
+ * EXERCISE 15.2: Position the sprite in a different place on the x-axis and the y-axis!
+ * - Which VIC II registers do you use for this?
+ * - Do you understand how the registers work?
+ * - We complete function sprite_enable to turn on the sprite.
+ * - We complete function sprite_position_x to position the sprite on the x-axis.
+ * - We complete function sprite_position_y to position the sprite on the y-axis.
+ * - We complete function sprite_bitmap to refer the sprite to the sprite bitmap.
+ * - We position the sprite on x-axis at 100 and on y-axis at 100.
+ *
+ * EXERCISE 15.3: Now try to change the color of the sprite.
+ * - We use VIC II registers D027 to D02E.
+ * - We complete function sprite_color to give the sprite a color.
+ *
+ * EXERCISE 15.4: Draw your own sprite in the excel sheet, and cut/paste the binary data into your c program.
+ * - Recompile and run your program. Does it work?
+ * - Ideas for a sprite are spaceships, planes, faces. Keep it simple.
+ *
+ * EXERCISE 15.5: Now make a 2nd and a 3rd sprite, based on the 1st sprite, but change it a bit.
+ * - Declare and allocate the bitmap of the 2nd and 3rd sprite.
+ * - Now try to adjust your program so that the 2nd sprite appears after a random keystroke.
+ * - To achieve this, you need to use the function to adjust the sprite bitmap register.
+ *
+ * EXERCISE 15.6: Now try to switch the sprite bitmap every 16 frames between the 1st sprite and the 2nd and the 3rd sprite.
+ * - We use the "grid line" method. Let me explain. The code scheleton contains all this logic.
+ * - We have to declare a counter that adds up every time.
+ * - For every 16 frames, we adjust the sprite bitmap to the next bitmap.
+ *
+ * EXERCISE 15.7: Now try to move the sprite on the x-axis, from position 50 to position 255.
+ * - If the sprite has landed at position 255, the position should be set back to 50 and we start from scratch.
+ * - We use a scan line interrupt to do this.
+ *
+ * EXERCISE 15.8: Now try to put the sprite BEYOND the position 255 on the x-axis!
+ * - You need a special register here!
+ * - You have to ask Sven how this register works.
+ * - We will learn here how to create a '|' (OR), use a '&' (AND), and a '~' (NOT) operator.
+ *
+ * EXERCISE 15.9: Now we try to move the sprite on the y-axis as well...
+ *
+ * @version 0.1
+ * @date 2022-01-13
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+#pragma encoding(petscii_mixed)
+#pragma var_model(zp)
+#pragma target(C128)
+
+#include
+#include
+#include
+
+#include
+
+// We declare and initialize the registers to give the screen and border a color.
+// For the color of the screen we use VIC II register 0xD021.
+// For the color of the border we use VIC II register 0xD020.
+char* const vic_background_color_0 = (char*)0xD021;
+char* const vic_border_color = (char*)0xD020;
+
+// We declare and initialize the registers that contain the sprite pointers.
+// Sprite pointers refer to the addresses where the sprite drawing is located.
+char* const vic_sprite_bitmap_base = (char*)0x07F8;
+
+// We declare the variables to place sprites on the x-axis and y-axis.
+char* const vic_sprite_x_base = (char*)0xD000;
+char* const vic_sprite_y_base = (char*)0xD001;
+char* const vic_sprite_x_msb = (char*)0xD010;
+
+// We declare the variables to give sprites a color.
+// There are 8 registers from D027 to D02E that contain the color of sprite 0 to 7.
+char* const vic_sprite_color_base = (char*)0xD027;
+
+// We declare the VICII register to show or hide a sprite.
+// Each bit represents 1 sprite.
+char* const vic_sprite_enable = (char*)0xD015;
+
+// We declare the VIC II register which contains the current grid (character) line of the screen.
+// This grid line register is at address 0xD012 in bit 0 to 7,
+// But register 0xD011 in bit 7, contains the 8th grid line bit which can test the values after 255!
+// In other words, if bit 7 of register is 0xD011 at 1, then the scan line is past the 255th line!
+char* const vic_raster_low = (char*)0xD012;
+char* const vic_raster_high = (char*)0xD011; // We gebruiken hier ENKEL de 7de bit!
+
+// spite_bitmap0
+// SOLUTION 15.4:
+static __address(0x2000) char sprite_bitmap_0[3*21] = {
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00011000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b01111110, 0b00000000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000011, 0b11111111, 0b11000000,
+0b00000111, 0b11111111, 0b11100000,
+0b00011100, 0b10010010, 0b01111000,
+0b00000111, 0b11111111, 0b11100000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000000, 0b01000010, 0b00000000,
+0b00000000, 0b10000001, 0b00000000,
+0b00000011, 0b00000000, 0b11000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000
+};
+
+// Ship1
+// SOLUTION 15.5:
+static __address(0x2040) char sprite_bitmap_1[3*21] = {
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00001100, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b01111110, 0b00000000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000011, 0b11111111, 0b11000000,
+0b00000111, 0b11111111, 0b11100000,
+0b00011110, 0b01001001, 0b00111000,
+0b00000111, 0b11111111, 0b11100000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000000, 0b01000010, 0b00000000,
+0b00000000, 0b10000001, 0b00000000,
+0b00000011, 0b00000000, 0b11000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000
+};
+
+// Ship2
+// SOLUTION 15.5:
+static __address(0x2080) char sprite_bitmap_2[3*21] = {
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00110000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b01111110, 0b00000000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000011, 0b11111111, 0b11000000,
+0b00000111, 0b11111111, 0b11100000,
+0b00011101, 0b00100100, 0b10111000,
+0b00000111, 0b11111111, 0b11100000,
+0b00000001, 0b11111111, 0b10000000,
+0b00000000, 0b01000010, 0b00000000,
+0b00000000, 0b10000001, 0b00000000,
+0b00000011, 0b00000000, 0b11000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000,
+0b00000000, 0b00000000, 0b00000000
+};
+
+char* sprite_bitmap_array[3] = {sprite_bitmap_0, sprite_bitmap_1, sprite_bitmap_2};
+
+
+inline void screen_color(char color) {
+ // SOLUTION 15.1:
+ *vic_background_color_0 = color;
+}
+
+inline void border_color(char color) {
+ // SOLUTION 15.1:
+ *vic_border_color = color;
+}
+
+inline void sprite_enable(char sprite) {
+ // SOLUTION 15.2:
+ // We activate the sprite 0 and 1 by setting bit 0 and 1 to 1 in the enable register.
+ *vic_sprite_enable = 1 << sprite;
+}
+
+inline void sprite_position_x(char sprite, unsigned int x) {
+ // SOLUTION 15.2:
+ char* vic_sprite_x = vic_sprite_x_base;
+ vic_sprite_x += sprite << 1;
+ *vic_sprite_x = BYTE0(x);
+
+ // SOLUTION 15.8:
+ if(BYTE1(x))
+ *vic_sprite_x_msb = *vic_sprite_x_msb | 1;
+ else
+ *vic_sprite_x_msb = *vic_sprite_x_msb & ~1;
+}
+
+inline void sprite_position_y(char sprite, char y) {
+ // SOLUTION 15.2:
+ char* vic_sprite_y = vic_sprite_y_base;
+ vic_sprite_y += sprite;
+ *vic_sprite_y = y;
+}
+
+inline void sprite_color(char sprite, char color) {
+ // SOLUTION 15.3:
+ char* vic_sprite_color = vic_sprite_color_base;
+ vic_sprite_color += sprite;
+ *vic_sprite_color = color;
+}
+
+inline void sprite_bitmap(char sprite, char* bitmap) {
+ // SOLUTION 15.2:
+ char* vic_sprite_bitmap = vic_sprite_bitmap_base;
+ vic_sprite_bitmap += sprite;
+ *vic_sprite_bitmap = (char)((unsigned int)bitmap >> 6);
+}
+
+int main() {
+
+ // You can skip these 2 instructions (ignore). Here we just put on the Commodore 128
+ // the BASIC logic out that the sprite control does.
+ // On the Commodore 64, these instructions are not necessary.
+ *((char*)0216) = 255;
+ *((char*)0xA04) = *((char*)0xA04) & ~1;
+
+ // We clear the screen.
+ clrscr();
+
+ // We do a loop in the main logic of this program, and we tested if a key was pressed.
+ // The character of the last keystroke used we store in ch,
+ // But now we initialize this value with 0 to indicate that no key was pressed.
+ unsigned char ch = 0;
+
+ // This is a work variable that we keep track of to make sure we have the grid line
+ // Run logic only if bit 8 of the grid line falls back to 0.
+ // I'll explain it in class, why we have and do this.
+ // We perform the main logic only if raster_test equals 1.
+ unsigned raster_test = 1;
+
+ // We keep track of the x position in a counter.
+ // The type of the x position must be an int,
+ // Because the screen has 320 pixels on the x-axis.
+ // We only have 256 possible values in a char.
+ // So we count with 2 bytes, and we use the type int.
+ // SOLUTION 15.7:
+ unsigned int x = 24;
+
+ // Here is the sprite telletje, we use it to change the array of sprite bitmaps.
+ // SOLUTION 15.6:
+ unsigned char sprite_counter = 0;
+
+ // This is the counter that counts every frame.
+ // SOLUTION 15.6:
+ unsigned char frame = 0;
+
+
+
+
+ // We give the screen a color of your choice.
+ // SOLUTION 15.1:
+ screen_color(1);
+
+ // We give the border a color of your choice.
+ // SOLUTION 15.1:
+ border_color(1);
+
+ // We activate sprite 0.
+ // SOLUTION 15.2:
+ sprite_enable(0);
+
+ // We set the sprite pointer to the address of the sprite bitmap.
+ // SOLUTION 15.2:
+ sprite_bitmap(0, sprite_bitmap_0);
+
+ // We put the sprite at a position on the x-axis an y-axis.
+ // SOLUTION 15.2:
+ sprite_position_x(0, 100);
+ sprite_position_y(0, 100);
+
+ // We set the color of the sprites to a color of your choice.
+ // SOLUTION 15.3:
+ sprite_color(0, 0);
+
+
+ // We continue to run this logic until a key is pressed.
+ while(!ch) {
+
+ // We tested whether we can raster_lijn tested and whether the 8th bit of the grid is set to 1.
+ // If the value of this bit is on, then we execute the logic.
+ if(raster_test && *vic_raster_high & 0x80) {
+
+ // We put the sprite 0 x-axis an y-axis.
+ // SOLUTION 15.7:
+ sprite_position_x(0, x);
+
+ sprite_position_y(0, 100);
+
+ // We put the sprite pointer at the address of the sprite_bitmap counter.
+ // SOLUTION 15.6:
+ sprite_bitmap(0, sprite_bitmap_array[sprite_counter]);
+
+
+ // We now position our sprite at position +1 on the x-axis.
+ // If the position is equal to 0 (EXERCISE 15.7),
+ // or equal to 320 (EXERCISE 15.8),
+ // Then we position our sprite at position 24, the starting position.
+ // SOLUTION 15.7 and 15.8 :
+ if(x < 320) {
+ x++;
+ } else {
+ x = 24;
+ }
+
+ // Here we add 1 to frame to keep track of how many frames we have had.
+ // SOLUTION 15.6:
+ frame += 1;
+
+ // To ensure that we sprite_bitmap increase every 16 frames,
+ // we calculate the current frame AND 0b00010000.
+ // If the result is not 0, then the logic of the if is executed.
+ if((frame & 0x0F) == 0x0F) {
+ sprite_counter++; // We now increase the counter sprite_bitmap by 1.
+ if(sprite_counter == 3) { // If sprite_bitmap equals 3?
+ sprite_counter = 0; // Then we put sprite_bitmap back to 0.
+ }
+ }
+
+ // We just read a character from the keyboard.
+ ch = kbhit();
+
+ // To ensure that we only run the logic 1 time, we put it
+ // raster_test flag at 0.
+ // We perform the main logic only if raster_test equals 1.
+ raster_test = 0;
+
+ } else {
+ // Otherwise... Now we tested whether we can test the current grid line.
+ // If we are allowed to test raster_lijn, so if raster_test equals 0
+ // AND or bit 8 of grid line equals 0.
+ if(!raster_test && !(*vic_raster_high & 0x80)) {
+ raster_test = 1; // Then we put raster_test back to 1;
+ }
+ }
+
+ }
+
+ return 1;
+}
diff --git a/src/test/kc/examples/cx16/banking/cx16-banking.c b/src/test/kc/examples/cx16/banking/cx16-banking.c
new file mode 100644
index 000000000..8648d45d1
--- /dev/null
+++ b/src/test/kc/examples/cx16/banking/cx16-banking.c
@@ -0,0 +1,164 @@
+/**
+ * @file cx16-banking-1.c
+ * @author your name (you@domain.com)
+ * @brief This program demonstrates a simple example of a banked call.
+ * @version 0.1
+ * @date 2023-04-05
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+// The linker specification of the different segments.
+#pragma target(cx16)
+#pragma link("cx16-banking.ld")
+#pragma var_model(mem)
+
+#include
+#include
+#include
+
+// The target computer platform is the Commander X16,
+// which implements banking in ram between 0xA0000 and 0xBFFF,
+// and in ram between 0xC000 and 0xFFFF.
+#pragma target(cx16)
+
+// Functional code
+
+#pragma code_seg(Bank1) // The sequent functions will be addressed specified by segment bank1 in the linker.
+#pragma bank(cx16_ram, 1) // The sequent functions will be banked using call method ram in bank number 1.
+
+char add_a(char a) {
+ printf("add_a(%02x), ", bank_get_bram());
+ return a+1;
+}
+
+char add_c(char a) {
+ printf("add_c(%02x), ", bank_get_bram());
+ return add_a(a)+1; // Non banked call in ram bank 1.
+}
+
+char add_d(char a) {
+ printf("add_d(%02x), ",bank_get_bram());
+ return mul_a(a)+1; // Banked call fram ram bank 1 to ram bank 2.
+}
+
+char add_e(char a) {
+ printf("add_e(%02x), ",bank_get_bram());
+ return mul_b(a)+1; // Banked call fram ram bank 1 to ram bank 2.
+}
+
+char add_f(char a) {
+ printf("add_f(%02x), ",bank_get_bram());
+ return add_m(a)+1; // Non banked call fram ram bank 1 to main memory.
+}
+
+
+#pragma code_seg(Bank2) // The sequent functions will be addressed specified by segment bank2 in the linker.
+#pragma bank(cx16_ram, 2) // The sequent functions will be banked using call method ram in bank number 2.
+
+char mul_a(char m) {
+ printf("mul_a(%02x), ",bank_get_bram());
+ return m * 2;
+}
+
+char mul_c(char m) {
+ printf("mul_c(%02x), ",bank_get_bram());
+ return add_a(m)*2; // Banked call fram ram bank 2 to ram bank 1.
+}
+
+char mul_d(char m) {
+ printf("mul_d(%02x), ",bank_get_bram());
+ return mul_a(m)*2; // Non banked call in ram bank 2.
+}
+
+char mul_e(char a) {
+ printf("mul_e(%02x), ",bank_get_bram());
+ return mul_b(a)*2; // Non Banked call in ram bank 2.
+}
+
+char mul_f(char m) {
+ printf("mul_f(%02x), ",bank_get_bram());
+ return add_m(m)*2; // Non banked call fram ram bank 2 to main memory.
+}
+
+
+#pragma nobank // The sequent functions will consider no banking calculations anymore.
+
+#pragma code_seg(Bank1) // The sequent functions will be addressed specified by segment bank1 in the linker.
+// The __bank directive declares this function to be banked using call method ram in bank number 1 of banked ram.
+char __bank(cx16_ram, 1) add_b(char a) {
+ printf("add_b(%02x), ",bank_get_bram());
+ return a+1;
+}
+
+#pragma code_seg(Bank2) // The sequent functions will be addressed specified by segment bank1 in the linker.
+// The __bank directive declares this function to be banked using call method ram in bank number 2 of banked ram.
+char __bank(cx16_ram, 2) mul_b(char m) {
+ printf("mul_b(%02x), ",bank_get_bram());
+ return m*2;
+}
+
+#pragma code_seg(Code) // The sequent functions will be addressed in the default main memory location (segment Code).
+
+// Allocated in main memory.
+char add_m(char a) {
+ printf("add_m(%02x), ",bank_get_bram());
+ return add_e(a)+1; // Banked call to ram in bank 1 fram main memory.
+}
+
+// Allocated in main memory.
+char mul_m(char m) {
+ printf("mul_m(%02x), ",bank_get_bram());
+ return mul_e(m)*2; // Banked call to ram in bank 2 fram main memory.
+}
+
+
+// Practically this means that the main() function is placed in main memory ...
+
+void load_bank(char bank, char *file) {
+ bank_set_bram(bank);
+ cbm_k_setnam(file);
+ cbm_k_setlfs(1,8,2);
+ cbm_k_load((char*)0xA000, 0);
+ cbm_k_close(1);
+}
+
+void main(void) {
+
+ clrscr();
+
+ load_bank(1, "BANK1.BIN");
+ load_bank(2, "BANK2.BIN");
+
+ bank_set_bram(0);
+
+ asm{.byte $db}
+ printf("result = %u\n", add_a(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_b(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_c(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_d(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_e(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_f(1)); // Banked call to ram in bank 1 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_a(1)); // Banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_b(1)); // Banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_c(1)); // Banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_d(1)); // Banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_e(1)); // banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_f(1)); // banked call to ram in bank 2 fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", add_m(1)); // Near call in main memory fram main memory.
+ asm{.byte $db}
+ printf("result = %u\n", mul_m(1)); // Near call in main memory fram main memory.
+}
diff --git a/src/test/kc/examples/cx16/banking/cx16-banking.ld b/src/test/kc/examples/cx16/banking/cx16-banking.ld
new file mode 100644
index 000000000..e21277416
--- /dev/null
+++ b/src/test/kc/examples/cx16/banking/cx16-banking.ld
@@ -0,0 +1,14 @@
+.file [name="%O", type="prg", segments="Program"]
+.file [name="BANK1.BIN", type="bin", segments="Bank1"]
+.file [name="BANK2.BIN", type="bin", segments="Bank2"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=%P]
+.segmentdef Data [startAfter="Code"]
+.segmentdef Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segment Basic
+:BasicUpstart(%E)
+.segment Code
+.segment Data
+
diff --git a/src/test/kc/examples/cx16/cx16-bankaddressing.c b/src/test/kc/examples/cx16/cx16-bankaddressing.c
deleted file mode 100644
index 77989733a..000000000
--- a/src/test/kc/examples/cx16/cx16-bankaddressing.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// Example program for the Commander X16
-// Demonstrates some bank addressing calculations
-
-#pragma target(cx16)
-
-#include
-#include <6502.h>
-#include
-#include
-#include
-#include
-
-void main() {
-
- dword src = (dword)0x02000;
- dword num = 64*64*2;
-
- word inc = 0x0123;
-
- for(dword src=0x0000;src<0x3F000;src+=num) {
-
- dword calcbeg = src;
- dword calcend = src+num+(-1);
- byte bankbeg = BYTE2(calcbeg)<<3 | BYTE1(calcbeg)>>5 ; //(byte)(((((word)<(>calcbeg)<<8)|>(>5)+((word)<(>calcbeg)<<3));
- byte bankend = BYTE2(calcend)<<3 | BYTE1(calcend)>>5 ; //(byte)(((((word)<(>calcend)<<8)|>(>5)+((word)<(>calcend)<<3));
- const word borderbeg = 0xA000;
- const word borderend = 0xA000+0x1FFF;
- word beg = (WORD0(calcbeg)&0x1FFF); // stip off the top 3 bits, which are representing the bank of the word!
- word end = (WORD0(calcend)&0x1FFF); // same for the end;
- beg += borderbeg;
- end += borderbeg;
-
- printf("cbeg=%x, add=%x, cend=%x, bbeg=%x, bend=%x, beg=%x, end=%x\n", calcbeg, num, calcend, bankbeg, bankend, beg, end );
- num+=inc;
- }
-}
\ No newline at end of file
diff --git a/src/test/kc/examples/cx16/cx16-bankload.c b/src/test/kc/examples/cx16/cx16-bankload.c
deleted file mode 100644
index 3f904a4c1..000000000
--- a/src/test/kc/examples/cx16/cx16-bankload.c
+++ /dev/null
@@ -1,99 +0,0 @@
-// Commander X16 Load a file to a memory bank
-
-#pragma target(cx16)
-#pragma link("cx16-bankload.ld")
-
-#include
-#include
-#include
-#include
-#include <6502.h>
-#include
-#include
-#include
-
-#pragma data_seg(Sprite)
-__export char SPRITE_PIXELS[] = kickasm(resource "ship.png") {{
- .var pic = LoadPicture("ship.png")
- // palette: rgb->idx
- .var palette = Hashtable()
- // RGB value for each palette index
- .var palList = List()
- // Next palette index
- .var nxt_idx = 0;
- // Extract palette while outputting pixels as palete index values
- .for (var y=0; y<64; y++) {
- .for (var x=0;x<64; x++) {
- // Find palette index (add if not known)
- .var rgb = pic.getPixel(x,y);
- .var idx = palette.get(rgb)
- .if(idx==null) {
- .eval idx = nxt_idx++;
- .eval palette.put(rgb,idx);
- .eval palList.add(rgb)
- }
- }
- }
- .if(nxt_idx>16) .error "Image has too many colours "+nxt_idx
-
- .for(var i=0;i<16;i++) {
- .var rgb = palList.get(i)
- .var red = floor(rgb / [256*256])
- .var green = floor(rgb/256) & 255
- .var blue = rgb & 255
- // bits 4-8: green, bits 0-3 blue
- .byte green&$f0 | blue/16
- // bits bits 0-3 red
- .byte red/16
- }
-
- .for (var y=0; y<64; y++) {
- .for (var x=0;x<64; x+=2) {
- // Find palette index (add if not known)
- .var rgb = pic.getPixel(x,y);
- .var idx1 = palette.get(rgb)
- .if(idx1==null) {
- .printnow "unknown rgb value!"
- }
- // Find palette index (add if not known)
- .eval rgb = pic.getPixel(x+1,y);
- .var idx2 = palette.get(rgb)
- .if(idx2==null) {
- .printnow "unknown rgb value!"
- }
- .byte idx1*16+idx2;
- }
- }
-}};
-
-#pragma data_seg(Data)
-
-void main() {
-
- vera_layer_set_text_color_mode( 1, VERA_LAYER_CONFIG_16C );
- screenlayer(1);
- clrscr();
- printf("\n\nsprite banked file load and display demo.\n");
-
- // RAM Bank where sprite is loaded
- const dword BANK_SPRITE = 0x12000;
- // VRAM address of sprite
- const dword VRAM_SPRITE = 0x10000;
- // Sprite attributes: 8bpp, in front, 64x64, address SPRITE_PIXELS_VRAM
- struct VERA_SPRITE SPRITE_ATTR = { WORD0(VRAM_SPRITE/32)|VERA_SPRITE_8BPP, 320-32, 240-32, 0x0c, 0xf1 };
-
- char status = load_to_bank(8, "SPRITE", BANK_SPRITE );
-
- memcpy_bank_to_vram(VERA_PALETTE+32, BANK_SPRITE-2, 32);
- memcpy_bank_to_vram(VRAM_SPRITE, BANK_SPRITE+32-2, 64*32);
-
- SPRITE_ATTR.ADDR = WORD0(VRAM_SPRITE/32)|VERA_SPRITE_4BPP;
- SPRITE_ATTR.X = 100;
- SPRITE_ATTR.Y = 100;
- memcpy_to_vram(BYTE2(VERA_SPRITE_ATTR), (char*)WORD0(VERA_SPRITE_ATTR), &SPRITE_ATTR, sizeof(SPRITE_ATTR));
-
- // Enable sprites
- *VERA_CTRL &= ~VERA_DCSEL;
- *VERA_DC_VIDEO |= VERA_SPRITES_ENABLE;
-
-}
diff --git a/src/test/kc/examples/cx16/cx16-input.c b/src/test/kc/examples/cx16/cx16-input.c
index 49715884d..8ce170b10 100644
--- a/src/test/kc/examples/cx16/cx16-input.c
+++ b/src/test/kc/examples/cx16/cx16-input.c
@@ -1,12 +1,12 @@
#pragma target(cx16)
#include
-#include
+#include
#include
-// Find the value of a keypress as returned by kernal getin()
+// Find the value of a keypress as returned by conio kbhit()
void main() {
printf("\npress a key\n");
char test = 0;
- while(test==0) test=getin();
+ while(test==0) test=kbhit();
printf("\nchar = %u\n", test);
}
\ No newline at end of file
diff --git a/src/test/kc/examples/cx16/cx16-sprites.c b/src/test/kc/examples/cx16/cx16-sprites.c
index ad6538f60..48afa5e72 100644
--- a/src/test/kc/examples/cx16/cx16-sprites.c
+++ b/src/test/kc/examples/cx16/cx16-sprites.c
@@ -4,6 +4,7 @@
#pragma target(cx16)
#include
#include <6502.h>
+#include
#define NUM_SPRITES 32
@@ -53,15 +54,15 @@ struct VERA_SPRITE SPRITE_ATTR = { WORD0(SPRITE_PIXELS_VRAM/32)|VERA_SPRITE_8BPP
void main() {
// Copy sprite data to VRAM
- memcpy_to_vram(BYTE2(SPRITE_PIXELS_VRAM), (char*)WORD0(SPRITE_PIXELS_VRAM), SPRITE_PIXELS, 64*64);
+ memcpy_vram_ram((vram_bank_t)BYTE2(SPRITE_PIXELS_VRAM), (vram_offset_t)WORD0(SPRITE_PIXELS_VRAM), (ram_ptr_t)SPRITE_PIXELS, 64*64);
// Copy sprite palette to VRAM
- memcpy_to_vram(BYTE2(VERA_PALETTE), (char*)WORD0(VERA_PALETTE), SPRITE_PIXELS+64*64, 0x200);
+ memcpy_vram_ram((vram_bank_t)BYTE2(VERA_PALETTE), (vram_offset_t)WORD0(VERA_PALETTE), (ram_ptr_t)SPRITE_PIXELS+64*64, 0x200);
// Copy 8* sprite attributes to VRAM
char* vram_sprite_attr = (char*)WORD0(VERA_SPRITE_ATTR);
for(char s=0;s=SINX_LEN) i_x -= SINX_LEN;
i_y += 19; if(i_y>=SINY_LEN) i_y -= SINY_LEN;
diff --git a/src/test/kc/examples/cx16/cx16-text.c b/src/test/kc/examples/cx16/cx16-text.c
index c4d18cc11..b2e1bdfc4 100644
--- a/src/test/kc/examples/cx16/cx16-text.c
+++ b/src/test/kc/examples/cx16/cx16-text.c
@@ -7,14 +7,14 @@
void main() {
// Copy message to screen one char at a time
char MSG[] = "hello world!";
- char* vaddr = DEFAULT_SCREEN;
+ vram_offset_t vaddr = DEFAULT_SCREEN;
for(char i=0;MSG[i];i++) {
vpoke(0, vaddr++, MSG[i]); // Message
vpoke(0, vaddr++, 0x21); // Red background, White foreground
}
// Copy message (and colors) to screen using memcpy_to_vram
char MSG2[] = "h e l l o w o r l d ! "; // Space is 0x20, red background black foreground
- memcpy_to_vram(0, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2));
+ memcpy_vram_ram(1, DEFAULT_SCREEN+0x100, MSG2, sizeof(MSG2));
}
diff --git a/src/test/kc/examples/cx16/cx16-tilemap.c b/src/test/kc/examples/cx16/cx16-tilemap.c
deleted file mode 100644
index d782d1017..000000000
--- a/src/test/kc/examples/cx16/cx16-tilemap.c
+++ /dev/null
@@ -1,145 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA layer 0 and 1.
-
-// Author: Sven Van de Velde
-
-// The default layer of the CX16 is layer 1.
-// The CX16 starts in tile map mode, 1BPP in 16 color mode, and uses 8x8 tiles.
-// The map base is address 0x00000 in VERA VRAM, the tile map is address 0x0F800.
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include <6502.h>
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- dword tilebase = vera_layer_get_tilebase_address(1);
-
- vera_layer_mode_tile(0, 0x10000, tilebase, 128, 128, 8, 8, 1);
-
- screenlayer(0);
- scroll(0); // Scrolling on conio is deactivated, so conio will output beyond the borders of the visible screen.
- textcolor(WHITE);
- bgcolor(GREEN);
-
- draw_characters(tilebase);
-
- // Enable VSYNC IRQ (also set line bit 8 to 0)
- SEI();
- *KERNEL_IRQ = &irq_vsync;
- *VERA_IEN = VERA_VSYNC;
- CLI();
-
- vera_layer_show(0);
- while(!kbhit());
-
- vera_layer_hide(0);
- textcolor(GREY);
- bgcolor(GREEN);
- draw_characters(tilebase);
- vera_layer_show(0);
-
- screenlayer(1);
-
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("\n\nthis demo displays the design of the standard x16 commander\n");
- printf("character set on the vera layer 0. it's the character set i grew up with :-).\n");
- printf("\nthe smooth scrolling is implemented by manipulating the scrolling \n");
- printf("registers of layer 0. at each raster line interrupt, \n");
- printf("the x and y scrolling registers are manipulated. the cx16 terminal \n");
- printf("works on layer 1. when layer 0 is enabled with the scrolling, \n");
- printf("it gives a nice background effect. this technique can be used to implement\n");
- printf("smooth scrolling backgrounds using tile layouts in games or demos.\n");
-
- textcolor(YELLOW);
- printf("\npress a key to continue ...");
-
- while(!kbhit());
-
- screenlayer(0);
- vera_layer_hide(0);
- textcolor(DARK_GREY);
- bgcolor(BLACK);
- draw_characters(tilebase);
- vera_layer_show(0);
-
- screenlayer(1);
- gotoxy(0,20);
-
-}
-
-void draw_characters(dword tilebase) {
- dword tilecolumn = tilebase;
- dword tilerow = tilebase;
- clrscr();
-
- for(byte y:0..15) {
- tilerow = tilebase;
- for(byte r:0..7) {
- tilecolumn = tilerow;
- for(byte x:0..15) {
- vera_vram_address0(tilecolumn,VERA_INC_0);
- byte data = *VERA_DATA0;
- byte bit = data;
- for(byte b:8..1) {
- bit = (data >> (b-1)) & $1;
- printf("%c", (char)((bit)?'*':'.'));
- }
- tilecolumn += 8;
- printf("");
- }
- //printf("\n");
- tilerow += 1;
- }
- tilebase += 8*16;
- }
-}
-
-// X sine index
-volatile int scroll_x = 0;
-volatile int scroll_y = 0;
-volatile int delta_x = 2;
-volatile int delta_y = 0;
-volatile int speed = 2;
-
-// VSYNC Interrupt Routine
-__interrupt(rom_sys_cx16) void irq_vsync() {
-
- scroll_x += delta_x;
- scroll_y += delta_y;
-
- if( scroll_x>(128*8-80*8)) {
- delta_x = 0;
- delta_y = speed;
- scroll_x = (128*8-80*8);
- }
- if( scroll_y>(128*8-60*8)) {
- delta_x = -speed;
- delta_y = 0;
- scroll_y = (128*8-60*8);
- }
- if(scroll_x<0) {
- delta_x = 0;
- delta_y = -speed;
- scroll_x = 0;
- }
- if(scroll_y<0) {
- delta_x = speed;
- delta_y = 0;
- scroll_y = 0;
- }
-
- vera_layer_set_horizontal_scroll(0,(word)scroll_x);
- vera_layer_set_vertical_scroll(0,(word)scroll_y);
-
- // Reset the VSYNC interrupt
- *VERA_ISR = VERA_VSYNC;
-}
\ No newline at end of file
diff --git a/src/test/kc/examples/cx16/cx16-veralayers.c b/src/test/kc/examples/cx16/cx16-veralayers.c
deleted file mode 100644
index 0bc8cdfe1..000000000
--- a/src/test/kc/examples/cx16/cx16-veralayers.c
+++ /dev/null
@@ -1,135 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA layer 0 and 1.
-
-// Author: Sven Van de Velde
-
-// The default layer of the CX16 is layer 1.
-// The CX16 starts in tile map mode, 1BPP in 16 color mode, and uses 8x8 tiles.
-// The map base is address 0x00000 in VERA VRAM, the tile map is address 0x0F800.
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- // Wait for a keypress and after clear the line!
- textcolor(YELLOW);
- printf("press a key");
- while(!kbhit());
- clearline();
-
- screenlayer(1);
-
- gotoxy(0,16);
- textcolor(GREEN);
-
- printf("this program demonstrates the layer functionality in text mode.\n");
-
- // Here we use the screensizex and screensizey functions to show the width and height of the text screen.
- printf("\nvera card width = %u; height = %u\n", screensizex(), screensizey());
-
- // This is the content of the main controller registers of the VERA of layer 1.
- // Layer 1 is the default layer that is activated in the CX16 at startup.
- // It displays the characters in 1BPP 16x16 color mode!
- unsigned byte dcvideo = *VERA_DC_VIDEO;
- printf("\nvera dc video = %x\n", dcvideo);
- unsigned byte config = vera_layer_get_config(1);
- printf("\nvera layer 1 config = %x\n", config);
- unsigned byte layershown = vera_layer_is_visible(1);
- printf("vera layer 1 shown = %c\n", layershown);
- unsigned byte mapbase = vera_layer_get_mapbase(1);
- unsigned byte tilebase = vera_layer_get_tilebase(1);
- printf("vera layer 1 mapbase = %hhx, tilebase = %hhx\n", mapbase, tilebase);
-
- // Wait for a keypress and after clear the line!
- textcolor(YELLOW);
- printf("press a key");
- while(!kbhit());
- clearline();
-
- // Now we continue with demonstrating the layering!
- // We set the mapbase of layer 0 to an address in VRAM.
- // We copy the tilebase address from layer 1, so that we reference to the same tilebase.
- // We print a text on layer 0, which of course, won't yet be displayed,
- // because we haven't activated layer 0 on the VERA.
- // But the text will be printed and awaiting to be displayer later, once we activate layer 0!
- // But first, we also print the layer 0 VERA configuration.
- // This statement sets the base of the display layer 1 at VRAM address 0x0200
-
- vera_layer_set_mapbase(0,0x80); // Set the map base to address 0x10000 in VERA VRAM!
- vera_layer_set_config(0, vera_layer_get_config(1));
- vera_layer_set_tilebase(0, vera_layer_get_tilebase(1));
-
- textcolor(WHITE);
- config = vera_layer_get_config(0);
- printf("\nvera layer 0 config = %x\n", vera_layer_get_config(0));
- layershown = vera_layer_is_visible(0);
- printf("vera layer 0 shown = %x\n", layershown);
- mapbase = vera_layer_get_mapbase(0);
- tilebase = vera_layer_get_tilebase(0);
- printf("vera layer 0 mapbase = %x, tilebase = %x\n", mapbase, tilebase);
-
- // Now we print the layer 0 text on the layer 0!
- screenlayer(0); // We set conio to output to layer 0 instead of layer 1!
- textcolor(BLUE);
- bgcolor(BLACK);
- clrscr(); // We clear the screen of layer 0!
- bgcolor(WHITE);
- gotoxy(19,4);
- printf(" ");
- gotoxy(19,5);
- printf(" this is printed on layer 0 !!! ");
- gotoxy(19,6);
- printf(" ");
-
- screenlayer(1); // Now we ask conio again to output to layer 1!
-
- // Wait for a keypress and after clear the line!
- textcolor(YELLOW);
- bgcolor(BLACK);
- printf("press a key to show layer 0 and show the text!");
- while(!kbhit());
- clearline();
-
- // Now we activate layer 0.
- vera_layer_show(0);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera layer 0 shown = %x. ", vera_layer_is_visible(0));
-
- // Wait for a keypress and after clear the line!
- textcolor(YELLOW);
- bgcolor(BLACK);
- printf("press a key to hide layer 0 and hide the text again");
- while(!kbhit());
- clearline();
-
- vera_layer_hide(0);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera layer 0 shown = %x. ", vera_layer_is_visible(0));
-
- // Wait for a keypress and after clear the line!
- textcolor(YELLOW);
- bgcolor(BLACK);
- printf("press a key to finish");
- while(!kbhit());
- clearline();
-
- clrscr();
- textcolor(RED);
- bgcolor(WHITE);
- gotoxy(19,10);
- printf(" ");
- gotoxy(19,11);
- printf(" analyze the code and learn! ");
- gotoxy(19,12);
- printf(" ");
-}
diff --git a/src/test/kc/examples/cx16/cx16-veramodes.c b/src/test/kc/examples/cx16/cx16-veramodes.c
deleted file mode 100644
index fb283c974..000000000
--- a/src/test/kc/examples/cx16/cx16-veramodes.c
+++ /dev/null
@@ -1,1230 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-
-void main() {
-
- do {
- vera_layer_mode_text(1, 0x00000, 0x0f800, 64, 64, 8, 8, 4);
- vera_display_set_scale_double();
- vera_layer_show(1);
- screenlayer(1);
-
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
- printf( "\n *** vera demo ***\n\n" );
- printf( "1. bitmap - 320x240 - 1 bpp.\n");
- printf( "2. bitmap - 640x480 - 1 bpp.\n");
- printf( "3. bitmap - 320x240 - 2 bpp.\n");
- printf( "4. bitmap - 640x480 - 2 bpp.\n");
- printf( "5. bitmap - 320x240 - 4 bpp.\n");
- printf( "6. bitmap - 320x240 - 8 bpp.\n");
-
- printf( "\na. text - 8x8 - 1 bpp, 16c.\n");
- printf( "b. text - 8x8 - 1 bpp, 256c.\n");
-
- printf( "\nc. tile - 8x8 - 2 bpp.\n");
- printf( "d. tile - 16x16 - 2 bpp.\n");
- printf( "e. tile - 8x8 - 4 bpp.\n");
- printf( "f. tile - 16x16 - 4 bpp.\n");
- printf( "g. tile - 8x8 - 8 bpp.\n");
- printf( "h. tile - 16x16 - 8 bpp.\n");
-
- printf( "\n0. exit.\n");
-
- byte menu = 0;
- while(menu==0) {
- menu = getin();
- }
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- switch( menu ) {
- case 49:
- bitmap_320_x_240_1BPP();
- break;
- case 50:
- bitmap_640_x_480_1BPP();
- break;
- case 51:
- bitmap_320_x_240_2BPP();
- break;
- case 52:
- bitmap_640_x_480_2BPP();
- break;
- case 53:
- bitmap_320_x_240_4BPP();
- break;
- case 54:
- bitmap_320_x_240_8BPP();
- break;
- case 65:
- text_8_x_8_1BPP_16_color();
- break;
- case 66:
- text_8_x_8_1BPP_256_color();
- break;
- case 67:
- tile_8_x_8_2BPP_4_color();
- break;
- case 68:
- tile_16_x_16_2BPP_4_color();
- break;
- case 69:
- tile_8_x_8_4BPP_16_color();
- break;
- case 70:
- tile_16_x_16_4BPP_16_color();
- break;
- case 71:
- tile_8_x_8_8BPP_256_color();
- break;
- case 72:
- tile_16_x_16_8BPP_256_color();
- break;
- }
-
- vera_layer_hide(0);
- vera_layer_mode_text(1, 0x00000, 0x0f800, 64, 64, 8, 8, 4);
- vera_layer_show(1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
- } while( menu != 48 );
-
-}
-
-void tile_16_x_16_8BPP_256_color() {
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[256] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- };
-
- // Before we can load the tiles into memory we need to re-arrange a few things!
- // The amount of tiles is 256, the color depth is 256, so each tile is 256 bytes!
- // That is 65356 bytes of memory, which is 64K. Yup! One memory bank in VRAM.
- // VERA VRAM holds in bank 1 many registers that interfere loading all of this data.
- // So it is better to load all in bank 0, but then there is an other issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x10000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
-
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x10000, 0x1F000, 128, 64, 8, 8, 1);
- vera_display_set_scale_none();
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- // Now we can use the full bank 0!
- // We set the mapbase of the tile demo to output to 0x12000,
- // and the tilebase is set to 0x0000!
- vera_layer_mode_tile(0, 0x14000, 0x00000, 64, 64, 16, 16, 8);
-
-
- word tilebase = 0x0000;
- memcpy_to_vram(0, tilebase, tiles, 256);
- tilebase+=256;
- for(byte t:1..255) {
- for(byte p:0..255) {
- tiles[p]+=1;
- }
- memcpy_to_vram(0, tilebase, tiles, 256);
- tilebase+=256;
- }
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- byte row = 1;
- for(byte r:0..11) {
- byte column = 0;
- for(byte c:0..19) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 8 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 256 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- vera_layer_show(0);
-
- while(!getin());
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- tile = 0;
- row = 0;
- for(byte r:0..11) {
- byte column = 0;
- for(byte c:0..19) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- while(!getin());
-
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-
-void tile_8_x_8_8BPP_256_color() {
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 8);
- vera_display_set_scale_none();
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[64] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
- };
-
- word tilebase = 0x4000;
- memcpy_to_vram(1, tilebase, tiles, 64);
- tilebase+=64;
- for(byte t:1..255) {
- for(byte p:0..63) {
- tiles[p]+=1;
- }
- memcpy_to_vram(1, tilebase, tiles, 64);
- tilebase+=64;
- }
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- byte row = 1;
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- tile = 0;
- row = 20;
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 8 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 256 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!getin());
-
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-
-void tile_16_x_16_4BPP_16_color() {
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 16, 16, 4);
- vera_display_set_scale_none();
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[2048] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 2048);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- tile = 0;
- byte column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 1, 1, 1, 0, 0, 0);
- column+=4;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 3, 1, 1, 0, 0, 0);
- column+=4;
- tile++;
- }
-
- tile = 0;
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 5, 3, 3, 0, 0, 0);
- column+=4;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 9, 3, 3, 0, 0, 0);
- column+=4;
- tile++;
- }
-
- tile = 0;
- byte offset = 0;
-
- byte row = 13;
-
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, offset);
- column+=1;
- tile++;
- if((c & 0x0f) == 0x0f) offset++;
- tile &= 0x0f;
- }
- row += 1;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 16 x 16, color depth 4 bits per pixel.\n");
-
- printf("in this mode, tiles are 16 pixels wide and 16 pixels tall.\n");
- printf("each tile can have a variation of 16 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!getin());
-}
-
-
-void tile_8_x_8_4BPP_16_color() {
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 4);
- vera_display_set_scale_none();
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[512] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 512);
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- tile = 0;
- byte column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 1, 1, 1, 0, 0, 0);
- column+=8;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 3, 1, 1, 0, 0, 0);
- column+=8;
- tile++;
- }
-
- tile = 0;
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 5, 6, 6, 0, 0, 0);
- column+=8;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 12, 6, 6, 0, 0, 0);
- column+=8;
- tile++;
- }
-
- tile = 0;
- byte offset = 0;
-
- byte row = 20;
-
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, offset);
- column+=2;
- tile++;
- if((c & 0x0f) == 0x0f) offset++;
- tile &= 0x0f;
- }
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 4 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 16 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!getin());
-}
-
-
-void tile_16_x_16_2BPP_4_color() {
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 16, 16, 2);
- vera_display_set_scale_none();
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[256] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 256);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- vera_tile_area(0, 0, 4, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 1, 10, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 2, 16, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 3, 22, 2, 1, 1, 0, 0, 0);
-
- // Draw 4 squares with each tile, starting from row 6, width 4, height 4, separated by 2 characters.
- vera_tile_area(0, 0, 4, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 1, 10, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 2, 16, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 3, 22, 4, 4, 4, 0, 0, 0);
-
- word tile = 0;
- byte offset = 0;
-
- byte row = 10;
-
- for(byte r:0..3) {
- byte column = 4;
- for(byte c:0..16) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, offset);
- column+=2;
- offset++;
- }
- tile++;
- tile &= 0x3;
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 2 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 4 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors, and only the first 4 colors\n");
- printf("can be used per offset!\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!getin());
-}
-
-void tile_8_x_8_2BPP_4_color() {
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 2);
- vera_display_set_scale_none();
-
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- byte tiles[64] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-
- byte map[16] = {0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x03,0x00};
-
- memcpy_to_vram(1, 0x4000, tiles, 64);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- // Draw 4 squares with each tile, staring from row 2, width 10, height 10, separated by 2 characters.
- vera_tile_area(0, 0, 4, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 1, 16, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 2, 28, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 3, 40, 4, 10, 10, 0, 0, 0);
-
- word tile = 0;
- byte offset = 0;
-
- byte row = 22;
-
- for(byte r:0..3) {
- byte column = 4;
- for(byte c:0..15) {
- vera_tile_area(0, tile, column, row, 3, 3, 0, 0, offset);
- column+=4;
- offset++;
- }
- tile++;
- tile &= 0x3;
- row += 4;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 2 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 4 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors, and only the first 4 colors\n");
- printf("can be used per offset!\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!getin());
-}
-
-
-void text_8_x_8_1BPP_256_color() {
-
- // Configure the VERA card to work in text, 256 mode.
- // The color mode is here 256 colors, (256 foreground on a black transparent background).
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
- vera_display_set_scale_none();
- screenlayer(1);
-
- for(byte c:0..255) {
- textcolor(c);
- printf(" ****** ");
- }
-
- vera_layer_show(1);
-
- gotoxy(0,50);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera in text mode 8 x 8, color depth 1 bits per pixel.\n");
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each character can have a variation of 256 foreground colors.\n");
- printf("here we display 6 stars (******) each with a different color.\n");
- printf("however, the first color will always be transparent (black).\n");
- printf("in this mode, the background color cannot be set and is always transparent.\n");
-
- while(!getin());
-}
-
-void text_8_x_8_1BPP_16_color() {
-
- // Configure the VERA card to work in text.
- // The color mode is here 16 colors, (16 foreground and 16 background colors).
- vera_layer_mode_text(1, 0x00000, 0x0F800, 128, 128, 8, 8, 16);
- vera_display_set_scale_none();
- screenlayer(1);
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
-
- for(byte c:0..255) {
- bgcolor(c);
- printf(" ++++++ ");
- }
-
- vera_layer_show(1);
-
- gotoxy(0,50);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera in text mode 8 x 8, color depth 1 bits per pixel.\n");
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each character can have a variation of 16 foreground colors and 16 background colors.\n");
- printf("here we display 6 stars (******) each with a different color.\n");
- printf("however, the first color will always be transparent (black).\n");
- printf("in this mode, the background color cannot be set and is always transparent.\n");
-
- while(!getin());
-}
-
-
-void bitmap_320_x_240_1BPP() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 1);
-
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
- screenlayer(1);
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&1);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>1) color=0;
- x++;
- if(x>319) x=0;
- };
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-void bitmap_640_x_480_1BPP() {
-
- vera_display_set_scale_none();
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 640, 1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),639,0), modr16u(rand(),639,0), modr16u(rand(),399,0), modr16u(rand(),399,0), rand()&1);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 399, color);
- color++;
- if(color>1) color=0;
- x++;
- if(x>639) x=0;
- };
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-void bitmap_320_x_240_2BPP() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 2);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 2 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 4 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&3);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>3) color=0;
- x++;
- if(x>319) x=0;
- };
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-void bitmap_640_x_480_2BPP() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 640, 2);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),639,0), modr16u(rand(),639,0), modr16u(rand(),399,0), modr16u(rand(),399,0), rand()&3);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 399, color);
- color++;
- if(color>3) color=0;
- x++;
- if(x>639) x=0;
- };
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-void bitmap_320_x_240_4BPP() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
-
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 4);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 4 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 16 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&15);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>15) color=0;
- x++;
- if(x>319) x=0;
- };
-
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
-
-void bitmap_320_x_240_8BPP() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 8);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 8 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 256 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!getin()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!getin()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- x++;
- if(x>319) x=0;
- };
-
- memcpy_in_vram(0, 0xF800, VERA_INC_1, 1, 0xF000, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
-}
diff --git a/src/test/kc/examples/cx16/ship.png b/src/test/kc/examples/cx16/ship.png
deleted file mode 100644
index 295195466..000000000
Binary files a/src/test/kc/examples/cx16/ship.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_1.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_1.png
deleted file mode 100644
index 86a26465f..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_1.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_2.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_2.png
deleted file mode 100644
index 2de84d925..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_2.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_3.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_3.png
deleted file mode 100644
index 6e2214315..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_3.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_4.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_4.png
deleted file mode 100644
index 0b142132f..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/frame_4.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_1.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_1.png
deleted file mode 100644
index 7cbec374e..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_1.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_2.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_2.png
deleted file mode 100644
index 162915e83..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_2.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_3.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_3.png
deleted file mode 100644
index 6a08b2887..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_3.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_4.png b/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_4.png
deleted file mode 100644
index f24b5a851..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Metal_1/metal_4.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_1.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_1.png
deleted file mode 100644
index 295195466..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_1.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_10.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_10.png
deleted file mode 100644
index d40a2936f..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_10.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_11.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_11.png
deleted file mode 100644
index 62ad7fb17..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_11.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_12.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_12.png
deleted file mode 100644
index c58128a1d..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_12.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_2.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_2.png
deleted file mode 100644
index b690978fb..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_2.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_3.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_3.png
deleted file mode 100644
index e324623f2..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_3.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_4.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_4.png
deleted file mode 100644
index e25c7f99a..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_4.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_5.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_5.png
deleted file mode 100644
index 9a1920d03..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_5.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_6.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_6.png
deleted file mode 100644
index 6f8717f84..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_6.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_7.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_7.png
deleted file mode 100644
index c5651f50a..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_7.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_8.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_8.png
deleted file mode 100644
index c9930517d..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_8.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_9.png b/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_9.png
deleted file mode 100644
index 544b19308..000000000
Binary files a/src/test/kc/examples/cx16/spacedemo/Ship_1/ship_1_360_9.png and /dev/null differ
diff --git a/src/test/kc/examples/cx16/spacedemo/spacedemo.c b/src/test/kc/examples/cx16/spacedemo/spacedemo.c
deleted file mode 100644
index eba284763..000000000
--- a/src/test/kc/examples/cx16/spacedemo/spacedemo.c
+++ /dev/null
@@ -1,383 +0,0 @@
-// Example program for the Commander X16
-
-#pragma target(cx16)
-#pragma link("spacedemo.ld")
-
-#pragma data_seg(Data)
-
-#include
-#include
-#include
-#include <6502.h>
-#include
-#include
-#include
-#include
-
-const byte NUM_SPRITES = 12;
-const byte NUM_TILES_SMALL = 4;
-const byte NUM_TILES_LARGE = 4;
-
-#pragma data_seg(Palettes)
-__export char* PALETTES;
-
-#pragma data_seg(Sprites)
-__export char SPRITE_PIXELS[] = kickasm(resource "Ship_1/ship_1_360_1.png") {{
- .var pic = LoadPicture("Ship_1/ship_1_360_1.png")
- // palette: rgb->idx
- .var palette = Hashtable()
- // RGB value for each palette index
- .var palList = List()
- // Next palette index
- .var nxt_idx = 0;
- // Extract palette while outputting pixels as palete index values
- .for (var y=0; y<64; y++) {
- .for (var x=0;x<64; x++) {
- // Find palette index (add if not known)
- .var rgb = pic.getPixel(x,y);
- .var idx = palette.get(rgb)
- .if(idx==null) {
- .eval idx = nxt_idx++;
- .eval palette.put(rgb,idx);
- .eval palList.add(rgb)
- }
- }
- }
- .if(nxt_idx>16) .error "Image has too many colours "+nxt_idx
-
- .segment Palettes
- .for(var i=0;i<16;i++) {
- .var rgb = palList.get(i)
- .var red = floor(rgb / [256*256])
- .var green = floor(rgb/256) & 255
- .var blue = rgb & 255
- // bits 4-8: green, bits 0-3 blue
- .byte green&$f0 | blue/16
- // bits bits 0-3 red
- .byte red/16
- }
-
- .segment Sprites
- .for(var p=1;p<=NUM_SPRITES;p++) {
- .var pic = LoadPicture("Ship_1/ship_1_360_" + p + ".png")
- .for (var y=0; y<64; y++) {
- .for (var x=0;x<64; x+=2) {
- // Find palette index (add if not known)
- .var rgb = pic.getPixel(x,y);
- .var idx1 = palette.get(rgb)
- .if(idx1==null) {
- .printnow "unknown rgb value!"
- }
- // Find palette index (add if not known)
- .eval rgb = pic.getPixel(x+1,y);
- .var idx2 = palette.get(rgb)
- .if(idx2==null) {
- .printnow "unknown rgb value!"
- }
- .byte idx1*16+idx2;
- }
- }
- }
-}};
-
-#pragma data_seg(TileS)
-__export char TILE_PIXELS_SMALL[] = kickasm(resource "Metal_1/frame_1.png") {{
- // palette: rgb->idx
- .var palette2 = Hashtable()
- // RGB value for each palette index
- .var palList2 = List()
- // Next palette index
- // Extract palette while outputting pixels as palete index values
- .var nxt_idx2 = 0;
- .for(var p=1;p<=NUM_TILES_SMALL;p++) {
- .var pic = LoadPicture("Metal_1/frame_" + p + ".png")
- .for (var y=0; y<32; y++) {
- .for (var x=0;x<32; x++) {
- // Find palette index (add if not known)
- .var rgb = pic.getPixel(x,y);
- .var idx = palette2.get(rgb)
- .if(idx==null) {
- .eval idx = nxt_idx2++;
- .eval palette2.put(rgb,idx);
- .eval palList2.add(rgb)
- }
- }
- }
- }
- .if(nxt_idx2>16) .error "Image has too many colours "+nxt_idx2
-
- .segment Palettes
- .for(var i=0;i<16;i++) {
- .var rgb = 16*256*256+16*256+16
- .if(iidx
- .var palette3 = Hashtable()
- // RGB value for each palette index
- .var palList3 = List()
- // Next palette index
- .var nxt_idx3 = 0;
- // Extract palette while outputting pixels as palete index values
- .for (var y=0; y<64; y++) {
- .for (var x=0;x<64; x++) {
- // Find palette index (add if not known)
- .var rgb = pic3.getPixel(x,y);
- .var idx = palette3.get(rgb)
- .if(idx==null) {
- .eval idx = nxt_idx3++;
- .eval palette3.put(rgb,idx);
- .eval palList3.add(rgb)
- }
- }
- }
- .if(nxt_idx3>16) .error "Image has too many colours "+nxt_idx3
-
- .segment Palettes
- .for(var i=0;i<16;i++) {
- .var rgb = 0
- .if(iVERA_SPRITE_ATTR, vram_sprite_attr, &SPRITE_ATTR, sizeof(SPRITE_ATTR));
- vram_sprite_attr += sizeof(SPRITE_ATTR);
- sprite_offset += 64;
- }
- // Enable sprites
- *VERA_CTRL &= ~VERA_DCSEL;
- *VERA_DC_VIDEO |= VERA_SPRITES_ENABLE;
- // Enable VSYNC IRQ (also set line bit 8 to 0)
- SEI();
- *KERNEL_IRQ = &irq_vsync;
- *VERA_IEN = VERA_VSYNC;
- CLI();
-
- while(!getin());
-}
-
-volatile byte i = 0;
-volatile byte a = 4;
-volatile word vscroll = 0;
-volatile word scroll_action = 2;
-
-// VSYNC Interrupt Routine
-__interrupt(rom_sys_cx16) void irq_vsync() {
- // Move the sprite around
-
- a--;
- if(a==0) {
- a=4;
- const char vram_sprite_attr_bank = (char)>VERA_SPRITE_ATTR;
- char *vram_sprite_attr = (char*)=NUM_SPRITES) {
- x-=NUM_SPRITES;
- }
- SPRITE_ATTR.ADDR = sprites[x];
- SPRITE_ATTR.X = (word)40+((word)(s&03)<<7);
- SPRITE_ATTR.Y = (word)100+((word)(s>>2)<<7);
- // Copy sprite positions to VRAM (the 4 relevant bytes in VERA_SPRITE_ATTR)
- memcpy_to_vram(vram_sprite_attr_bank, vram_sprite_attr, &SPRITE_ATTR, 6);
- vram_sprite_attr += sizeof(SPRITE_ATTR);
- }
-
- i++;
- if(i>=NUM_SPRITES) i=0;
-
- }
-
- if(scroll_action--) {
- scroll_action = 2;
- vscroll++;
- if(vscroll>(32+64)*2-1) vscroll=0;
- vera_layer_set_vertical_scroll(0,vscroll);
- }
-
- // Reset the VSYNC interrupt
- *VERA_ISR = VERA_VSYNC;
-}
diff --git a/src/test/kc/examples/cx16/spacedemo/spacedemo.ld b/src/test/kc/examples/cx16/spacedemo/spacedemo.ld
deleted file mode 100644
index 59bb4b240..000000000
--- a/src/test/kc/examples/cx16/spacedemo/spacedemo.ld
+++ /dev/null
@@ -1,16 +0,0 @@
-// Create a bunch of files
-.file [name="%O", type="prg", segments="Program"]
-.file [name="SPRITES", type="bin", segments="Sprites"]
-.file [name="TILES", type="bin", segments="TileS"]
-.file [name="TILEB", type="bin", segments="TileB"]
-.file [name="PALETTES", type="bin", segments="Palettes"]
-.segmentdef Program [segments="Basic, Code, Data"]
-.segmentdef Basic [start=$0801]
-.segmentdef Code [start=%P]
-.segmentdef Data [startAfter="Code"]
-.segment Basic
-:BasicUpstart(%E)
-.segmentdef Sprites
-.segmentdef TileS
-.segmentdef TileB
-.segmentdef Palettes
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_1bpp_320_x_240.c b/src/test/kc/examples/cx16/veralib/bitmap_1bpp_320_x_240.c
deleted file mode 100644
index 929041d74..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_1bpp_320_x_240.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA graphic modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&1);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>1) color=0;
- x++;
- if(x>319) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_1bpp_640_x_480.c b/src/test/kc/examples/cx16/veralib/bitmap_1bpp_640_x_480.c
deleted file mode 100644
index 486fe5175..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_1bpp_640_x_480.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA graphic modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 640, 1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),639,0), modr16u(rand(),639,0), modr16u(rand(),399,0), modr16u(rand(),399,0), rand()&1);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 399, color);
- color++;
- if(color>1) color=0;
- x++;
- if(x>639) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_2bpp_320_x_240.c b/src/test/kc/examples/cx16/veralib/bitmap_2bpp_320_x_240.c
deleted file mode 100644
index c2d3d0801..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_2bpp_320_x_240.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA graphic modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 2);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 2 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 4 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&3);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>3) color=0;
- x++;
- if(x>319) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_2bpp_640_x_480.c b/src/test/kc/examples/cx16/veralib/bitmap_2bpp_640_x_480.c
deleted file mode 100644
index e04945d8d..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_2bpp_640_x_480.c
+++ /dev/null
@@ -1,79 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA graphic modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 640, 2);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("vera in bitmap mode,\n");
- printf("color depth 1 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 2 colors (black or color).\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),639,0), modr16u(rand(),639,0), modr16u(rand(),399,0), modr16u(rand(),399,0), rand()&3);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,54);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,59);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 399, color);
- color++;
- if(color>3) color=0;
- x++;
- if(x>639) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_4bpp_320_x_240.c b/src/test/kc/examples/cx16/veralib/bitmap_4bpp_320_x_240.c
deleted file mode 100644
index e453a0a52..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_4bpp_320_x_240.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA graphic modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
-
- memcpy_in_vram(1, 0xF000, VERA_INC_1, 0, 0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 4);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 4 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 16 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&15);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- if(color>15) color=0;
- x++;
- if(x>319) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/bitmap_8bpp_320_x_240.c b/src/test/kc/examples/cx16/veralib/bitmap_8bpp_320_x_240.c
deleted file mode 100644
index 2c278e44c..000000000
--- a/src/test/kc/examples/cx16/veralib/bitmap_8bpp_320_x_240.c
+++ /dev/null
@@ -1,83 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-// The default layer of the CX16 is layer 1, but the tiles are written on layer 0.
-
-// An explanation is given how this mode is organized, and how the tiles display and coloring works.
-// Pälette offsets are explained also.
-
-#pragma target(cx16)
-#include
-#include
-#include
-#include
-#include
-#include
-
-void main() {
-
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- memcpy_in_vram(1, (char*)0xF000, VERA_INC_1, 0, (char*)0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1);
-
- vera_layer_mode_bitmap(0, (dword)0x00000, 320, 8);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,25);
- printf("vera in bitmap mode,\n");
- printf("color depth 8 bits per pixel.\n");
- printf("in this mode, it is possible to display\n");
- printf("graphics in 256 colors.\n");
-
- vera_layer_show(0);
-
- bitmap_init(0, 0x00000);
- bitmap_clear();
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- while(!kbhit()) {
- bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255);
- };
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- gotoxy(0,26);
- printf("here you see all the colors possible.\n");
-
- gotoxy(0,29);
- textcolor(YELLOW);
- printf("press a key ...");
-
- word x = 0;
- byte color = 0;
- while(!kbhit()) {
- bitmap_line(x, x, 0, 199, color);
- color++;
- x++;
- if(x>319) x=0;
- };
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_16_color.c b/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_16_color.c
deleted file mode 100644
index 60552bafe..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_16_color.c
+++ /dev/null
@@ -1,43 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- // Configure the VERA card to work in text, 16x16 mode.
- // The color mode is here 16 colors, indicating 16x16 color mode, (16 foreground and 16 background colors).
- vera_layer_set_text_color_mode( 1, VERA_LAYER_CONFIG_16C );
-
- // or you can use the below statement, but that includes setting a "mode", including
- // layer, map base address, tile base address, map width, map height, tile width, tile height, color mode.
- //vera_layer_mode_text(1, 0x00000, 0x0F800, 128, 128, 8, 8, 16);
-
- for(byte c:0..255) {
- bgcolor(c);
- printf(" ****** ");
- }
-
- vera_layer_show(1);
-
- gotoxy(0,50);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera in text mode 8 x 8, color depth 1 bits per pixel.\n");
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each character can have a variation of 16 foreground colors and 16 background colors.\n");
- printf("here we display 6 stars (******) each with a different color.\n");
- printf("however, the first color will always be transparent (black).\n");
- printf("in this mode, the background color cannot be set and is always transparent.\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_256_color.c b/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_256_color.c
deleted file mode 100644
index 878135d98..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_1bpp_8_x_8_256_color.c
+++ /dev/null
@@ -1,43 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- // Configure the VERA card to work in text, 256 mode.
- // The color mode is here 256 colors, (256 foreground on a black transparent background).
- vera_layer_mode_text( 1, 0x00000, 0x0F800, 128, 128, 8, 8, 256 );
-
- // or you can use the below statement, but that includes setting a "mode", including
- // layer, map base address, tile base address, map width, map height, tile width, tile height, color mode.
- //vera_layer_mode_text(1, 0x00000, 0x0F800, 128, 128, 8, 8, 256);
-
- for(byte c:0..255) {
- textcolor(c);
- printf(" ****** ");
- }
-
- vera_layer_show(1);
-
- gotoxy(0,50);
- textcolor(WHITE);
- bgcolor(BLACK);
- printf("vera in text mode 8 x 8, color depth 1 bits per pixel.\n");
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each character can have a variation of 256 foreground colors.\n");
- printf("here we display 6 stars (******) each with a different color.\n");
- printf("however, the first color will always be transparent (black).\n");
- printf("in this mode, the background color cannot be set and is always transparent.\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_2bpp_16_x_16.c b/src/test/kc/examples/cx16/veralib/tilemap_2bpp_16_x_16.c
deleted file mode 100644
index d7ef652ab..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_2bpp_16_x_16.c
+++ /dev/null
@@ -1,88 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 16, 16, 2);
-
- byte tiles[256] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 256);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- vera_tile_area(0, 0, 4, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 1, 10, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 2, 16, 2, 1, 1, 0, 0, 0);
- vera_tile_area(0, 3, 22, 2, 1, 1, 0, 0, 0);
-
- // Draw 4 squares with each tile, starting from row 6, width 4, height 4, separated by 2 characters.
- vera_tile_area(0, 0, 4, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 1, 10, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 2, 16, 4, 4, 4, 0, 0, 0);
- vera_tile_area(0, 3, 22, 4, 4, 4, 0, 0, 0);
-
- word tile = 0;
- byte offset = 0;
-
- byte row = 10;
-
- for(byte r:0..3) {
- byte column = 4;
- for(byte c:0..16) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, offset);
- column+=2;
- offset++;
- }
- tile++;
- tile &= 0x3;
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 2 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 4 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors, and only the first 4 colors\n");
- printf("can be used per offset!\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_2bpp_8_x_8.c b/src/test/kc/examples/cx16/veralib/tilemap_2bpp_8_x_8.c
deleted file mode 100644
index c5889a321..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_2bpp_8_x_8.c
+++ /dev/null
@@ -1,70 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 2);
-
- byte tiles[64] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
-
- byte map[16] = {0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x02,0x00,0x02,0x00,0x03,0x00,0x03,0x00};
-
- memcpy_to_vram(1, 0x4000, tiles, 64);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- // Draw 4 squares with each tile, staring from row 2, width 10, height 10, separated by 2 characters.
- vera_tile_area(0, 0, 4, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 1, 16, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 2, 28, 4, 10, 10, 0, 0, 0);
- vera_tile_area(0, 3, 40, 4, 10, 10, 0, 0, 0);
-
- word tile = 0;
- byte offset = 0;
-
- byte row = 22;
-
- for(byte r:0..3) {
- byte column = 4;
- for(byte c:0..15) {
- vera_tile_area(0, tile, column, row, 3, 3, 0, 0, offset);
- column+=4;
- offset++;
- }
- tile++;
- tile &= 0x3;
- row += 4;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 2 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 4 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors, and only the first 4 colors\n");
- printf("can be used per offset!\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_4bpp_16_x_16.c b/src/test/kc/examples/cx16/veralib/tilemap_4bpp_16_x_16.c
deleted file mode 100644
index b627f71d5..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_4bpp_16_x_16.c
+++ /dev/null
@@ -1,218 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 16, 16, 4);
-
- byte tiles[2048] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 2048);
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- tile = 0;
- byte column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 1, 1, 1, 0, 0, 0);
- column+=4;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 3, 1, 1, 0, 0, 0);
- column+=4;
- tile++;
- }
-
- tile = 0;
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 5, 3, 3, 0, 0, 0);
- column+=4;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 9, 3, 3, 0, 0, 0);
- column+=4;
- tile++;
- }
-
- tile = 0;
- byte offset = 0;
-
- byte row = 13;
-
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, offset);
- column+=1;
- tile++;
- if((c & 0x0f) == 0x0f) offset++;
- tile &= 0x0f;
- }
- row += 1;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 16 x 16, color depth 4 bits per pixel.\n");
-
- printf("in this mode, tiles are 16 pixels wide and 16 pixels tall.\n");
- printf("each tile can have a variation of 16 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_4bpp_8_x_8.c b/src/test/kc/examples/cx16/veralib/tilemap_4bpp_8_x_8.c
deleted file mode 100644
index 437d609b4..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_4bpp_8_x_8.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 4);
-
- byte tiles[512] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,0x11,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,0x33,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,0x44,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,0x77,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,0x88,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,0x99,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,0xDD,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,0xEE,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- };
-
- memcpy_to_vram(1, 0x4000, tiles, 512);
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- tile = 0;
- byte column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 1, 1, 1, 0, 0, 0);
- column+=8;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 3, 1, 1, 0, 0, 0);
- column+=8;
- tile++;
- }
-
- tile = 0;
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 5, 6, 6, 0, 0, 0);
- column+=8;
- tile++;
- }
- column = 1;
- for(byte c:0..7) {
- vera_tile_area(0, tile, column, 12, 6, 6, 0, 0, 0);
- column+=8;
- tile++;
- }
-
- tile = 0;
- byte offset = 0;
-
- byte row = 20;
-
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, offset);
- column+=2;
- tile++;
- if((c & 0x0f) == 0x0f) offset++;
- tile &= 0x0f;
- }
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 4 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 16 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_8bpp_16_x_16.c b/src/test/kc/examples/cx16/veralib/tilemap_8bpp_16_x_16.c
deleted file mode 100644
index 0f151f3b3..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_8bpp_16_x_16.c
+++ /dev/null
@@ -1,133 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
-
- byte tiles[256] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- };
-
- // Before we can load the tiles into memory we need to re-arrange a few things!
- // The amount of tiles is 256, the color depth is 256, so each tile is 256 bytes!
- // That is 65356 bytes of memory, which is 64K. Yup! One memory bank in VRAM.
- // VERA VRAM holds in bank 1 many registers that interfere loading all of this data.
- // So it is better to load all in bank 0, but then there is an other issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x10000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
-
- memcpy_in_vram(1, (char*)0xF000, VERA_INC_1, 0, (char*)0xF800, VERA_INC_1, 256*8); // We copy the 128 character set of 8 bytes each.
- vera_layer_mode_tile(1, 0x10000, 0x1F000, 128, 64, 8, 8, 1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- // Now we can use the full bank 0!
- // We set the mapbase of the tile demo to output to 0x12000,
- // and the tilebase is set to 0x0000!
- vera_layer_mode_tile(0, 0x14000, 0x00000, 64, 64, 16, 16, 8);
-
-
- char* tilebase = (char*)0x0000;
- memcpy_to_vram(0, tilebase, tiles, 256);
- tilebase+=256;
- for(byte t:1..255) {
- for(byte p:0..255) {
- tiles[p]+=1;
- }
- memcpy_to_vram(0, tilebase, tiles, 256);
- tilebase+=256;
- }
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- byte row = 1;
- for(byte r:0..11) {
- byte column = 0;
- for(byte c:0..19) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 8 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 256 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- vera_layer_show(0);
-
- while(!kbhit());
-
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
-
- tile = 0;
- row = 0;
- for(byte r:0..11) {
- byte column = 0;
- for(byte c:0..19) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- while(!kbhit());
-
- // Now put back the defaults ...
- vera_tile_area(0, 0, 0, 0, 40, 30, 0, 0, 0);
- vera_layer_hide(0);
- memcpy_in_vram(0, (char*)0xF800, VERA_INC_1, 1, (char*)0xF000, VERA_INC_1, 256*8);
- vera_layer_mode_tile(1, 0x00000, 0x0F800, 128, 128, 8, 8, 1);
- vera_layer_mode_tile(0, 0x00000, 0x0F800, 128, 128, 8, 8, 1);
-
- screenlayer(1);
- textcolor(WHITE);
- bgcolor(BLUE);
- clrscr();
-
-}
diff --git a/src/test/kc/examples/cx16/veralib/tilemap_8bpp_8_x_8.c b/src/test/kc/examples/cx16/veralib/tilemap_8bpp_8_x_8.c
deleted file mode 100644
index 6061005d6..000000000
--- a/src/test/kc/examples/cx16/veralib/tilemap_8bpp_8_x_8.c
+++ /dev/null
@@ -1,87 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-
-// Author: Sven Van de Velde
-
-#pragma target(cx16)
-#include
-#include
-#include
-
-void main() {
-
- textcolor(WHITE);
- bgcolor(BLACK);
- clrscr();
-
- vera_layer_mode_tile(0, 0x04000, 0x14000, 128, 128, 8, 8, 8);
-
- byte tiles[64] = {
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
- };
-
- char* tilebase = (char*)0x4000;
- memcpy_to_vram(1, tilebase, tiles, 64);
- tilebase+=64;
- for(byte t:1..255) {
- for(byte p:0..63) {
- tiles[p]+=1;
- }
- memcpy_to_vram(1, tilebase, tiles, 64);
- tilebase+=64;
- }
-
- //vera_tile_area(byte layer, word tileindex, byte x, byte y, byte w, byte h, byte hflip, byte vflip, byte offset)
-
- vera_tile_area(0, 0, 0, 0, 80, 60, 0, 0, 0);
-
- word tile = 0;
-
- // Draw 4 squares with each tile, starting from row 4, width 1, height 1, separated by 2 characters.
- byte row = 1;
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 1, 1, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- tile = 0;
- row = 20;
- for(byte r:0..7) {
- byte column = 1;
- for(byte c:0..31) {
- vera_tile_area(0, tile, column, row, 2, 2, 0, 0, 0);
- column+=2;
- tile++;
- tile &= 0xff;
- }
- row += 2;
- }
-
- vera_layer_show(0);
-
- gotoxy(0,50);
- printf("vera in tile mode 8 x 8, color depth 8 bits per pixel.\n");
-
- printf("in this mode, tiles are 8 pixels wide and 8 pixels tall.\n");
- printf("each tile can have a variation of 256 colors.\n");
- printf("the vera palette of 256 colors, can be used by setting the palette\n");
- printf("offset for each tile.\n");
- printf("here each column is displaying the same tile, but with different offsets!\n");
- printf("each offset aligns to multiples of 16 colors in the palette!.\n");
- printf("however, the first color will always be transparent (black).\n");
-
- while(!kbhit());
-}
diff --git a/src/test/kc/examples/memfast/memfast.c b/src/test/kc/examples/memfast/memfast.c
new file mode 100644
index 000000000..0023f4da3
--- /dev/null
+++ b/src/test/kc/examples/memfast/memfast.c
@@ -0,0 +1,39 @@
+/**
+ * @file memfast.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @brief Demonstration of functions memcpy_fast and memset_fast
+ * for 8 bit architectures.
+ * @version 0.1
+ * @date 2023-04-14
+ *
+ * @copyright Copyright (c) 2023
+ *
+ */
+
+#include
+#include
+#include
+
+
+void main() {
+ const char* screen = (char*)0x0400;
+ const char* bottom = (char*)0x0400 + 40*12;
+
+ // Show mixed chars on screen
+ *((char*)0xd018) = 0x17;
+
+ // Clear screen
+ clrscr();
+
+ for(char i:0..255) {
+ memset_fast(screen, i, 256); // 256 will be truncated to 0, which will copy 256 bytes!
+ memcpy_fast(bottom, screen, 256);
+ }
+
+ // There is a longer term plan to allow these calls to be written as "inline" ...
+ // Which would give the programmer the means to decide how the code should
+ // be generated for these copy functions.
+ // inline memset_fast(screen, i, 256); // 256 will be truncated to 0, which will copy 256 bytes!
+ // inline memcpy_fast(bottom, screen, 256);
+
+}
\ No newline at end of file
diff --git a/src/test/kc/pragma-noparam-noparen.c b/src/test/kc/pragma-noparam-noparen.c
new file mode 100644
index 000000000..2d9fe466b
--- /dev/null
+++ b/src/test/kc/pragma-noparam-noparen.c
@@ -0,0 +1,8 @@
+// Test that #pragma works with no parenthesis and no parameters
+
+#pragma nobank
+
+void main() {
+ char * const SCREEN = (char*) 0x0400;
+ *SCREEN = 'a';
+}
\ No newline at end of file
diff --git a/src/test/kc/union-10.c b/src/test/kc/union-10.c
new file mode 100644
index 000000000..e05a9d461
--- /dev/null
+++ b/src/test/kc/union-10.c
@@ -0,0 +1,27 @@
+// More extensive union with C99 style designator initialization behaviour of the second element.
+
+struct Move {
+ char f;
+ char t;
+ char s;
+};
+
+struct Turn {
+ char t;
+ char s;
+ char r;
+ char d;
+};
+
+union Data {
+ struct Move m;
+ struct Turn t;
+};
+
+union Data data = { .t={1,2,3,4} };
+
+char* const SCREEN = (char*)0x0400;
+
+void main() {
+ SCREEN[0] = data.m.f;
+}
\ No newline at end of file
diff --git a/src/test/kc/union-11.c b/src/test/kc/union-11.c
new file mode 100644
index 000000000..840f4c9a0
--- /dev/null
+++ b/src/test/kc/union-11.c
@@ -0,0 +1,27 @@
+// More extensive union with C99 style designator initialization behaviour of the first element.
+
+struct Move {
+ char f;
+ char t;
+ char s;
+};
+
+struct Turn {
+ char t;
+ char s;
+ char r;
+ char d;
+};
+
+union Data {
+ struct Move m;
+ struct Turn t;
+};
+
+union Data data = { .m={1,2,3} };
+
+char* const SCREEN = (char*)0x0400;
+
+void main() {
+ SCREEN[0] = data.m.f;
+}
\ No newline at end of file
diff --git a/src/test/kc/union-12.c b/src/test/kc/union-12.c
new file mode 100644
index 000000000..a6e084637
--- /dev/null
+++ b/src/test/kc/union-12.c
@@ -0,0 +1,29 @@
+// More extensive union with C99 style designator initialization behaviour using const expressions.
+
+struct Move {
+ char f;
+ char t;
+ char s;
+};
+
+struct Turn {
+ char t;
+ char s;
+ char r;
+ char d;
+};
+
+union Data {
+ struct Move m;
+ struct Turn t;
+};
+
+const struct Move move = {1,2,3};
+
+union Data data = { .m=move };
+
+char* const SCREEN = (char*)0x0400;
+
+void main() {
+ SCREEN[0] = data.m.f;
+}
\ No newline at end of file
diff --git a/src/test/kc/union-13.c b/src/test/kc/union-13.c
new file mode 100644
index 000000000..fbfb6d8f4
--- /dev/null
+++ b/src/test/kc/union-13.c
@@ -0,0 +1,20 @@
+// More extensive union with C99 style designator initialization behaviour using const expressions.
+
+union A {
+ unsigned char b;
+ unsigned int w;
+};
+
+union B {
+ union A a;
+ char b[4];
+};
+
+union B b1 = { .a={ .b=1 } };
+
+
+char* const SCREEN = (char*)0x0400;
+
+void main() {
+ SCREEN[0] = b1.b[0];
+}
\ No newline at end of file
diff --git a/src/test/kc/union-9.c b/src/test/kc/union-9.c
new file mode 100644
index 000000000..bf7a6dd30
--- /dev/null
+++ b/src/test/kc/union-9.c
@@ -0,0 +1,14 @@
+// Minimal union with C99 style designator initialization behaviour.
+
+union Data {
+ char b;
+ unsigned w;
+};
+
+union Data data = { .w=1234 };
+
+char* const SCREEN = (char*)0x0400;
+
+void main() {
+ SCREEN[0] = data.b;
+}
\ No newline at end of file
diff --git a/src/test/kc/varcall-5.c b/src/test/kc/varcall-5.c
index 0e0b1cd1a..e6b7f18d1 100644
--- a/src/test/kc/varcall-5.c
+++ b/src/test/kc/varcall-5.c
@@ -6,10 +6,17 @@ struct Cols {
char bg;
};
-struct Cols * const COLS = (struct Cols *)0xd020;
+struct Cols * const COLS = (struct Cols * const)0xd020;
struct Cols a;
+__varcall struct Cols make(char v) {
+ struct Cols c;
+ c.border = v;
+ c.bg = v+v;
+ return c;
+}
+
void main() {
a = make(1);
*COLS = a;
@@ -17,6 +24,3 @@ void main() {
*COLS = a;
}
-__varcall struct Cols make(char v) {
- return { v, v+v };
-}
diff --git a/src/test/kc/varcall-6.c b/src/test/kc/varcall-6.c
index f5e00cc96..41c23d687 100644
--- a/src/test/kc/varcall-6.c
+++ b/src/test/kc/varcall-6.c
@@ -8,15 +8,15 @@ struct Cols {
struct Cols * const COLS = (struct Cols *)0xd020;
-void main() {
- struct Cols a = { 1, 2 };
- //*COLS = a;
- a = plus(a, { 2, 3 } );
- *COLS = a;
- //a = plus(a, a);
- //*COLS = a;
-}
-
__varcall struct Cols plus(struct Cols a, struct Cols b) {
return { a.border+b.border, a.bg+b.bg };
-}
\ No newline at end of file
+}
+
+
+void main() {
+ struct Cols a = { 1, 2 };
+ struct Cols c = plus(a, { 2, 3 });
+ *COLS = c;
+ c = plus(c, a);
+ *COLS = c;
+}
diff --git a/src/test/kc/varcall-7.c b/src/test/kc/varcall-7.c
new file mode 100644
index 000000000..83d418bee
--- /dev/null
+++ b/src/test/kc/varcall-7.c
@@ -0,0 +1,21 @@
+// Test __varcall calling convention
+// Struct parameter & return value - only a single call
+
+struct Cols {
+ char border;
+ char bg;
+};
+
+struct Cols * const COLS = (struct Cols *)0xd020;
+
+__varcall struct Cols plus(struct Cols a, struct Cols b) {
+ return { a.border+b.border, a.bg+b.bg };
+}
+
+
+void main() {
+ struct Cols a = { 1, 2 };
+ struct Cols b = { 2, 3 };
+ struct Cols c = plus(a, b);
+ *COLS = c;
+}
diff --git a/src/test/kc/varcall-8.c b/src/test/kc/varcall-8.c
new file mode 100644
index 000000000..be744f1b3
--- /dev/null
+++ b/src/test/kc/varcall-8.c
@@ -0,0 +1,28 @@
+// Test __varcall calling convention
+// Pointer to Struct parameter & return value
+
+struct Cols {
+ char border;
+ char bg;
+};
+
+struct Cols * const COLS = (struct Cols *)0xd020;
+
+__varcall struct Cols * min(struct Cols * a, struct Cols * b) {
+ if(a->bg < b->bg)
+ return a;
+ else
+ return b;
+
+}
+
+
+void main() {
+ struct Cols a = { 1, 7 };
+ struct Cols b = { 2, 6 };
+ struct Cols c = { 3, 5 };
+ struct Cols *m = min(&a,&b);
+ *COLS = *m;
+ m = min(m,&c);
+ *COLS = *m;
+}
diff --git a/src/test/kc/varcall-9.c b/src/test/kc/varcall-9.c
new file mode 100644
index 000000000..b72b75bba
--- /dev/null
+++ b/src/test/kc/varcall-9.c
@@ -0,0 +1,26 @@
+// Test __varcall calling convention
+// Struct of struct parameter value
+
+struct Col {
+ char border;
+ char bg;
+};
+
+struct Cols {
+ struct Col normal;
+ struct Col error;
+};
+
+char * const COLS = (char*)0xd020;
+
+__varcall char plus(struct Cols a, struct Cols b) {
+ return a.normal.border + b.normal.border + a.normal.bg + b.normal.bg + a.error.border + b.error.border + a.error.bg + b.error.bg;
+}
+
+void main() {
+ struct Cols a = { { 1, 2 }, { 3, 4 }};
+ struct Cols b = { { 5, 6 }, { 7, 8 }};
+ struct Cols c = { { 9, 10 }, { 11, 12 }};
+ *COLS = plus(a, b);
+ *COLS = plus(b, c);
+}
diff --git a/src/test/ref/asm-culling-jmp.asm b/src/test/ref/asm-culling-jmp.asm
index 39c886fa8..152a669fe 100644
--- a/src/test/ref/asm-culling-jmp.asm
+++ b/src/test/ref/asm-culling-jmp.asm
@@ -12,7 +12,7 @@
main: {
// asm
jmp qwe
- .byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
+ .byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
qwe:
lda #$32
// *((char*)0x0400) = 'c'
diff --git a/src/test/ref/asm-culling-jmp.log b/src/test/ref/asm-culling-jmp.log
index 8f295f1ae..9870ae91e 100644
--- a/src/test/ref/asm-culling-jmp.log
+++ b/src/test/ref/asm-culling-jmp.log
@@ -83,7 +83,7 @@ ASSEMBLER BEFORE OPTIMIZATION
main: {
// asm { jmpqwe .byte0,25,51,76,102,128,153,179,204,230 qwe: lda#50 }
jmp qwe
- .byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
+ .byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
qwe:
lda #$32
// [1] *((char *) 1024) = 'c' -- _deref_pbuc1=vbuc2
@@ -130,7 +130,7 @@ main: {
// asm
// asm { jmpqwe .byte0,25,51,76,102,128,153,179,204,230 qwe: lda#50 }
jmp qwe
- .byte 0, 25, 51, 76, 102, 128, 153, 179, 204, 230
+ .byte 0, $19, $33, $4c, $66, $80, $99, $b3, $cc, $e6
qwe:
lda #$32
// *((char*)0x0400) = 'c'
diff --git a/src/test/ref/c64dtv-8bppcharstretch.asm b/src/test/ref/c64dtv-8bppcharstretch.asm
index 13c88352a..8fadfc7eb 100644
--- a/src/test/ref/c64dtv-8bppcharstretch.asm
+++ b/src/test/ref/c64dtv-8bppcharstretch.asm
@@ -457,7 +457,7 @@ dtvSetCpuBankSegment1: {
// asm
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
// }
rts
}
diff --git a/src/test/ref/c64dtv-8bppcharstretch.log b/src/test/ref/c64dtv-8bppcharstretch.log
index 4c5a4bc2e..9e674183c 100644
--- a/src/test/ref/c64dtv-8bppcharstretch.log
+++ b/src/test/ref/c64dtv-8bppcharstretch.log
@@ -1872,7 +1872,7 @@ dtvSetCpuBankSegment1: {
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
jmp __breturn
// dtvSetCpuBankSegment1::@return
__breturn:
@@ -2714,7 +2714,7 @@ dtvSetCpuBankSegment1: {
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
// dtvSetCpuBankSegment1::@return
// }
// [87] return
diff --git a/src/test/ref/c64dtv-8bppchunkystretch.asm b/src/test/ref/c64dtv-8bppchunkystretch.asm
index 7ebe19652..becb0cb59 100644
--- a/src/test/ref/c64dtv-8bppchunkystretch.asm
+++ b/src/test/ref/c64dtv-8bppchunkystretch.asm
@@ -365,7 +365,7 @@ dtvSetCpuBankSegment1: {
// asm
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
// }
rts
}
diff --git a/src/test/ref/c64dtv-8bppchunkystretch.log b/src/test/ref/c64dtv-8bppchunkystretch.log
index cc100204f..932a1908c 100644
--- a/src/test/ref/c64dtv-8bppchunkystretch.log
+++ b/src/test/ref/c64dtv-8bppchunkystretch.log
@@ -1260,7 +1260,7 @@ dtvSetCpuBankSegment1: {
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
jmp __breturn
// dtvSetCpuBankSegment1::@return
__breturn:
@@ -1881,7 +1881,7 @@ dtvSetCpuBankSegment1: {
// asm { .byte$32,$dd lda$ff .byte$32,$00 }
.byte $32, $dd
lda.z $ff
- .byte $32, $00
+ .byte $32, 0
// dtvSetCpuBankSegment1::@return
// }
// [57] return
diff --git a/src/test/ref/call-banked-phi-case-1-near-0.asm b/src/test/ref/call-banked-phi-case-1-near-0.asm
new file mode 100644
index 000000000..9c88aba31
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-0.asm
@@ -0,0 +1,70 @@
+/**
+ * @file call-banked-phi-case-1-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-1-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ lda #7
+ ldx #'0'
+ jsr plus
+ // plus('0', 7)
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ lda #6
+ ldx #'1'
+ jsr plus
+ // plus('1', 6)
+ // SCREEN[1] = plus('1', 6)
+ // near call
+ sta SCREEN+1
+ // }
+ rts
+}
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // a+b
+ stx.z $ff
+ clc
+ adc.z $ff
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-1-near-0.cfg b/src/test/ref/call-banked-phi-case-1-near-0.cfg
new file mode 100644
index 000000000..936abd391
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-0.cfg
@@ -0,0 +1,30 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-1-near-0.log b/src/test/ref/call-banked-phi-case-1-near-0.log
new file mode 100644
index 000000000..2ffa84883
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-0.log
@@ -0,0 +1,462 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ plus::$0 = plus::a#2 + plus::b#2
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ plus::return#6 = phi( plus/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+void main()
+char main::$0
+char main::$1
+char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Successful SSA optimization Pass2AliasElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 11.0
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ plus::return#2 ]
+Allocated zp[1]:2 [ plus::a#2 ]
+Allocated zp[1]:3 [ plus::b#2 ]
+Allocated zp[1]:4 [ plus::return#0 ]
+Allocated zp[1]:5 [ main::$0 ]
+Allocated zp[1]:6 [ plus::return#1 ]
+Allocated zp[1]:7 [ main::$1 ]
+Allocated zp[1]:8 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [11] plus::return#2 = plus::a#2 + plus::b#2 [ plus::return#2 ] ( plus:1 [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } plus:5 [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Potential registers zp[1]:2 [ plus::a#2 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ plus::b#2 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ plus::return#0 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ main::$0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:6 [ plus::return#1 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ main::$1 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#2 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [plus] 11: zp[1]:2 [ plus::a#2 ] 11: zp[1]:3 [ plus::b#2 ] 4: zp[1]:4 [ plus::return#0 ] 4: zp[1]:6 [ plus::return#1 ] 3.75: zp[1]:8 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:5 [ main::$0 ] 4: zp[1]:7 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [plus] best 81 combination reg byte x [ plus::a#2 ] reg byte a [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:8 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 1024 possible.
+Uplifting [main] best 69 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 69 combination
+Attempting to uplift remaining variables inzp[1]:8 [ plus::return#2 ]
+Uplifting [plus] best 60 combination reg byte a [ plus::return#2 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-1-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-1-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuaa=vbuc1
+ lda #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- vbuxx=vbuc1
+ ldx #'0'
+ jsr plus
+ // [2] plus::return#0 = plus::return#2
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuaa=vbuc1
+ lda #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- vbuxx=vbuc1
+ ldx #'1'
+ jsr plus
+ // [6] plus::return#1 = plus::return#2
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // near call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+ // plus
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuaa=vbuxx_plus_vbuaa
+ stx.z $ff
+ clc
+ adc.z $ff
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [12] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte x 11.0
+char plus::b
+char plus::b#2 // reg byte a 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte a 3.75
+
+reg byte x [ plus::a#2 ]
+reg byte a [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte a [ plus::return#2 ]
+
+
+FINAL ASSEMBLER
+Score: 48
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-1-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be)
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-1-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuaa=vbuc1
+ lda #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- vbuxx=vbuc1
+ ldx #'0'
+ jsr plus
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuaa=vbuc1
+ lda #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- vbuxx=vbuc1
+ ldx #'1'
+ jsr plus
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // near call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+ // plus
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // a+b
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuaa=vbuxx_plus_vbuaa
+ stx.z $ff
+ clc
+ adc.z $ff
+ // plus::@return
+ // }
+ // [12] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-1-near-0.sym b/src/test/ref/call-banked-phi-case-1-near-0.sym
new file mode 100644
index 000000000..aad9eb173
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-0.sym
@@ -0,0 +1,21 @@
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte x 11.0
+char plus::b
+char plus::b#2 // reg byte a 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte a 3.75
+
+reg byte x [ plus::a#2 ]
+reg byte a [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte a [ plus::return#2 ]
diff --git a/src/test/ref/call-banked-phi-case-1-near-1.asm b/src/test/ref/call-banked-phi-case-1-near-1.asm
new file mode 100644
index 000000000..c5395e6ac
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-1.asm
@@ -0,0 +1,78 @@
+/**
+ * @file call-banked-phi-case-1-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-1-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ lda #7
+ ldx #'0'
+ jsr plus
+ // plus('0', 7)
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ lda #6
+ ldx #'1'
+ jsr plus
+ // plus('1', 6)
+ // SCREEN[1] = plus('1', 6)
+ // near call
+ sta SCREEN+1
+ // }
+ rts
+}
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // add(a, b)
+ stx.z add.a
+ jsr add
+ // }
+ rts
+}
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-1-near-1.cfg b/src/test/ref/call-banked-phi-case-1-near-1.cfg
new file mode 100644
index 000000000..bd8833228
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-1.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-1-near-1.log b/src/test/ref/call-banked-phi-case-1-near-1.log
new file mode 100644
index 000000000..916bd8ab3
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-1.log
@@ -0,0 +1,599 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 129 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 99 combination reg byte x [ plus::a#2 ] reg byte a [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 1024 possible.
+Uplifting [main] best 87 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 87 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 87 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 78 combination reg byte a [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-1-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-1-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuaa=vbuc1
+ lda #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- vbuxx=vbuc1
+ ldx #'0'
+ jsr plus
+ // [2] plus::return#0 = plus::return#2
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuaa=vbuc1
+ lda #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- vbuxx=vbuc1
+ ldx #'1'
+ jsr plus
+ // [6] plus::return#1 = plus::return#2
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // near call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+ // plus
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuxx
+ stx.z add.a
+ // [12] add::b#0 = plus::b#2
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction __breturn:
+Succesful ASM optimization Pass5RedundantLabelElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte x 11.0
+char plus::b
+char plus::b#2 // reg byte a 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte a 3.75
+
+reg byte x [ plus::a#2 ]
+reg byte a [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte a [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 60
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-1-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #1
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-1-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuaa=vbuc1
+ lda #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- vbuxx=vbuc1
+ ldx #'0'
+ jsr plus
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuaa=vbuc1
+ lda #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- vbuxx=vbuc1
+ ldx #'1'
+ jsr plus
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // near call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+ // plus
+// __register(A) char plus(__register(X) char a, __register(A) char b)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuxx
+ stx.z add.a
+ // [12] add::b#0 = plus::b#2
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-1-near-1.sym b/src/test/ref/call-banked-phi-case-1-near-1.sym
new file mode 100644
index 000000000..bfa554ac0
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-1-near-1.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte x 11.0
+char plus::b
+char plus::b#2 // reg byte a 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte a 3.75
+
+reg byte x [ plus::a#2 ]
+reg byte a [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte a [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-2-close-0.asm b/src/test/ref/call-banked-phi-case-2-close-0.asm
new file mode 100644
index 000000000..efdf5fdb6
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-0.asm
@@ -0,0 +1,96 @@
+/**
+ * @file call-banked-phi-case-2-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-2-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // a+b
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-2-close-0.cfg b/src/test/ref/call-banked-phi-case-2-close-0.cfg
new file mode 100644
index 000000000..b5f3a4af5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-0.cfg
@@ -0,0 +1,30 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-2-close-0.log b/src/test/ref/call-banked-phi-case-2-close-0.log
new file mode 100644
index 000000000..96e2fadd5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-0.log
@@ -0,0 +1,520 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ plus::$0 = plus::a#2 + plus::b#2
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ plus::return#6 = phi( plus/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Successful SSA optimization Pass2AliasElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 11.0
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ plus::return#2 ]
+Allocated zp[1]:2 [ plus::a#2 ]
+Allocated zp[1]:3 [ plus::b#2 ]
+Allocated zp[1]:4 [ plus::return#0 ]
+Allocated zp[1]:5 [ main::$0 ]
+Allocated zp[1]:6 [ plus::return#1 ]
+Allocated zp[1]:7 [ main::$1 ]
+Allocated zp[1]:8 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:8 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::return#2 = plus::a#2 + plus::b#2 [ plus::return#2 ] ( plus:1 [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } plus:5 [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::return#2 = plus::a#2 + plus::b#2 [ plus::return#2 ] ( plus:1 [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } plus:5 [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Potential registers zp[1]:2 [ plus::a#2 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ plus::b#2 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ plus::return#0 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ main::$0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:6 [ plus::return#1 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ main::$1 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#2 ] : zp[1]:8 , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [plus] 11: zp[1]:2 [ plus::a#2 ] 11: zp[1]:3 [ plus::b#2 ] 4: zp[1]:4 [ plus::return#0 ] 4: zp[1]:6 [ plus::return#1 ] 3.75: zp[1]:8 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:5 [ main::$0 ] 4: zp[1]:7 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [plus] best 141 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:8 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 129 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 129 combination
+Attempting to uplift remaining variables inzp[1]:8 [ plus::return#2 ]
+Uplifting [plus] best 126 combination reg byte x [ plus::return#2 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-2-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-2-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuxx=vbuaa_plus_vbuxx
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [12] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte x [ plus::return#2 ]
+
+
+FINAL ASSEMBLER
+Score: 114
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-2-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-2-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // a+b
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuxx=vbuaa_plus_vbuxx
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ // plus::@return
+ // }
+ // [12] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-2-close-0.sym b/src/test/ref/call-banked-phi-case-2-close-0.sym
new file mode 100644
index 000000000..00ee4aca5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-0.sym
@@ -0,0 +1,21 @@
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte x [ plus::return#2 ]
diff --git a/src/test/ref/call-banked-phi-case-2-close-1.asm b/src/test/ref/call-banked-phi-case-2-close-1.asm
new file mode 100644
index 000000000..5a15ee9a6
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-1.asm
@@ -0,0 +1,96 @@
+/**
+ * @file call-banked-phi-case-2-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-2-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // a+b
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-2-close-1.cfg b/src/test/ref/call-banked-phi-case-2-close-1.cfg
new file mode 100644
index 000000000..b5f3a4af5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-1.cfg
@@ -0,0 +1,30 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-2-close-1.log b/src/test/ref/call-banked-phi-case-2-close-1.log
new file mode 100644
index 000000000..9f7544ae5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-1.log
@@ -0,0 +1,520 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ plus::$0 = plus::a#2 + plus::b#2
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ plus::return#6 = phi( plus/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Successful SSA optimization Pass2AliasElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] plus::return#2 = plus::a#2 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [12] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 11.0
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ plus::return#2 ]
+Allocated zp[1]:2 [ plus::a#2 ]
+Allocated zp[1]:3 [ plus::b#2 ]
+Allocated zp[1]:4 [ plus::return#0 ]
+Allocated zp[1]:5 [ main::$0 ]
+Allocated zp[1]:6 [ plus::return#1 ]
+Allocated zp[1]:7 [ main::$1 ]
+Allocated zp[1]:8 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:8 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::return#2 = plus::a#2 + plus::b#2 [ plus::return#2 ] ( plus:1 [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } plus:5 [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::return#2 = plus::a#2 + plus::b#2 [ plus::return#2 ] ( plus:1 [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } plus:5 [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Potential registers zp[1]:2 [ plus::a#2 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ plus::b#2 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ plus::return#0 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ main::$0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:6 [ plus::return#1 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ main::$1 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#2 ] : zp[1]:8 , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [plus] 11: zp[1]:2 [ plus::a#2 ] 11: zp[1]:3 [ plus::b#2 ] 4: zp[1]:4 [ plus::return#0 ] 4: zp[1]:6 [ plus::return#1 ] 3.75: zp[1]:8 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:5 [ main::$0 ] 4: zp[1]:7 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [plus] best 141 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:8 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 129 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 129 combination
+Attempting to uplift remaining variables inzp[1]:8 [ plus::return#2 ]
+Uplifting [plus] best 126 combination reg byte x [ plus::return#2 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-2-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-2-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuxx=vbuaa_plus_vbuxx
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [12] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte x [ plus::return#2 ]
+
+
+FINAL ASSEMBLER
+Score: 114
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-2-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #2.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-2-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // a+b
+ // [11] plus::return#2 = plus::a#2 + plus::b#2 -- vbuxx=vbuaa_plus_vbuxx
+ stx.z $ff
+ clc
+ adc.z $ff
+ tax
+ // plus::@return
+ // }
+ // [12] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-2-close-1.sym b/src/test/ref/call-banked-phi-case-2-close-1.sym
new file mode 100644
index 000000000..00ee4aca5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-2-close-1.sym
@@ -0,0 +1,21 @@
+__constant char * const SCREEN = (char *) 1024
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 11.0
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+reg byte x [ plus::return#2 ]
diff --git a/src/test/ref/call-banked-phi-case-3-near-0.asm b/src/test/ref/call-banked-phi-case-3-near-0.asm
new file mode 100644
index 000000000..60fa654fa
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-0.asm
@@ -0,0 +1,106 @@
+/**
+ * @file call-banked-phi-case-3-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-3-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr add
+ tax
+ // }
+ rts
+}
+.segment Code
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-3-near-0.cfg b/src/test/ref/call-banked-phi-case-3-near-0.cfg
new file mode 100644
index 000000000..f7ec35c09
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-0.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-3-near-0.log b/src/test/ref/call-banked-phi-case-3-near-0.log
new file mode 100644
index 000000000..63c05360e
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-0.log
@@ -0,0 +1,660 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-3-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-3-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment Code
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-3-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-3-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment Code
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-3-near-0.sym b/src/test/ref/call-banked-phi-case-3-near-0.sym
new file mode 100644
index 000000000..658eb6563
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-0.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-3-near-1.asm b/src/test/ref/call-banked-phi-case-3-near-1.asm
new file mode 100644
index 000000000..9ffca6b4a
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-1.asm
@@ -0,0 +1,106 @@
+/**
+ * @file call-banked-phi-case-3-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-3-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr add
+ tax
+ // }
+ rts
+}
+.segment Code
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-3-near-1.cfg b/src/test/ref/call-banked-phi-case-3-near-1.cfg
new file mode 100644
index 000000000..f7ec35c09
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-1.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-3-near-1.log b/src/test/ref/call-banked-phi-case-3-near-1.log
new file mode 100644
index 000000000..7b34ab84a
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-1.log
@@ -0,0 +1,660 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-3-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-3-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment Code
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-3-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #3.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-3-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment Code
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-3-near-1.sym b/src/test/ref/call-banked-phi-case-3-near-1.sym
new file mode 100644
index 000000000..658eb6563
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-3-near-1.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-4-near-0.asm b/src/test/ref/call-banked-phi-case-4-near-0.asm
new file mode 100644
index 000000000..a7a1cbbf4
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-0.asm
@@ -0,0 +1,106 @@
+/**
+ * @file call-banked-phi-case-4-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-4-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr add
+ tax
+ // }
+ rts
+}
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-4-near-0.cfg b/src/test/ref/call-banked-phi-case-4-near-0.cfg
new file mode 100644
index 000000000..bb224fbfe
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-0.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-4-near-0.log b/src/test/ref/call-banked-phi-case-4-near-0.log
new file mode 100644
index 000000000..5532553ee
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-0.log
@@ -0,0 +1,660 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-4-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-4-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-4-near-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-4-near-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-4-near-0.sym b/src/test/ref/call-banked-phi-case-4-near-0.sym
new file mode 100644
index 000000000..4267f6a35
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-0.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-4-near-1.asm b/src/test/ref/call-banked-phi-case-4-near-1.asm
new file mode 100644
index 000000000..97f10c7d0
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-1.asm
@@ -0,0 +1,106 @@
+/**
+ * @file call-banked-phi-case-4-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-4-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr add
+ tax
+ // }
+ rts
+}
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-4-near-1.cfg b/src/test/ref/call-banked-phi-case-4-near-1.cfg
new file mode 100644
index 000000000..bb224fbfe
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-1.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-4-near-1.log b/src/test/ref/call-banked-phi-case-4-near-1.log
new file mode 100644
index 000000000..4205fd77c
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-1.log
@@ -0,0 +1,660 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-4-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-4-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-4-near-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #4.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-4-near-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add
+ jsr add
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 1)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-4-near-1.sym b/src/test/ref/call-banked-phi-case-4-near-1.sym
new file mode 100644
index 000000000..4267f6a35
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-4-near-1.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-5-far-0.asm b/src/test/ref/call-banked-phi-case-5-far-0.asm
new file mode 100644
index 000000000..c8603afdc
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-0.asm
@@ -0,0 +1,110 @@
+/**
+ * @file call-banked-phi-case-5-far-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-5-far-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr $ff6e
+ .byte add
+ .byte 2
+ tax
+ // }
+ rts
+}
+.segment RAM_Bank2
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-5-far-0.cfg b/src/test/ref/call-banked-phi-case-5-far-0.cfg
new file mode 100644
index 000000000..03dfaf36c
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-0.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-5-far-0.log b/src/test/ref/call-banked-phi-case-5-far-0.log
new file mode 100644
index 000000000..d1d83e6e3
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-0.log
@@ -0,0 +1,668 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-5-far-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-5-far-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_far_cx16_ram
+ jsr $ff6e
+ .byte add
+ .byte 2
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment RAM_Bank2
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-5-far-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-5-far-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_far_cx16_ram
+ jsr $ff6e
+ .byte add
+ .byte 2
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment RAM_Bank2
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-5-far-0.sym b/src/test/ref/call-banked-phi-case-5-far-0.sym
new file mode 100644
index 000000000..f777cf8ef
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-0.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-5-far-1.asm b/src/test/ref/call-banked-phi-case-5-far-1.asm
new file mode 100644
index 000000000..93f4f13c5
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-1.asm
@@ -0,0 +1,110 @@
+/**
+ * @file call-banked-phi-case-5-far-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-5-far-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ jsr $ff6e
+ .byte add
+ .byte 2
+ tax
+ // }
+ rts
+}
+.segment RAM_Bank2
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-5-far-1.cfg b/src/test/ref/call-banked-phi-case-5-far-1.cfg
new file mode 100644
index 000000000..03dfaf36c
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-1.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-5-far-1.log b/src/test/ref/call-banked-phi-case-5-far-1.log
new file mode 100644
index 000000000..8844e959f
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-1.log
@@ -0,0 +1,668 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_ram, 2) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 189 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte a [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 256 possible.
+Uplifting [plus] best 161 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 149 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 149 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 149 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 146 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-5-far-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-5-far-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_far_cx16_ram
+ jsr $ff6e
+ .byte add
+ .byte 2
+ // [14] add::return#0 = add::return#1
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment RAM_Bank2
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 128
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-5-far-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #5.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-5-far-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_far_cx16_ram
+ jsr $ff6e
+ .byte add
+ .byte 2
+ // [14] add::return#0 = add::return#1
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment RAM_Bank2
+ // add
+// __register(A) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_ram, 2)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuaa=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-5-far-1.sym b/src/test/ref/call-banked-phi-case-5-far-1.sym
new file mode 100644
index 000000000..f777cf8ef
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-5-far-1.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_ram, 2) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte a 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte a [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-6-close-0.asm b/src/test/ref/call-banked-phi-case-6-close-0.asm
new file mode 100644
index 000000000..160ff45fa
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-0.asm
@@ -0,0 +1,119 @@
+/**
+ * @file call-banked-phi-case-6-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-6-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ txa
+ tax
+ // }
+ rts
+}
+.segment ROM_Bank1
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ tax
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-6-close-0.cfg b/src/test/ref/call-banked-phi-case-6-close-0.cfg
new file mode 100644
index 000000000..c10c5c2f7
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-0.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-6-close-0.log b/src/test/ref/call-banked-phi-case-6-close-0.log
new file mode 100644
index 000000000..b81bf7d9a
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-0.log
@@ -0,0 +1,689 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] call add [ add::return#1 ] ( plus:1 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:4 [ add::return#1 ]
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] call add [ add::return#1 ] ( plus:1 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 223 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte x [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 192 possible.
+Uplifting [plus] best 195 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 183 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 183 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 183 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 180 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-6-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-6-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_close_cx16_rom
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ // [14] add::return#0 = add::return#1 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment ROM_Bank1
+ // add
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuxx=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ tax
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte x 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte x [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 162
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-6-close-0.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the __bank() directive.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-6-close-0.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_close_cx16_rom
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ // [14] add::return#0 = add::return#1 -- vbuaa=vbuxx
+ txa
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment ROM_Bank1
+ // add
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuxx=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ tax
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-6-close-0.sym b/src/test/ref/call-banked-phi-case-6-close-0.sym
new file mode 100644
index 000000000..26eed0f1c
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-0.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte x 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte x [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-case-6-close-1.asm b/src/test/ref/call-banked-phi-case-6-close-1.asm
new file mode 100644
index 000000000..89f99c527
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-1.asm
@@ -0,0 +1,119 @@
+/**
+ * @file call-banked-phi-case-6-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ .file [name="call-banked-phi-case-6-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ // plus('0', 7)
+ ldx #7
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ txa
+ // SCREEN[0] = plus('0', 7)
+ sta SCREEN
+ // plus('1', 6)
+ ldx #6
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ txa
+ // SCREEN[1] = plus('1', 6)
+ // close call
+ sta SCREEN+1
+ // }
+ rts
+}
+.segment RAM_Bank1
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ sta.z add.a
+ txa
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ txa
+ tax
+ // }
+ rts
+}
+.segment ROM_Bank1
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // a+b
+ clc
+ adc.z a
+ tax
+ // }
+ rts
+}
diff --git a/src/test/ref/call-banked-phi-case-6-close-1.cfg b/src/test/ref/call-banked-phi-case-6-close-1.cfg
new file mode 100644
index 000000000..c10c5c2f7
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-1.cfg
@@ -0,0 +1,44 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-case-6-close-1.log b/src/test/ref/call-banked-phi-case-6-close-1.log
new file mode 100644
index 000000000..c64b16fba
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-1.log
@@ -0,0 +1,689 @@
+Loading link script "call-banked-phi.ld"
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ plus::a#0 = '0'
+ plus::b#0 = 7
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@1
+main::@1: scope:[main] from main
+ plus::return#4 = phi( main/plus::return#0 )
+ main::$0 = plus::return#4
+ SCREEN[0] = main::$0
+ plus::a#1 = '1'
+ plus::b#1 = 6
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ plus::return#5 = phi( main::@1/plus::return#1 )
+ main::$1 = plus::return#5
+ SCREEN[1] = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ plus::b#2 = phi( main/plus::b#0, main::@1/plus::b#1 )
+ plus::a#2 = phi( main/plus::a#0, main::@1/plus::a#1 )
+ add::a#0 = plus::a#2
+ add::b#0 = plus::b#2
+ call add
+ add::return#0 = add::return#2
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ add::return#3 = phi( plus/add::return#0 )
+ plus::$0 = add::return#3
+ plus::return#2 = plus::$0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ plus::return#6 = phi( plus::@1/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ add::b#1 = phi( plus/add::b#0 )
+ add::a#1 = phi( plus/add::a#0 )
+ add::$0 = add::a#1 + add::b#1
+ add::return#1 = add::$0
+ to:add::@return
+add::@return: scope:[add] from add
+ add::return#4 = phi( add/add::return#1 )
+ add::return#2 = add::return#4
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant char * const SCREEN = (char *)$400
+void __start()
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::$0
+char add::a
+char add::a#0
+char add::a#1
+char add::b
+char add::b#0
+char add::b#1
+char add::return
+char add::return#0
+char add::return#1
+char add::return#2
+char add::return#3
+char add::return#4
+void main()
+char main::$0
+char main::$1
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::$0
+char plus::a
+char plus::a#0
+char plus::a#1
+char plus::a#2
+char plus::b
+char plus::b#0
+char plus::b#1
+char plus::b#2
+char plus::return
+char plus::return#0
+char plus::return#1
+char plus::return#2
+char plus::return#3
+char plus::return#4
+char plus::return#5
+char plus::return#6
+
+Adding number conversion cast (unumber) 7 in plus::b#0 = 7
+Adding number conversion cast (unumber) 0 in SCREEN[0] = main::$0
+Adding number conversion cast (unumber) 6 in plus::b#1 = 6
+Adding number conversion cast (unumber) 1 in SCREEN[1] = main::$1
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::b#0 = (unumber)7
+Inlining cast plus::b#1 = (unumber)6
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (char *) 1024
+Simplifying constant integer cast 7
+Simplifying constant integer cast 0
+Simplifying constant integer cast 6
+Simplifying constant integer cast 1
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 7
+Finalized unsigned number type (char) 0
+Finalized unsigned number type (char) 6
+Finalized unsigned number type (char) 1
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias add::return#0 = add::return#3
+Alias plus::return#2 = plus::$0 plus::return#6 plus::return#3
+Alias add::return#1 = add::$0 add::return#4 add::return#2
+Successful SSA optimization Pass2AliasElimination
+Identical Phi Values add::a#1 add::a#0
+Identical Phi Values add::b#1 add::b#0
+Successful SSA optimization Pass2IdenticalPhiElimination
+Constant plus::a#0 = '0'
+Constant plus::b#0 = 7
+Constant plus::a#1 = '1'
+Constant plus::b#1 = 6
+Successful SSA optimization Pass2ConstantIdentification
+Simplifying expression containing zero SCREEN in [5] SCREEN[0] = main::$0
+Successful SSA optimization PassNSimplifyExpressionWithZero
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::b#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::b#1
+Constant inlined plus::b#1 = 6
+Constant inlined plus::b#0 = 7
+Constant inlined plus::a#1 = '1'
+Constant inlined plus::a#0 = '0'
+Successful SSA optimization Pass2ConstantInlining
+Consolidated array index constant in *(SCREEN+1)
+Successful SSA optimization Pass2ConstantAdditionElimination
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:1 plus:5
+Calls in [plus] to add:13
+
+Created 2 initial phi equivalence classes
+Coalesced down to 2 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ [1] call plus
+ [2] plus::return#0 = plus::return#2
+ to:main::@1
+main::@1: scope:[main] from main
+ [3] main::$0 = plus::return#0
+ [4] *SCREEN = main::$0
+ [5] call plus
+ [6] plus::return#1 = plus::return#2
+ to:main::@2
+main::@2: scope:[main] from main::@1
+ [7] main::$1 = plus::return#1
+ [8] *(SCREEN+1) = main::$1
+ to:main::@return
+main::@return: scope:[main] from main::@2
+ [9] return
+ to:@return
+
+__bank(cx16_ram, 1) char plus(char a , char b)
+plus: scope:[plus] from main main::@1
+ [10] plus::b#2 = phi( main/7, main::@1/6 )
+ [10] plus::a#2 = phi( main/'0', main::@1/'1' )
+ [11] add::a#0 = plus::a#2
+ [12] add::b#0 = plus::b#2
+ [13] call add
+ [14] add::return#0 = add::return#1
+ to:plus::@1
+plus::@1: scope:[plus] from plus
+ [15] plus::return#2 = add::return#0
+ to:plus::@return
+plus::@return: scope:[plus] from plus::@1
+ [16] return
+ to:@return
+
+__bank(cx16_rom, 1) char add(char a , char b)
+add: scope:[add] from plus
+ [17] add::return#1 = add::a#0 + add::b#0
+ to:add::@return
+add::@return: scope:[add] from add
+ [18] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // 56.0
+char add::b
+char add::b#0 // 112.0
+char add::return
+char add::return#0 // 22.0
+char add::return#1 // 37.33333333333333
+void main()
+char main::$0 // 4.0
+char main::$1 // 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // 11.0
+char plus::b
+char plus::b#2 // 5.5
+char plus::return
+char plus::return#0 // 4.0
+char plus::return#1 // 4.0
+char plus::return#2 // 3.75
+
+Initial phi equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$0 to live range equivalence class [ main::$0 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable add::a#0 to live range equivalence class [ add::a#0 ]
+Added variable add::b#0 to live range equivalence class [ add::b#0 ]
+Added variable add::return#0 to live range equivalence class [ add::return#0 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Added variable add::return#1 to live range equivalence class [ add::return#1 ]
+Complete equivalence classes
+[ plus::a#2 ]
+[ plus::b#2 ]
+[ plus::return#0 ]
+[ main::$0 ]
+[ plus::return#1 ]
+[ main::$1 ]
+[ add::a#0 ]
+[ add::b#0 ]
+[ add::return#0 ]
+[ plus::return#2 ]
+[ add::return#1 ]
+Allocated zp[1]:2 [ add::b#0 ]
+Allocated zp[1]:3 [ add::a#0 ]
+Allocated zp[1]:4 [ add::return#1 ]
+Allocated zp[1]:5 [ add::return#0 ]
+Allocated zp[1]:6 [ plus::a#2 ]
+Allocated zp[1]:7 [ plus::b#2 ]
+Allocated zp[1]:8 [ plus::return#0 ]
+Allocated zp[1]:9 [ main::$0 ]
+Allocated zp[1]:10 [ plus::return#1 ]
+Allocated zp[1]:11 [ main::$1 ]
+Allocated zp[1]:12 [ plus::return#2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:12 [ plus::return#2 ]
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] call add [ add::return#1 ] ( plus:1 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:4 [ add::return#1 ]
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [1] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ plus::return#2 ] ( [ plus::return#2 ] { { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] call add [ add::return#1 ] ( plus:1 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Statement [17] add::return#1 = add::a#0 + add::b#0 [ add::return#1 ] ( plus:1::add:13 [ add::return#1 ] { { plus::return#0 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } plus:5::add:13 [ add::return#1 ] { { plus::return#1 = plus::return#2 } { add::a#0 = plus::a#2 } { add::b#0 = plus::b#2 } { add::return#0 = add::return#1 } } ) always clobbers reg byte a
+Potential registers zp[1]:6 [ plus::a#2 ] : zp[1]:6 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:7 [ plus::b#2 ] : zp[1]:7 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:8 [ plus::return#0 ] : zp[1]:8 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:9 [ main::$0 ] : zp[1]:9 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:10 [ plus::return#1 ] : zp[1]:10 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:11 [ main::$1 ] : zp[1]:11 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:3 [ add::a#0 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:2 [ add::b#0 ] : zp[1]:2 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:5 [ add::return#0 ] : zp[1]:5 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:12 [ plus::return#2 ] : zp[1]:12 , reg byte x , reg byte y ,
+Potential registers zp[1]:4 [ add::return#1 ] : zp[1]:4 , reg byte x , reg byte y ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [add] 112: zp[1]:2 [ add::b#0 ] 56: zp[1]:3 [ add::a#0 ] 37.33: zp[1]:4 [ add::return#1 ] 22: zp[1]:5 [ add::return#0 ]
+Uplift Scope [plus] 11: zp[1]:6 [ plus::a#2 ] 5.5: zp[1]:7 [ plus::b#2 ] 4: zp[1]:8 [ plus::return#0 ] 4: zp[1]:10 [ plus::return#1 ] 3.75: zp[1]:12 [ plus::return#2 ]
+Uplift Scope [main] 4: zp[1]:9 [ main::$0 ] 4: zp[1]:11 [ main::$1 ]
+Uplift Scope []
+
+Uplifting [add] best 223 combination reg byte a [ add::b#0 ] zp[1]:3 [ add::a#0 ] reg byte x [ add::return#1 ] reg byte a [ add::return#0 ]
+Limited combination testing to 100 combinations of 192 possible.
+Uplifting [plus] best 195 combination reg byte a [ plus::a#2 ] reg byte x [ plus::b#2 ] reg byte a [ plus::return#0 ] reg byte a [ plus::return#1 ] zp[1]:12 [ plus::return#2 ]
+Limited combination testing to 100 combinations of 768 possible.
+Uplifting [main] best 183 combination reg byte a [ main::$0 ] reg byte a [ main::$1 ]
+Uplifting [] best 183 combination
+Attempting to uplift remaining variables inzp[1]:3 [ add::a#0 ]
+Uplifting [add] best 183 combination zp[1]:3 [ add::a#0 ]
+Attempting to uplift remaining variables inzp[1]:12 [ plus::return#2 ]
+Uplifting [plus] best 180 combination reg byte x [ plus::return#2 ]
+Allocated (was zp[1]:3) zp[1]:2 [ add::a#0 ]
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * @file call-banked-phi-case-6-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-6-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ plus_from_main:
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // main::@1
+ __b1:
+ // [3] main::$0 = plus::return#0
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ plus_from___b1:
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ jmp __b2
+ // main::@2
+ __b2:
+ // [7] main::$1 = plus::return#1
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_close_cx16_rom
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ // [14] add::return#0 = add::return#1 -- vbuaa=vbuxx
+ txa
+ jmp __b1
+ // plus::@1
+ __b1:
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [16] return
+ rts
+}
+.segment ROM_Bank1
+ // add
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuxx=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ tax
+ jmp __breturn
+ // add::@return
+ __breturn:
+ // [18] return
+ rts
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __b2
+Removing instruction jmp __breturn
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction plus_from_main:
+Removing instruction __b1:
+Removing instruction plus_from___b1:
+Removing instruction __b2:
+Removing instruction __breturn:
+Removing instruction __b1:
+Removing instruction __breturn:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte x 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte x [ add::return#1 ]
+
+
+FINAL ASSEMBLER
+Score: 162
+
+ // File Comments
+/**
+ * @file call-banked-phi-case-6-close-1.c
+ * @author Sven Van de Velde (sven.van.de.velde@telenet.be),
+ * @author Jesper Gravgaard
+ * @brief Test a procedure with calling convention PHI - case #6.
+ * Implementation using the #pragma bank and nobank directives.
+ * @version 0.1
+ * @date 2023-04-11
+ *
+ * @copyright Copyright (c) 2023
+ *
+ * The following cases exist in banked calling implementations:
+ *
+ * - case #1 - unbanked to unbanked and no banking areas
+ * - case #2 - unbanked to banked to any bank area
+ * - case #3 - banked to unbanked from any bank area
+ * - case #4 - banked to same bank in same bank area
+ * - case #5 - banked to different bank in same bank area
+ * - case #6 - banked to any bank between different bank areas
+ *
+ * This brings us to the call types:
+ *
+ * - near = case #1, #3, #4
+ * - close = case #2, #6
+ * - far = case #5
+ *
+ */
+ // Upstart
+ .file [name="call-banked-phi-case-6-close-1.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // plus('0', 7)
+ // [1] call plus
+ // [10] phi from main to plus [phi:main->plus]
+ // [10] phi plus::b#2 = 7 [phi:main->plus#0] -- vbuxx=vbuc1
+ ldx #7
+ // [10] phi plus::a#2 = '0' [phi:main->plus#1] -- call_phi_close_cx16_ram
+ lda #'0'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('0', 7)
+ // [2] plus::return#0 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@1
+ // [3] main::$0 = plus::return#0
+ // SCREEN[0] = plus('0', 7)
+ // [4] *SCREEN = main::$0 -- _deref_pbuc1=vbuaa
+ sta SCREEN
+ // plus('1', 6)
+ // [5] call plus
+ // [10] phi from main::@1 to plus [phi:main::@1->plus]
+ // [10] phi plus::b#2 = 6 [phi:main::@1->plus#0] -- vbuxx=vbuc1
+ ldx #6
+ // [10] phi plus::a#2 = '1' [phi:main::@1->plus#1] -- call_phi_close_cx16_ram
+ lda #'1'
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus('1', 6)
+ // [6] plus::return#1 = plus::return#2 -- vbuaa=vbuxx
+ txa
+ // main::@2
+ // [7] main::$1 = plus::return#1
+ // SCREEN[1] = plus('1', 6)
+ // [8] *(SCREEN+1) = main::$1 -- _deref_pbuc1=vbuaa
+ // close call
+ sta SCREEN+1
+ // main::@return
+ // }
+ // [9] return
+ rts
+}
+.segment RAM_Bank1
+ // plus
+// __register(X) char plus(__register(A) char a, __register(X) char b)
+// __bank(cx16_ram, 1)
+plus: {
+ // add(a, b)
+ // [11] add::a#0 = plus::a#2 -- vbuz1=vbuaa
+ sta.z add.a
+ // [12] add::b#0 = plus::b#2 -- vbuaa=vbuxx
+ txa
+ // [13] call add -- call_phi_close_cx16_rom
+ sta.z $ff
+ lda.z 1
+ pha
+ lda #1
+ sta.z 1
+ lda.z $ff
+ jsr add
+ sta.z $ff
+ pla
+ sta.z 1
+ lda.z $ff
+ // [14] add::return#0 = add::return#1 -- vbuaa=vbuxx
+ txa
+ // plus::@1
+ // [15] plus::return#2 = add::return#0 -- vbuxx=vbuaa
+ tax
+ // plus::@return
+ // }
+ // [16] return
+ rts
+}
+.segment ROM_Bank1
+ // add
+// __register(X) char add(__zp(2) char a, __register(A) char b)
+// __bank(cx16_rom, 1)
+add: {
+ .label a = 2
+ // a+b
+ // [17] add::return#1 = add::a#0 + add::b#0 -- vbuxx=vbuz1_plus_vbuaa
+ clc
+ adc.z a
+ tax
+ // add::@return
+ // }
+ // [18] return
+ rts
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-case-6-close-1.sym b/src/test/ref/call-banked-phi-case-6-close-1.sym
new file mode 100644
index 000000000..26eed0f1c
--- /dev/null
+++ b/src/test/ref/call-banked-phi-case-6-close-1.sym
@@ -0,0 +1,33 @@
+__constant char * const SCREEN = (char *) 1024
+__bank(cx16_rom, 1) char add(char a , char b)
+char add::a
+char add::a#0 // a zp[1]:2 56.0
+char add::b
+char add::b#0 // reg byte a 112.0
+char add::return
+char add::return#0 // reg byte a 22.0
+char add::return#1 // reg byte x 37.33333333333333
+void main()
+char main::$0 // reg byte a 4.0
+char main::$1 // reg byte a 4.0
+__bank(cx16_ram, 1) char plus(char a , char b)
+char plus::a
+char plus::a#2 // reg byte a 11.0
+char plus::b
+char plus::b#2 // reg byte x 5.5
+char plus::return
+char plus::return#0 // reg byte a 4.0
+char plus::return#1 // reg byte a 4.0
+char plus::return#2 // reg byte x 3.75
+
+reg byte a [ plus::a#2 ]
+reg byte x [ plus::b#2 ]
+reg byte a [ plus::return#0 ]
+reg byte a [ main::$0 ]
+reg byte a [ plus::return#1 ]
+reg byte a [ main::$1 ]
+zp[1]:2 [ add::a#0 ]
+reg byte a [ add::b#0 ]
+reg byte a [ add::return#0 ]
+reg byte x [ plus::return#2 ]
+reg byte x [ add::return#1 ]
diff --git a/src/test/ref/call-banked-phi-memvars.asm b/src/test/ref/call-banked-phi-memvars.asm
new file mode 100644
index 000000000..bd4556180
--- /dev/null
+++ b/src/test/ref/call-banked-phi-memvars.asm
@@ -0,0 +1,144 @@
+/**
+ * Test banked calls with memory variables.
+ * The parameters & return should end up in the shared/common bank.
+ */
+ .file [name="call-banked-phi-memvars.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ .label SCREEN = $400
+.segment Code
+main: {
+ ldy #0
+ __b1:
+ // for(char i=0;i<5; i++)
+ cpy #5
+ bcc __b2
+ // }
+ rts
+ __b2:
+ // plus(100, (int)i)
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ lda #<$64
+ sta plus.a
+ lda #>$64
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus(100, (int)i)
+ // SCREEN[i] = plus(100, (int)i)
+ tya
+ asl
+ tax
+ lda __1
+ sta SCREEN,x
+ lda __1+1
+ sta SCREEN+1,x
+ // 10+i
+ tya
+ tax
+ axs #-[$a]
+ // plus(200, (int)i)
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ lda #<$c8
+ sta plus.a
+ lda #>$c8
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus(200, (int)i)
+ // SCREEN[10+i] = plus(200, (int)i)
+ txa
+ asl
+ tax
+ lda __3
+ sta SCREEN,x
+ lda __3+1
+ sta SCREEN+1,x
+ // for(char i=0;i<5; i++)
+ iny
+ jmp __b1
+ .segment Data
+ .label __1 = plus.b
+ .label __3 = plus.b
+}
+.segment RAM_Bank1
+// __mem() int plus(__mem() int a, __mem() int b)
+// __bank(cx16_ram, 1)
+plus: {
+ // r += a
+ clc
+ lda a
+ adc #<2
+ sta r
+ lda a+1
+ adc #>2
+ sta r+1
+ // r += b
+ clc
+ lda r
+ adc b
+ sta r
+ lda r+1
+ adc b+1
+ sta r+1
+ // r += a
+ clc
+ lda r
+ adc a
+ sta r
+ lda r+1
+ adc a+1
+ sta r+1
+ // r += b
+ clc
+ lda return
+ adc r
+ sta return
+ lda return+1
+ adc r+1
+ sta return+1
+ // }
+ rts
+ .segment Data
+ b: .word 0
+ .label return = b
+ .segment RAM_Bank1
+ r: .word 0
+ .segment Data
+ a: .word 0
+}
diff --git a/src/test/ref/call-banked-phi-memvars.cfg b/src/test/ref/call-banked-phi-memvars.cfg
new file mode 100644
index 000000000..4cb2646a1
--- /dev/null
+++ b/src/test/ref/call-banked-phi-memvars.cfg
@@ -0,0 +1,45 @@
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ to:main::@1
+main::@1: scope:[main] from main main::@4
+ [1] main::i#2 = phi( main/0, main::@4/main::i#1 )
+ [2] if(main::i#2<5) goto main::@2
+ to:main::@return
+main::@return: scope:[main] from main::@1
+ [3] return
+ to:@return
+main::@2: scope:[main] from main::@1
+ [4] plus::b#0 = (int)main::i#2
+ [5] call plus
+ [6] plus::return#0 = plus::return#2
+ to:main::@3
+main::@3: scope:[main] from main::@2
+ [7] main::$1 = plus::return#0
+ [8] main::$4 = main::i#2 << 1
+ [9] SCREEN[main::$4] = main::$1
+ [10] main::$2 = $a + main::i#2
+ [11] plus::b#1 = (int)main::i#2
+ [12] call plus
+ [13] plus::return#1 = plus::return#2
+ to:main::@4
+main::@4: scope:[main] from main::@3
+ [14] main::$3 = plus::return#1
+ [15] main::$5 = main::$2 << 1
+ [16] SCREEN[main::$5] = main::$3
+ [17] main::i#1 = ++ main::i#2
+ to:main::@1
+
+__bank(cx16_ram, 1) int plus(int a , int b)
+plus: scope:[plus] from main::@2 main::@3
+ [18] plus::b#2 = phi( main::@2/plus::b#0, main::@3/plus::b#1 )
+ [18] plus::a#2 = phi( main::@2/$64, main::@3/$c8 )
+ [19] plus::r#1 = 2 + plus::a#2
+ [20] plus::r#2 = plus::r#1 + plus::b#2
+ [21] plus::r#3 = plus::r#2 + plus::a#2
+ [22] plus::return#2 = plus::r#3 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [23] return
+ to:@return
diff --git a/src/test/ref/call-banked-phi-memvars.log b/src/test/ref/call-banked-phi-memvars.log
new file mode 100644
index 000000000..6aea5faca
--- /dev/null
+++ b/src/test/ref/call-banked-phi-memvars.log
@@ -0,0 +1,803 @@
+Loading link script "call-banked-phi.ld"
+Updating intermediate variable memory area to MAIN_MEMORY main::$0
+Updating intermediate variable memory area to MAIN_MEMORY main::$1
+Updating intermediate variable memory area to MAIN_MEMORY main::$2
+Updating intermediate variable memory area to MAIN_MEMORY main::$3
+Fixing banked procedure parameter/return value to default segment plus::a
+Fixing banked procedure parameter/return value to default segment plus::b
+Fixing banked procedure parameter/return value to default segment plus::return
+
+CONTROL FLOW GRAPH SSA
+
+void main()
+main: scope:[main] from __start
+ main::i#0 = 0
+ to:main::@1
+main::@1: scope:[main] from main main::@4
+ main::i#2 = phi( main/main::i#0, main::@4/main::i#1 )
+ main::$0 = main::i#2 < 5
+ if(main::$0) goto main::@2
+ to:main::@return
+main::@2: scope:[main] from main::@1
+ main::i#3 = phi( main::@1/main::i#2 )
+ plus::a#0 = $64
+ plus::b#0 = (int)main::i#3
+ call plus
+ plus::return#0 = plus::return#3
+ to:main::@3
+main::@3: scope:[main] from main::@2
+ main::i#4 = phi( main::@2/main::i#3 )
+ plus::return#4 = phi( main::@2/plus::return#0 )
+ main::$1 = plus::return#4
+ main::$4 = main::i#4 * SIZEOF_INT
+ SCREEN[main::$4] = main::$1
+ main::$2 = $a + main::i#4
+ plus::a#1 = $c8
+ plus::b#1 = (int)main::i#4
+ call plus
+ plus::return#1 = plus::return#3
+ to:main::@4
+main::@4: scope:[main] from main::@3
+ main::i#5 = phi( main::@3/main::i#4 )
+ plus::return#5 = phi( main::@3/plus::return#1 )
+ main::$3 = plus::return#5
+ main::$5 = main::$2 * SIZEOF_INT
+ SCREEN[main::$5] = main::$3
+ main::i#1 = ++ main::i#5
+ to:main::@1
+main::@return: scope:[main] from main::@1
+ return
+ to:@return
+
+__bank(cx16_ram, 1) int plus(int a , int b)
+plus: scope:[plus] from main::@2 main::@3
+ plus::b#2 = phi( main::@2/plus::b#0, main::@3/plus::b#1 )
+ plus::a#2 = phi( main::@2/plus::a#0, main::@3/plus::a#1 )
+ plus::r#0 = 2
+ plus::r#1 = plus::r#0 + plus::a#2
+ plus::r#2 = plus::r#1 + plus::b#2
+ plus::r#3 = plus::r#2 + plus::a#2
+ plus::r#4 = plus::r#3 + plus::b#2
+ plus::return#2 = plus::r#4
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ plus::return#6 = phi( plus/plus::return#2 )
+ plus::return#3 = plus::return#6
+ return
+ to:@return
+
+void __start()
+__start: scope:[__start] from
+ call main
+ to:__start::@1
+__start::@1: scope:[__start] from __start
+ to:__start::@return
+__start::@return: scope:[__start] from __start::@1
+ return
+ to:@return
+
+SYMBOL TABLE SSA
+__constant int * const SCREEN = (int *)$400
+__constant char SIZEOF_INT = 2
+void __start()
+void main()
+bool main::$0
+int main::$1
+number main::$2
+int main::$3
+char main::$4
+number main::$5
+char main::i
+char main::i#0
+char main::i#1
+char main::i#2
+char main::i#3
+char main::i#4
+char main::i#5
+__bank(cx16_ram, 1) int plus(int a , int b)
+int plus::a
+int plus::a#0
+int plus::a#1
+int plus::a#2
+int plus::b
+int plus::b#0
+int plus::b#1
+int plus::b#2
+int plus::r
+int plus::r#0
+int plus::r#1
+int plus::r#2
+int plus::r#3
+int plus::r#4
+int plus::return
+int plus::return#0
+int plus::return#1
+int plus::return#2
+int plus::return#3
+int plus::return#4
+int plus::return#5
+int plus::return#6
+
+Adding number conversion cast (unumber) 5 in main::$0 = main::i#2 < 5
+Adding number conversion cast (snumber) $64 in plus::a#0 = $64
+Adding number conversion cast (unumber) $a in main::$2 = $a + main::i#4
+Adding number conversion cast (unumber) main::$2 in main::$2 = (unumber)$a + main::i#4
+Adding number conversion cast (snumber) $c8 in plus::a#1 = $c8
+Adding number conversion cast (unumber) main::$5 in main::$5 = main::$2 * SIZEOF_INT
+Successful SSA optimization PassNAddNumberTypeConversions
+Inlining cast plus::a#0 = (snumber)$64
+Inlining cast plus::a#1 = (snumber)$c8
+Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (int *) 1024
+Simplifying constant integer cast 5
+Simplifying constant integer cast $64
+Simplifying constant integer cast $a
+Simplifying constant integer cast $c8
+Successful SSA optimization PassNCastSimplification
+Finalized unsigned number type (char) 5
+Finalized signed number type (signed char) $64
+Finalized unsigned number type (char) $a
+Finalized signed number type (int) $c8
+Successful SSA optimization PassNFinalizeNumberTypeConversions
+Inferred type updated to char in main::$2 = $a + main::i#4
+Inferred type updated to char in main::$5 = main::$2 * SIZEOF_INT
+Alias main::i#2 = main::i#3 main::i#4 main::i#5
+Alias plus::return#0 = plus::return#4
+Alias plus::return#1 = plus::return#5
+Alias plus::return#2 = plus::r#4 plus::return#6 plus::return#3
+Successful SSA optimization Pass2AliasElimination
+Simple Condition main::$0 [3] if(main::i#2<5) goto main::@2
+Successful SSA optimization Pass2ConditionalJumpSimplification
+Constant main::i#0 = 0
+Constant plus::a#0 = $64
+Constant plus::a#1 = $c8
+Constant plus::r#0 = 2
+Successful SSA optimization Pass2ConstantIdentification
+Removing unused procedure __start
+Removing unused procedure block __start
+Removing unused procedure block __start::@1
+Removing unused procedure block __start::@return
+Successful SSA optimization PassNEliminateEmptyStart
+Rewriting multiplication to use shift [6] main::$4 = main::i#2 * SIZEOF_INT
+Rewriting multiplication to use shift [13] main::$5 = main::$2 * SIZEOF_INT
+Successful SSA optimization Pass2MultiplyToShiftRewriting
+Inlining constant with var siblings main::i#0
+Inlining constant with var siblings plus::a#0
+Inlining constant with var siblings plus::a#1
+Inlining constant with var siblings plus::r#0
+Constant inlined main::i#0 = 0
+Constant inlined plus::a#1 = $c8
+Constant inlined plus::r#0 = 2
+Constant inlined plus::a#0 = $64
+Successful SSA optimization Pass2ConstantInlining
+Eliminating unused constant SIZEOF_INT
+Successful SSA optimization PassNEliminateUnusedVars
+Adding NOP phi() at start of main
+CALL GRAPH
+Calls in [main] to plus:6 plus:14
+
+Created 3 initial phi equivalence classes
+Coalesced [5] plus::b#3 = plus::b#0
+Coalesced [13] plus::b#4 = plus::b#1
+Coalesced [20] main::i#6 = main::i#1
+Coalesced down to 3 phi equivalence classes
+Adding NOP phi() at start of main
+
+FINAL CONTROL FLOW GRAPH
+
+void main()
+main: scope:[main] from
+ [0] phi()
+ to:main::@1
+main::@1: scope:[main] from main main::@4
+ [1] main::i#2 = phi( main/0, main::@4/main::i#1 )
+ [2] if(main::i#2<5) goto main::@2
+ to:main::@return
+main::@return: scope:[main] from main::@1
+ [3] return
+ to:@return
+main::@2: scope:[main] from main::@1
+ [4] plus::b#0 = (int)main::i#2
+ [5] call plus
+ [6] plus::return#0 = plus::return#2
+ to:main::@3
+main::@3: scope:[main] from main::@2
+ [7] main::$1 = plus::return#0
+ [8] main::$4 = main::i#2 << 1
+ [9] SCREEN[main::$4] = main::$1
+ [10] main::$2 = $a + main::i#2
+ [11] plus::b#1 = (int)main::i#2
+ [12] call plus
+ [13] plus::return#1 = plus::return#2
+ to:main::@4
+main::@4: scope:[main] from main::@3
+ [14] main::$3 = plus::return#1
+ [15] main::$5 = main::$2 << 1
+ [16] SCREEN[main::$5] = main::$3
+ [17] main::i#1 = ++ main::i#2
+ to:main::@1
+
+__bank(cx16_ram, 1) int plus(int a , int b)
+plus: scope:[plus] from main::@2 main::@3
+ [18] plus::b#2 = phi( main::@2/plus::b#0, main::@3/plus::b#1 )
+ [18] plus::a#2 = phi( main::@2/$64, main::@3/$c8 )
+ [19] plus::r#1 = 2 + plus::a#2
+ [20] plus::r#2 = plus::r#1 + plus::b#2
+ [21] plus::r#3 = plus::r#2 + plus::a#2
+ [22] plus::return#2 = plus::r#3 + plus::b#2
+ to:plus::@return
+plus::@return: scope:[plus] from plus
+ [23] return
+ to:@return
+
+
+VARIABLE REGISTER WEIGHTS
+void main()
+int main::$1 // 11.0
+char main::$2 // 4.4
+int main::$3 // 11.0
+char main::$4 // 22.0
+char main::$5 // 22.0
+char main::i
+char main::i#1 // 22.0
+char main::i#2 // 3.6666666666666665
+__bank(cx16_ram, 1) int plus(int a , int b)
+int plus::a
+int plus::a#2 // 67.33333333333333
+int plus::b
+int plus::b#0 // 22.0
+int plus::b#1 // 22.0
+int plus::b#2 // 56.0
+int plus::r
+int plus::r#1 // 202.0
+int plus::r#2 // 202.0
+int plus::r#3 // 202.0
+int plus::return
+int plus::return#0 // 22.0
+int plus::return#1 // 22.0
+int plus::return#2 // 30.75
+
+Initial phi equivalence classes
+[ main::i#2 main::i#1 ]
+[ plus::a#2 ]
+[ plus::b#2 plus::b#0 plus::b#1 ]
+Added variable plus::return#0 to live range equivalence class [ plus::return#0 ]
+Added variable main::$1 to live range equivalence class [ main::$1 ]
+Added variable main::$4 to live range equivalence class [ main::$4 ]
+Added variable main::$2 to live range equivalence class [ main::$2 ]
+Added variable plus::return#1 to live range equivalence class [ plus::return#1 ]
+Added variable main::$3 to live range equivalence class [ main::$3 ]
+Added variable main::$5 to live range equivalence class [ main::$5 ]
+Added variable plus::r#1 to live range equivalence class [ plus::r#1 ]
+Added variable plus::r#2 to live range equivalence class [ plus::r#2 ]
+Added variable plus::r#3 to live range equivalence class [ plus::r#3 ]
+Added variable plus::return#2 to live range equivalence class [ plus::return#2 ]
+Complete equivalence classes
+[ main::i#2 main::i#1 ]
+[ plus::a#2 ]
+[ plus::b#2 plus::b#0 plus::b#1 ]
+[ plus::return#0 ]
+[ main::$1 ]
+[ main::$4 ]
+[ main::$2 ]
+[ plus::return#1 ]
+[ main::$3 ]
+[ main::$5 ]
+[ plus::r#1 ]
+[ plus::r#2 ]
+[ plus::r#3 ]
+[ plus::return#2 ]
+Allocated mem[2] [ plus::r#1 ]
+Allocated mem[2] [ plus::r#2 ]
+Allocated mem[2] [ plus::r#3 ]
+Allocated mem[2] [ plus::b#2 plus::b#0 plus::b#1 ]
+Allocated mem[2] [ plus::a#2 ]
+Allocated mem[2] [ plus::return#2 ]
+Allocated mem[1] [ main::i#2 main::i#1 ]
+Allocated mem[2] [ plus::return#0 ]
+Allocated mem[1] [ main::$4 ]
+Allocated mem[2] [ plus::return#1 ]
+Allocated mem[1] [ main::$5 ]
+Allocated mem[2] [ main::$1 ]
+Allocated mem[2] [ main::$3 ]
+Allocated mem[1] [ main::$2 ]
+REGISTER UPLIFT POTENTIAL REGISTERS
+Statement [4] plus::b#0 = (int)main::i#2 [ main::i#2 plus::b#0 ] ( [ main::i#2 plus::b#0 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for mem[1] [ main::i#2 main::i#1 ]
+Statement [5] call plus [ main::i#2 plus::return#2 ] ( [ main::i#2 plus::return#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [6] plus::return#0 = plus::return#2 [ main::i#2 plus::return#0 ] ( [ main::i#2 plus::return#0 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [7] main::$1 = plus::return#0 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [8] main::$4 = main::i#2 << 1 [ main::i#2 main::$1 main::$4 ] ( [ main::i#2 main::$1 main::$4 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [9] SCREEN[main::$4] = main::$1 [ main::i#2 ] ( [ main::i#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [10] main::$2 = $a + main::i#2 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::b#1 = (int)main::i#2 [ main::i#2 main::$2 plus::b#1 ] ( [ main::i#2 main::$2 plus::b#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for mem[1] [ main::$2 ]
+Statement [12] call plus [ main::i#2 plus::return#2 main::$2 ] ( [ main::i#2 plus::return#2 main::$2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] plus::return#1 = plus::return#2 [ main::i#2 main::$2 plus::return#1 ] ( [ main::i#2 main::$2 plus::return#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [14] main::$3 = plus::return#1 [ main::i#2 main::$2 main::$3 ] ( [ main::i#2 main::$2 main::$3 ] { } ) always clobbers reg byte a
+Statement [15] main::$5 = main::$2 << 1 [ main::i#2 main::$3 main::$5 ] ( [ main::i#2 main::$3 main::$5 ] { } ) always clobbers reg byte a
+Statement [16] SCREEN[main::$5] = main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
+Statement [19] plus::r#1 = 2 + plus::a#2 [ plus::a#2 plus::b#2 plus::r#1 ] ( plus:5 [ main::i#2 plus::a#2 plus::b#2 plus::r#1 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::a#2 plus::b#2 plus::r#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [20] plus::r#2 = plus::r#1 + plus::b#2 [ plus::a#2 plus::b#2 plus::r#2 ] ( plus:5 [ main::i#2 plus::a#2 plus::b#2 plus::r#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::a#2 plus::b#2 plus::r#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [21] plus::r#3 = plus::r#2 + plus::a#2 [ plus::b#2 plus::r#3 ] ( plus:5 [ main::i#2 plus::b#2 plus::r#3 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::b#2 plus::r#3 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [22] plus::return#2 = plus::r#3 + plus::b#2 [ plus::return#2 ] ( plus:5 [ main::i#2 plus::return#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::return#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [4] plus::b#0 = (int)main::i#2 [ main::i#2 plus::b#0 ] ( [ main::i#2 plus::b#0 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [5] call plus [ main::i#2 plus::return#2 ] ( [ main::i#2 plus::return#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [6] plus::return#0 = plus::return#2 [ main::i#2 plus::return#0 ] ( [ main::i#2 plus::return#0 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } ) always clobbers reg byte a
+Statement [7] main::$1 = plus::return#0 [ main::i#2 main::$1 ] ( [ main::i#2 main::$1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [8] main::$4 = main::i#2 << 1 [ main::i#2 main::$1 main::$4 ] ( [ main::i#2 main::$1 main::$4 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [9] SCREEN[main::$4] = main::$1 [ main::i#2 ] ( [ main::i#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [10] main::$2 = $a + main::i#2 [ main::i#2 main::$2 ] ( [ main::i#2 main::$2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [11] plus::b#1 = (int)main::i#2 [ main::i#2 main::$2 plus::b#1 ] ( [ main::i#2 main::$2 plus::b#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [12] call plus [ main::i#2 plus::return#2 main::$2 ] ( [ main::i#2 plus::return#2 main::$2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [13] plus::return#1 = plus::return#2 [ main::i#2 main::$2 plus::return#1 ] ( [ main::i#2 main::$2 plus::return#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [14] main::$3 = plus::return#1 [ main::i#2 main::$2 main::$3 ] ( [ main::i#2 main::$2 main::$3 ] { } ) always clobbers reg byte a
+Statement [15] main::$5 = main::$2 << 1 [ main::i#2 main::$3 main::$5 ] ( [ main::i#2 main::$3 main::$5 ] { } ) always clobbers reg byte a
+Statement [16] SCREEN[main::$5] = main::$3 [ main::i#2 ] ( [ main::i#2 ] { } ) always clobbers reg byte a
+Statement [19] plus::r#1 = 2 + plus::a#2 [ plus::a#2 plus::b#2 plus::r#1 ] ( plus:5 [ main::i#2 plus::a#2 plus::b#2 plus::r#1 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::a#2 plus::b#2 plus::r#1 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [20] plus::r#2 = plus::r#1 + plus::b#2 [ plus::a#2 plus::b#2 plus::r#2 ] ( plus:5 [ main::i#2 plus::a#2 plus::b#2 plus::r#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::a#2 plus::b#2 plus::r#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [21] plus::r#3 = plus::r#2 + plus::a#2 [ plus::b#2 plus::r#3 ] ( plus:5 [ main::i#2 plus::b#2 plus::r#3 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::b#2 plus::r#3 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Statement [22] plus::return#2 = plus::r#3 + plus::b#2 [ plus::return#2 ] ( plus:5 [ main::i#2 plus::return#2 ] { { plus::b#0 = plus::b#2 } { plus::return#0 = plus::return#2 } } plus:12 [ main::i#2 main::$2 plus::return#2 ] { { plus::b#1 = plus::b#2 } { plus::return#1 = plus::return#2 } } ) always clobbers reg byte a
+Potential registers mem[1] [ main::i#2 main::i#1 ] : mem[1] , reg byte x , reg byte y ,
+Potential registers mem[2] [ plus::a#2 ] : mem[2] ,
+Potential registers mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] : mem[2] ,
+Potential registers mem[2] [ plus::return#0 ] : mem[2] ,
+Potential registers mem[2] [ main::$1 ] : mem[2] ,
+Potential registers mem[1] [ main::$4 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
+Potential registers mem[1] [ main::$2 ] : mem[1] , reg byte x , reg byte y ,
+Potential registers mem[2] [ plus::return#1 ] : mem[2] ,
+Potential registers mem[2] [ main::$3 ] : mem[2] ,
+Potential registers mem[1] [ main::$5 ] : mem[1] , reg byte a , reg byte x , reg byte y ,
+Potential registers mem[2] [ plus::r#1 ] : mem[2] ,
+Potential registers mem[2] [ plus::r#2 ] : mem[2] ,
+Potential registers mem[2] [ plus::r#3 ] : mem[2] ,
+Potential registers mem[2] [ plus::return#2 ] : mem[2] ,
+
+REGISTER UPLIFT SCOPES
+Uplift Scope [plus] 202: mem[2] [ plus::r#1 ] 202: mem[2] [ plus::r#2 ] 202: mem[2] [ plus::r#3 ] 100: mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] 67.33: mem[2] [ plus::a#2 ] 30.75: mem[2] [ plus::return#2 ] 22: mem[2] [ plus::return#0 ] 22: mem[2] [ plus::return#1 ]
+Uplift Scope [main] 25.67: mem[1] [ main::i#2 main::i#1 ] 22: mem[1] [ main::$4 ] 22: mem[1] [ main::$5 ] 11: mem[2] [ main::$1 ] 11: mem[2] [ main::$3 ] 4.4: mem[1] [ main::$2 ]
+Uplift Scope []
+
+Uplifting [plus] best 2226 combination mem[2] [ plus::r#1 ] mem[2] [ plus::r#2 ] mem[2] [ plus::r#3 ] mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] mem[2] [ plus::a#2 ] mem[2] [ plus::return#2 ] mem[2] [ plus::return#0 ] mem[2] [ plus::return#1 ]
+Uplifting [main] best 1866 combination reg byte y [ main::i#2 main::i#1 ] reg byte x [ main::$4 ] reg byte x [ main::$5 ] mem[2] [ main::$1 ] mem[2] [ main::$3 ] reg byte x [ main::$2 ]
+Limited combination testing to 100 combinations of 144 possible.
+Uplifting [] best 1866 combination
+Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 ] ] with [ mem[2] [ plus::return#2 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::return#0 ] ] with [ mem[2] [ main::$1 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::return#1 ] ] with [ mem[2] [ main::$3 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::r#1 ] ] with [ mem[2] [ plus::r#2 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 ] ] with [ mem[2] [ plus::return#0 main::$1 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 ] ] with [ mem[2] [ plus::return#1 main::$3 ] ] - score: 1
+Coalescing zero page register [ mem[2] [ plus::r#1 plus::r#2 ] ] with [ mem[2] [ plus::r#3 ] ] - score: 1
+
+ASSEMBLER BEFORE OPTIMIZATION
+ // File Comments
+/**
+ * Test banked calls with memory variables.
+ * The parameters & return should end up in the shared/common bank.
+ */
+ // Upstart
+ .file [name="call-banked-phi-memvars.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] phi from main to main::@1 [phi:main->main::@1]
+ __b1_from_main:
+ // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
+ ldy #0
+ jmp __b1
+ // main::@1
+ __b1:
+ // [2] if(main::i#2<5) goto main::@2 -- vbuyy_lt_vbuc1_then_la1
+ cpy #5
+ bcc __b2
+ jmp __breturn
+ // main::@return
+ __breturn:
+ // [3] return
+ rts
+ // main::@2
+ __b2:
+ // [4] plus::b#0 = (int)main::i#2 -- vwsm1=_sword_vbuyy
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ // [5] call plus
+ // [18] phi from main::@2 to plus [phi:main::@2->plus]
+ plus_from___b2:
+ // [18] phi plus::b#2 = plus::b#0 [phi:main::@2->plus#0] -- register_copy
+ // [18] phi plus::a#2 = $64 [phi:main::@2->plus#1] -- call_phi_close_cx16_ram
+ lda #<$64
+ sta plus.a
+ lda #>$64
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [6] plus::return#0 = plus::return#2
+ jmp __b3
+ // main::@3
+ __b3:
+ // [7] main::$1 = plus::return#0
+ // [8] main::$4 = main::i#2 << 1 -- vbuxx=vbuyy_rol_1
+ tya
+ asl
+ tax
+ // [9] SCREEN[main::$4] = main::$1 -- pwsc1_derefidx_vbuxx=vwsm1
+ lda __1
+ sta SCREEN,x
+ lda __1+1
+ sta SCREEN+1,x
+ // [10] main::$2 = $a + main::i#2 -- vbuxx=vbuc1_plus_vbuyy
+ tya
+ tax
+ axs #-[$a]
+ // [11] plus::b#1 = (int)main::i#2 -- vwsm1=_sword_vbuyy
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ // [12] call plus
+ // [18] phi from main::@3 to plus [phi:main::@3->plus]
+ plus_from___b3:
+ // [18] phi plus::b#2 = plus::b#1 [phi:main::@3->plus#0] -- register_copy
+ // [18] phi plus::a#2 = $c8 [phi:main::@3->plus#1] -- call_phi_close_cx16_ram
+ lda #<$c8
+ sta plus.a
+ lda #>$c8
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // [13] plus::return#1 = plus::return#2
+ jmp __b4
+ // main::@4
+ __b4:
+ // [14] main::$3 = plus::return#1
+ // [15] main::$5 = main::$2 << 1 -- vbuxx=vbuxx_rol_1
+ txa
+ asl
+ tax
+ // [16] SCREEN[main::$5] = main::$3 -- pwsc1_derefidx_vbuxx=vwsm1
+ lda __3
+ sta SCREEN,x
+ lda __3+1
+ sta SCREEN+1,x
+ // [17] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy
+ iny
+ // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
+ __b1_from___b4:
+ // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy
+ jmp __b1
+ .segment Data
+ .label __1 = plus.b
+ .label __3 = plus.b
+}
+.segment RAM_Bank1
+ // plus
+// __mem() int plus(__mem() int a, __mem() int b)
+// __bank(cx16_ram, 1)
+plus: {
+ // [19] plus::r#1 = 2 + plus::a#2 -- vwsm1=vwsc1_plus_vwsm2
+ clc
+ lda a
+ adc #<2
+ sta r
+ lda a+1
+ adc #>2
+ sta r+1
+ // [20] plus::r#2 = plus::r#1 + plus::b#2 -- vwsm1=vwsm1_plus_vwsm2
+ clc
+ lda r
+ adc b
+ sta r
+ lda r+1
+ adc b+1
+ sta r+1
+ // [21] plus::r#3 = plus::r#2 + plus::a#2 -- vwsm1=vwsm1_plus_vwsm2
+ clc
+ lda r
+ adc a
+ sta r
+ lda r+1
+ adc a+1
+ sta r+1
+ // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm1
+ clc
+ lda return
+ adc r
+ sta return
+ lda return+1
+ adc r+1
+ sta return+1
+ jmp __breturn
+ // plus::@return
+ __breturn:
+ // [23] return
+ rts
+ .segment Data
+ b: .word 0
+ .label return = b
+ .segment RAM_Bank1
+ r: .word 0
+ .segment Data
+ a: .word 0
+}
+ // File Data
+
+ASSEMBLER OPTIMIZATIONS
+Removing instruction jmp __b1
+Removing instruction jmp __breturn
+Removing instruction jmp __b3
+Removing instruction jmp __b4
+Removing instruction jmp __breturn
+Succesful ASM optimization Pass5NextJumpElimination
+Removing instruction __b1_from_main:
+Removing instruction __breturn:
+Removing instruction plus_from___b2:
+Removing instruction __b3:
+Removing instruction plus_from___b3:
+Removing instruction __b4:
+Removing instruction __b1_from___b4:
+Removing instruction __breturn:
+Succesful ASM optimization Pass5UnusedLabelElimination
+
+FINAL SYMBOL TABLE
+__constant int * const SCREEN = (int *) 1024
+void main()
+int main::$1 // mem[2] 11.0
+char main::$2 // reg byte x 4.4
+int main::$3 // mem[2] 11.0
+char main::$4 // reg byte x 22.0
+char main::$5 // reg byte x 22.0
+char main::i
+char main::i#1 // reg byte y 22.0
+char main::i#2 // reg byte y 3.6666666666666665
+__bank(cx16_ram, 1) int plus(int a , int b)
+int plus::a
+int plus::a#2 // a mem[2] 67.33333333333333
+int plus::b
+int plus::b#0 // b mem[2] 22.0
+int plus::b#1 // b mem[2] 22.0
+int plus::b#2 // b mem[2] 56.0
+int plus::r
+int plus::r#1 // r mem[2] 202.0
+int plus::r#2 // r mem[2] 202.0
+int plus::r#3 // r mem[2] 202.0
+int plus::return
+int plus::return#0 // return mem[2] 22.0
+int plus::return#1 // return mem[2] 22.0
+int plus::return#2 // return mem[2] 30.75
+
+reg byte y [ main::i#2 main::i#1 ]
+mem[2] [ plus::a#2 ]
+mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 plus::return#1 main::$3 ]
+reg byte x [ main::$4 ]
+reg byte x [ main::$2 ]
+reg byte x [ main::$5 ]
+mem[2] [ plus::r#1 plus::r#2 plus::r#3 ]
+
+
+FINAL ASSEMBLER
+Score: 1103
+
+ // File Comments
+/**
+ * Test banked calls with memory variables.
+ * The parameters & return should end up in the shared/common bank.
+ */
+ // Upstart
+ .file [name="call-banked-phi-memvars.prg", type="prg", segments="Program"]
+.segmentdef Program [segments="Basic, Code, Data"]
+.segmentdef Basic [start=$0801]
+.segmentdef Code [start=$80d]
+.segmentdef Data [startAfter="Code"]
+.segmentdef RAM_Bank1 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef RAM_Bank2 [start=$A000, min=$A000, max=$BFFF, align=$100]
+.segmentdef ROM_Bank1 [start=$C000, min=$C000, max=$FFFF, align=$100]
+.segment Basic
+:BasicUpstart(main)
+.segment Code
+.segment Data
+
+
+ // Global Constants & labels
+ .label SCREEN = $400
+.segment Code
+ // main
+main: {
+ // [1] phi from main to main::@1 [phi:main->main::@1]
+ // [1] phi main::i#2 = 0 [phi:main->main::@1#0] -- vbuyy=vbuc1
+ ldy #0
+ // main::@1
+ __b1:
+ // for(char i=0;i<5; i++)
+ // [2] if(main::i#2<5) goto main::@2 -- vbuyy_lt_vbuc1_then_la1
+ cpy #5
+ bcc __b2
+ // main::@return
+ // }
+ // [3] return
+ rts
+ // main::@2
+ __b2:
+ // plus(100, (int)i)
+ // [4] plus::b#0 = (int)main::i#2 -- vwsm1=_sword_vbuyy
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ // [5] call plus
+ // [18] phi from main::@2 to plus [phi:main::@2->plus]
+ // [18] phi plus::b#2 = plus::b#0 [phi:main::@2->plus#0] -- register_copy
+ // [18] phi plus::a#2 = $64 [phi:main::@2->plus#1] -- call_phi_close_cx16_ram
+ lda #<$64
+ sta plus.a
+ lda #>$64
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus(100, (int)i)
+ // [6] plus::return#0 = plus::return#2
+ // main::@3
+ // [7] main::$1 = plus::return#0
+ // SCREEN[i] = plus(100, (int)i)
+ // [8] main::$4 = main::i#2 << 1 -- vbuxx=vbuyy_rol_1
+ tya
+ asl
+ tax
+ // [9] SCREEN[main::$4] = main::$1 -- pwsc1_derefidx_vbuxx=vwsm1
+ lda __1
+ sta SCREEN,x
+ lda __1+1
+ sta SCREEN+1,x
+ // 10+i
+ // [10] main::$2 = $a + main::i#2 -- vbuxx=vbuc1_plus_vbuyy
+ tya
+ tax
+ axs #-[$a]
+ // plus(200, (int)i)
+ // [11] plus::b#1 = (int)main::i#2 -- vwsm1=_sword_vbuyy
+ tya
+ sta plus.b
+ lda #0
+ sta plus.b+1
+ // [12] call plus
+ // [18] phi from main::@3 to plus [phi:main::@3->plus]
+ // [18] phi plus::b#2 = plus::b#1 [phi:main::@3->plus#0] -- register_copy
+ // [18] phi plus::a#2 = $c8 [phi:main::@3->plus#1] -- call_phi_close_cx16_ram
+ lda #<$c8
+ sta plus.a
+ lda #>$c8
+ sta plus.a+1
+ sta.z $ff
+ lda.z 0
+ pha
+ lda #1
+ sta.z 0
+ lda.z $ff
+ jsr plus
+ sta.z $ff
+ pla
+ sta.z 0
+ lda.z $ff
+ // plus(200, (int)i)
+ // [13] plus::return#1 = plus::return#2
+ // main::@4
+ // [14] main::$3 = plus::return#1
+ // SCREEN[10+i] = plus(200, (int)i)
+ // [15] main::$5 = main::$2 << 1 -- vbuxx=vbuxx_rol_1
+ txa
+ asl
+ tax
+ // [16] SCREEN[main::$5] = main::$3 -- pwsc1_derefidx_vbuxx=vwsm1
+ lda __3
+ sta SCREEN,x
+ lda __3+1
+ sta SCREEN+1,x
+ // for(char i=0;i<5; i++)
+ // [17] main::i#1 = ++ main::i#2 -- vbuyy=_inc_vbuyy
+ iny
+ // [1] phi from main::@4 to main::@1 [phi:main::@4->main::@1]
+ // [1] phi main::i#2 = main::i#1 [phi:main::@4->main::@1#0] -- register_copy
+ jmp __b1
+ .segment Data
+ .label __1 = plus.b
+ .label __3 = plus.b
+}
+.segment RAM_Bank1
+ // plus
+// __mem() int plus(__mem() int a, __mem() int b)
+// __bank(cx16_ram, 1)
+plus: {
+ // r += a
+ // [19] plus::r#1 = 2 + plus::a#2 -- vwsm1=vwsc1_plus_vwsm2
+ clc
+ lda a
+ adc #<2
+ sta r
+ lda a+1
+ adc #>2
+ sta r+1
+ // r += b
+ // [20] plus::r#2 = plus::r#1 + plus::b#2 -- vwsm1=vwsm1_plus_vwsm2
+ clc
+ lda r
+ adc b
+ sta r
+ lda r+1
+ adc b+1
+ sta r+1
+ // r += a
+ // [21] plus::r#3 = plus::r#2 + plus::a#2 -- vwsm1=vwsm1_plus_vwsm2
+ clc
+ lda r
+ adc a
+ sta r
+ lda r+1
+ adc a+1
+ sta r+1
+ // r += b
+ // [22] plus::return#2 = plus::r#3 + plus::b#2 -- vwsm1=vwsm2_plus_vwsm1
+ clc
+ lda return
+ adc r
+ sta return
+ lda return+1
+ adc r+1
+ sta return+1
+ // plus::@return
+ // }
+ // [23] return
+ rts
+ .segment Data
+ b: .word 0
+ .label return = b
+ .segment RAM_Bank1
+ r: .word 0
+ .segment Data
+ a: .word 0
+}
+ // File Data
+
diff --git a/src/test/ref/call-banked-phi-memvars.sym b/src/test/ref/call-banked-phi-memvars.sym
new file mode 100644
index 000000000..4300fc0bd
--- /dev/null
+++ b/src/test/ref/call-banked-phi-memvars.sym
@@ -0,0 +1,33 @@
+__constant int * const SCREEN = (int *) 1024
+void main()
+int main::$1 // mem[2] 11.0
+char main::$2 // reg byte x 4.4
+int main::$3 // mem[2] 11.0
+char main::$4 // reg byte x 22.0
+char main::$5 // reg byte x 22.0
+char main::i
+char main::i#1 // reg byte y 22.0
+char main::i#2 // reg byte y 3.6666666666666665
+__bank(cx16_ram, 1) int plus(int a , int b)
+int plus::a
+int plus::a#2 // a mem[2] 67.33333333333333
+int plus::b
+int plus::b#0 // b mem[2] 22.0
+int plus::b#1 // b mem[2] 22.0
+int plus::b#2 // b mem[2] 56.0
+int plus::r
+int plus::r#1 // r mem[2] 202.0
+int plus::r#2 // r mem[2] 202.0
+int plus::r#3 // r mem[2] 202.0
+int plus::return
+int plus::return#0 // return mem[2] 22.0
+int plus::return#1 // return mem[2] 22.0
+int plus::return#2 // return mem[2] 30.75
+
+reg byte y [ main::i#2 main::i#1 ]
+mem[2] [ plus::a#2 ]
+mem[2] [ plus::b#2 plus::b#0 plus::b#1 plus::return#2 plus::return#0 main::$1 plus::return#1 main::$3 ]
+reg byte x [ main::$4 ]
+reg byte x [ main::$2 ]
+reg byte x [ main::$5 ]
+mem[2] [ plus::r#1 plus::r#2 plus::r#3 ]
diff --git a/src/test/ref/casting-negative.log b/src/test/ref/casting-negative.log
index cfa761d3c..2dc403ae1 100644
--- a/src/test/ref/casting-negative.log
+++ b/src/test/ref/casting-negative.log
@@ -13,6 +13,8 @@ Inlined call call __init
Eliminating unused variable with no statement gotoxy::$4
Eliminating unused variable with no statement memcpy::$0
Eliminating unused variable with no statement memset::$2
+Eliminating unused variable with no statement __snprintf_capacity
+Eliminating unused variable with no statement __snprintf_size
Eliminating unused variable with no statement test_casting::$0
Calling convention STACK_CALL adding prepare/execute/finalize for call *printf_str::putc printf_str::c
Calling convention STACK_CALL adding prepare/execute/finalize for call *printf_padding::putc printf_padding::pad
diff --git a/src/test/ref/cbm-keyboard.log b/src/test/ref/cbm-keyboard.log
index 0ffec3780..951995af8 100644
--- a/src/test/ref/cbm-keyboard.log
+++ b/src/test/ref/cbm-keyboard.log
@@ -15,6 +15,8 @@ Inlined call call __init
Eliminating unused variable with no statement memcpy::$0
Eliminating unused variable with no statement memset::$2
Eliminating unused variable with no statement gotoxy::$4
+Eliminating unused variable with no statement __snprintf_capacity
+Eliminating unused variable with no statement __snprintf_size
Eliminating unused variable with no statement main::$2
Eliminating unused variable with no statement main::$7
Calling convention STACK_CALL adding prepare/execute/finalize for call *printf_str::putc printf_str::c
diff --git a/src/test/ref/complex/xmega65/xmega65.log b/src/test/ref/complex/xmega65/xmega65.log
index 0610788ff..c7b45bec3 100644
--- a/src/test/ref/complex/xmega65/xmega65.log
+++ b/src/test/ref/complex/xmega65/xmega65.log
@@ -1,4 +1,5 @@
Loading link script "xmega65.ld"
+Inlined call call __init
Eliminating unused variable with no statement memset::$2
CONTROL FLOW GRAPH SSA
@@ -47,7 +48,7 @@ memset::@return: scope:[memset] from memset::@1
to:@return
void main()
-main: scope:[main] from __start
+main: scope:[main] from __start::@1
*VICII_MEMORY = $14
memset::str#0 = (void *)SCREEN
memset::c#0 = ' '
@@ -116,11 +117,15 @@ syscall2::@return: scope:[syscall2] from syscall2
void __start()
__start: scope:[__start] from
- call main
+ to:__start::__init1
+__start::__init1: scope:[__start] from __start
to:__start::@1
-__start::@1: scope:[__start] from __start
+__start::@1: scope:[__start] from __start::__init1
+ call main
+ to:__start::@2
+__start::@2: scope:[__start] from __start::@1
to:__start::@return
-__start::@return: scope:[__start] from __start::@1
+__start::@return: scope:[__start] from __start::@2
return
to:@return
@@ -281,7 +286,9 @@ Eliminating unused variable memset::return#3 and assignment [14] memset::return#
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
+Removing unused procedure block __start::__init1
Removing unused procedure block __start::@1
+Removing unused procedure block __start::@2
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Simple Condition main::$2 [20] if(*RASTER==$36) goto main::@5
diff --git a/src/test/ref/ducks-array.log b/src/test/ref/ducks-array.log
index 52b0efcee..200ca1e29 100644
--- a/src/test/ref/ducks-array.log
+++ b/src/test/ref/ducks-array.log
@@ -7,6 +7,8 @@ Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call call __init
Eliminating unused variable with no statement gotoxy::$4
Eliminating unused variable with no statement printf_buffer
+Eliminating unused variable with no statement __snprintf_capacity
+Eliminating unused variable with no statement __snprintf_size
CONTROL FLOW GRAPH SSA
diff --git a/src/test/ref/ducks-total.log b/src/test/ref/ducks-total.log
index b2ef90b84..65e8f8939 100644
--- a/src/test/ref/ducks-total.log
+++ b/src/test/ref/ducks-total.log
@@ -11,6 +11,8 @@ Eliminating unused variable with no statement memcpy::$0
Eliminating unused variable with no statement memset::$2
Eliminating unused variable with no statement gotoxy::$4
Eliminating unused variable with no statement printf_buffer
+Eliminating unused variable with no statement __snprintf_capacity
+Eliminating unused variable with no statement __snprintf_size
Eliminating unused variable with no statement div16u8u::$1
Eliminating unused variable with no statement div16u8u::$3
Eliminating unused variable with no statement div16u8u::$4
diff --git a/src/test/ref/examples/c64/font-2x2/font-2x2.log b/src/test/ref/examples/c64/font-2x2/font-2x2.log
index 54e8fc78d..f89e3df56 100644
--- a/src/test/ref/examples/c64/font-2x2/font-2x2.log
+++ b/src/test/ref/examples/c64/font-2x2/font-2x2.log
@@ -1,5 +1,6 @@
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call main::$2 = call toD018(SCREEN, FONT_COMPRESSED)
+Inlined call call __init
Eliminating unused variable with no statement memset::$2
Eliminating unused variable with no statement main::$1
Eliminating unused variable with no statement show::$3
@@ -52,7 +53,7 @@ memset::@return: scope:[memset] from memset::@1
to:@return
void main()
-main: scope:[main] from __start
+main: scope:[main] from __start::@1
asm { sei }
*PROCPORT = PROCPORT_RAM_CHARROM
font_2x2::font_original#0 = CHARGEN
@@ -500,11 +501,15 @@ font_find::@return: scope:[font_find] from font_find::@3 font_find::@8
void __start()
__start: scope:[__start] from
- call main
+ to:__start::__init1
+__start::__init1: scope:[__start] from __start
to:__start::@1
-__start::@1: scope:[__start] from __start
+__start::@1: scope:[__start] from __start::__init1
+ call main
+ to:__start::@2
+__start::@2: scope:[__start] from __start::@1
to:__start::@return
-__start::@return: scope:[__start] from __start::@1
+__start::@return: scope:[__start] from __start::@2
return
to:@return
@@ -1278,7 +1283,9 @@ Eliminating unused constant memset::return#2
Successful SSA optimization PassNEliminateUnusedVars
Removing unused procedure __start
Removing unused procedure block __start
+Removing unused procedure block __start::__init1
Removing unused procedure block __start::@1
+Removing unused procedure block __start::@2
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Adding number conversion cast (unumber) 8 in [30] if(main::x#1!=8) goto main::@2
diff --git a/src/test/ref/examples/c64/kernalload/kernalload.log b/src/test/ref/examples/c64/kernalload/kernalload.log
index b0fba1a3b..dd29f2926 100644
--- a/src/test/ref/examples/c64/kernalload/kernalload.log
+++ b/src/test/ref/examples/c64/kernalload/kernalload.log
@@ -8,6 +8,7 @@ Setting inferred volatile on symbol affected by address-of: load::verify in asm
Setting inferred volatile on symbol affected by address-of: load::status in asm { ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcserror lda#$ff error: stastatus }
Inlined call vicSelectGfxBank::$0 = call toDd00(vicSelectGfxBank::gfx)
Inlined call main::$3 = call toSpritePtr(LOAD_SPRITE)
+Inlined call call __init
Eliminating unused variable with no statement main::$0
CONTROL FLOW GRAPH SSA
@@ -40,7 +41,7 @@ strlen::@return: scope:[strlen] from strlen::@3
to:@return
void main()
-main: scope:[main] from __start
+main: scope:[main] from __start::@1
loadFileToMemory::device#0 = 8
loadFileToMemory::filename#0 = main::filename
loadFileToMemory::address#0 = LOAD_SPRITE
@@ -166,11 +167,15 @@ load::@return: scope:[load] from load
void __start()
__start: scope:[__start] from
- call main
+ to:__start::__init1
+__start::__init1: scope:[__start] from __start
to:__start::@1
-__start::@1: scope:[__start] from __start
+__start::@1: scope:[__start] from __start::__init1
+ call main
+ to:__start::@2
+__start::@2: scope:[__start] from __start::@1
to:__start::@return
-__start::@return: scope:[__start] from __start::@1
+__start::@return: scope:[__start] from __start::@2
return
to:@return
@@ -366,7 +371,9 @@ Simplifying expression containing zero SPRITES_YPOS in [24] SPRITES_YPOS[0] = $3
Successful SSA optimization PassNSimplifyExpressionWithZero
Removing unused procedure __start
Removing unused procedure block __start
+Removing unused procedure block __start::__init1
Removing unused procedure block __start::@1
+Removing unused procedure block __start::@2
Removing unused procedure block __start::@return
Successful SSA optimization PassNEliminateEmptyStart
Alias candidate removed (volatile)load::return#1 = load::status load::return#2
diff --git a/src/test/ref/examples/cx16/cx16-rasterbars.asm b/src/test/ref/examples/cx16/cx16-rasterbars.asm
index 0cedde062..465ab6799 100644
--- a/src/test/ref/examples/cx16/cx16-rasterbars.asm
+++ b/src/test/ref/examples/cx16/cx16-rasterbars.asm
@@ -1,7 +1,7 @@
// Example program for the Commander X16
// Displays raster bars in the border
.cpu _65c02
- // Commodore 64 PRG executable file
+ // Commander X16 PRG executable file
.file [name="cx16-rasterbars.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
@@ -9,9 +9,13 @@
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(__start)
+
.const VERA_DCSEL = 2
.const VERA_LINE = 2
+ .const isr_vsync = $314
.const SIZEOF_CHAR = 1
+ /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
+ .label KERNEL_IRQ = $314
/// $9F25 CTRL Control
/// Bit 7: Reset
/// Bit 1: DCSEL
@@ -48,22 +52,28 @@
.label VERA_DC_VSTART = $9f2b
/// $9F2C DC_VSTOP (DCSEL=1) Active Display V-Stop (8:1)
.label VERA_DC_VSTOP = $9f2c
- /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
- .label KERNEL_IRQ = $314
+ .label BRAM = 0
+ .label BROM = 1
// The horizontal start
- .label hstart = 6
+ .label hstart = $26
// The horizontal stop
- .label hstop = 7
+ .label hstop = $27
// The vertical start
- .label vstart = 8
+ .label vstart = $28
// The vertical stop
- .label vstop = 9
+ .label vstop = $29
// The countdown
- .label cnt = 5
+ .label cnt = $25
// The sin idx
- .label sin_idx = $a
+ .label sin_idx = $2a
.segment Code
__start: {
+ // __export volatile __address(0x00) unsigned char BRAM = 0
+ lda #0
+ sta.z BRAM
+ // __export volatile __address(0x01) unsigned char BROM = 4
+ lda #4
+ sta.z BROM
// volatile char hstart = 0/4
lda #0
sta.z hstart
@@ -87,8 +97,8 @@ __start: {
}
// LINE Interrupt Routine
irq_line: {
- .label idx = 4
- .label bar = 2
+ .label idx = $24
+ .label bar = $22
// *VERA_CTRL |= VERA_DCSEL
// Update the border
lda #VERA_DCSEL
@@ -243,7 +253,7 @@ memset: {
.const c = 0
.label str = BARS
.label end = str+num
- .label dst = 2
+ .label dst = $22
lda #str
diff --git a/src/test/ref/examples/cx16/cx16-rasterbars.cfg b/src/test/ref/examples/cx16/cx16-rasterbars.cfg
index 76233912a..ffa1c2b84 100644
--- a/src/test/ref/examples/cx16/cx16-rasterbars.cfg
+++ b/src/test/ref/examples/cx16/cx16-rasterbars.cfg
@@ -4,138 +4,140 @@ __start: scope:[__start] from
[0] phi()
to:__start::__init1
__start::__init1: scope:[__start] from __start
- [1] hstart = 0
- [2] hstop = (char)$280/4
- [3] vstart = 0
- [4] vstop = (char)$1e0/2
- [5] cnt = 2
- [6] sin_idx = $64
+ [1] BRAM = 0
+ [2] BROM = 4
+ [3] hstart = 0
+ [4] hstop = (char)$280/4
+ [5] vstart = 0
+ [6] vstop = (char)$1e0/2
+ [7] cnt = 2
+ [8] sin_idx = $64
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
- [7] phi()
- [8] call main
+ [9] phi()
+ [10] call main
to:__start::@return
__start::@return: scope:[__start] from __start::@1
- [9] return
+ [11] return
to:@return
__interrupt(rom_min_cx16) void irq_line()
irq_line: scope:[irq_line] from
- [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL
- [11] *VERA_DC_HSTART = hstart
- [12] *VERA_DC_HSTOP = hstop
- [13] *VERA_DC_VSTART = vstart
- [14] *VERA_DC_VSTOP = vstop
- [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL
+ [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL
+ [13] *VERA_DC_HSTART = hstart
+ [14] *VERA_DC_HSTOP = hstop
+ [15] *VERA_DC_VSTART = vstart
+ [16] *VERA_DC_VSTOP = vstop
+ [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL
to:irq_line::@2
irq_line::@2: scope:[irq_line] from irq_line irq_line::@10
- [16] irq_line::l#2 = phi( irq_line/0, irq_line::@10/irq_line::l#1 )
- [17] if(irq_line::l#2!=$e6) goto irq_line::@3
+ [18] irq_line::l#2 = phi( irq_line/0, irq_line::@10/irq_line::l#1 )
+ [19] if(irq_line::l#2!=$e6) goto irq_line::@3
to:irq_line::@4
irq_line::@4: scope:[irq_line] from irq_line::@2
- [18] cnt = -- cnt
- [19] if(cnt!=0) goto irq_line::@1
+ [20] cnt = -- cnt
+ [21] if(cnt!=0) goto irq_line::@1
to:irq_line::@11
irq_line::@11: scope:[irq_line] from irq_line::@4
- [20] cnt = 2
- [21] if(hstart>=(char)$140/4+1) goto irq_line::@1
+ [22] cnt = 2
+ [23] if(hstart>=(char)$140/4+1) goto irq_line::@1
to:irq_line::@12
irq_line::@12: scope:[irq_line] from irq_line::@11
- [22] hstart = ++ hstart
- [23] hstop = -- hstop
- [24] vstart = ++ vstart
- [25] vstop = -- vstop
+ [24] hstart = ++ hstart
+ [25] hstop = -- hstop
+ [26] vstart = ++ vstart
+ [27] vstop = -- vstop
to:irq_line::@1
irq_line::@1: scope:[irq_line] from irq_line::@11 irq_line::@12 irq_line::@4
- [26] phi()
- [27] call memset
+ [28] phi()
+ [29] call memset
to:irq_line::@19
irq_line::@19: scope:[irq_line] from irq_line::@1
- [28] irq_line::idx#0 = sin_idx
- [29] sin_idx = -- sin_idx
+ [30] irq_line::idx#0 = sin_idx
+ [31] sin_idx = -- sin_idx
to:irq_line::@13
irq_line::@13: scope:[irq_line] from irq_line::@18 irq_line::@19
- [30] irq_line::idx#2 = phi( irq_line::@18/irq_line::idx#1, irq_line::@19/irq_line::idx#0 )
- [30] irq_line::b#2 = phi( irq_line::@18/irq_line::b#1, irq_line::@19/0 )
- [31] if(irq_line::b#2<8) goto irq_line::@14
+ [32] irq_line::idx#2 = phi( irq_line::@18/irq_line::idx#1, irq_line::@19/irq_line::idx#0 )
+ [32] irq_line::b#2 = phi( irq_line::@18/irq_line::b#1, irq_line::@19/0 )
+ [33] if(irq_line::b#2<8) goto irq_line::@14
to:irq_line::@15
irq_line::@15: scope:[irq_line] from irq_line::@13
- [32] *VERA_ISR = VERA_LINE
+ [34] *VERA_ISR = VERA_LINE
to:irq_line::@return
irq_line::@return: scope:[irq_line] from irq_line::@15
- [33] return
+ [35] return
to:@return
irq_line::@14: scope:[irq_line] from irq_line::@13
- [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2]
+ [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2]
to:irq_line::@16
irq_line::@16: scope:[irq_line] from irq_line::@14 irq_line::@17
- [35] irq_line::i2#2 = phi( irq_line::@14/0, irq_line::@17/irq_line::i2#1 )
- [36] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17
+ [37] irq_line::i2#2 = phi( irq_line::@14/0, irq_line::@17/irq_line::i2#1 )
+ [38] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17
to:irq_line::@18
irq_line::@18: scope:[irq_line] from irq_line::@16
- [37] irq_line::idx#1 = irq_line::idx#2 + $d
- [38] irq_line::b#1 = ++ irq_line::b#2
+ [39] irq_line::idx#1 = irq_line::idx#2 + $d
+ [40] irq_line::b#1 = ++ irq_line::b#2
to:irq_line::@13
irq_line::@17: scope:[irq_line] from irq_line::@16
- [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2]
- [40] irq_line::i2#1 = ++ irq_line::i2#2
+ [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2]
+ [42] irq_line::i2#1 = ++ irq_line::i2#2
to:irq_line::@16
irq_line::@3: scope:[irq_line] from irq_line::@2
- [41] *VERA_DC_BORDER = BARS[irq_line::l#2]
+ [43] *VERA_DC_BORDER = BARS[irq_line::l#2]
to:irq_line::@5
irq_line::@5: scope:[irq_line] from irq_line::@3 irq_line::@6
- [42] irq_line::i#2 = phi( irq_line::@3/0, irq_line::@6/irq_line::i#1 )
- [43] if(irq_line::i#2<$18) goto irq_line::@6
+ [44] irq_line::i#2 = phi( irq_line::@3/0, irq_line::@6/irq_line::i#1 )
+ [45] if(irq_line::i#2<$18) goto irq_line::@6
to:irq_line::@7
irq_line::@7: scope:[irq_line] from irq_line::@5
- [44] *VERA_DC_BORDER = 0
+ [46] *VERA_DC_BORDER = 0
to:irq_line::@8
irq_line::@8: scope:[irq_line] from irq_line::@7 irq_line::@9
- [45] irq_line::i1#2 = phi( irq_line::@7/0, irq_line::@9/irq_line::i1#1 )
- [46] if(irq_line::i1#2<$17) goto irq_line::@9
+ [47] irq_line::i1#2 = phi( irq_line::@7/0, irq_line::@9/irq_line::i1#1 )
+ [48] if(irq_line::i1#2<$17) goto irq_line::@9
to:irq_line::@10
irq_line::@10: scope:[irq_line] from irq_line::@8
asm { nop nop }
- [48] irq_line::l#1 = ++ irq_line::l#2
+ [50] irq_line::l#1 = ++ irq_line::l#2
to:irq_line::@2
irq_line::@9: scope:[irq_line] from irq_line::@8
- [49] irq_line::i1#1 = ++ irq_line::i1#2
+ [51] irq_line::i1#1 = ++ irq_line::i1#2
to:irq_line::@8
irq_line::@6: scope:[irq_line] from irq_line::@5
- [50] irq_line::i#1 = ++ irq_line::i#2
+ [52] irq_line::i#1 = ++ irq_line::i#2
to:irq_line::@5
void main()
main: scope:[main] from __start::@1
- [51] phi()
+ [53] phi()
to:main::SEI1
main::SEI1: scope:[main] from main
asm { sei }
to:main::@2
main::@2: scope:[main] from main::SEI1
- [53] *KERNEL_IRQ = &irq_line
- [54] *VERA_IEN = VERA_LINE
- [55] *VERA_IRQLINE_L = 5
+ [55] *KERNEL_IRQ = &irq_line
+ [56] *VERA_IEN = VERA_LINE
+ [57] *VERA_IRQLINE_L = 5
to:main::CLI1
main::CLI1: scope:[main] from main::@2
asm { cli }
to:main::@1
main::@1: scope:[main] from main::@1 main::CLI1
- [57] phi()
+ [59] phi()
to:main::@1
void * memset(void *str , char c , unsigned int num)
memset: scope:[memset] from irq_line::@1
- [58] phi()
+ [60] phi()
to:memset::@1
memset::@1: scope:[memset] from memset memset::@2
- [59] memset::dst#2 = phi( memset/(char *)memset::str#0, memset::@2/memset::dst#1 )
- [60] if(memset::dst#2!=memset::end#0) goto memset::@2
+ [61] memset::dst#2 = phi( memset/(char *)memset::str#0, memset::@2/memset::dst#1 )
+ [62] if(memset::dst#2!=memset::end#0) goto memset::@2
to:memset::@return
memset::@return: scope:[memset] from memset::@1
- [61] return
+ [63] return
to:@return
memset::@2: scope:[memset] from memset::@1
- [62] *memset::dst#2 = memset::c#0
- [63] memset::dst#1 = ++ memset::dst#2
+ [64] *memset::dst#2 = memset::c#0
+ [65] memset::dst#1 = ++ memset::dst#2
to:memset::@1
diff --git a/src/test/ref/examples/cx16/cx16-rasterbars.log b/src/test/ref/examples/cx16/cx16-rasterbars.log
index 18cd7a889..933993238 100644
--- a/src/test/ref/examples/cx16/cx16-rasterbars.log
+++ b/src/test/ref/examples/cx16/cx16-rasterbars.log
@@ -1,11 +1,54 @@
Resolved forward reference irq_line to __interrupt(rom_min_cx16) void irq_line()
-Setting inferred volatile on symbol affected by address-of: setnam::filename_len in asm { ldafilename_len ldxfilename ldyfilename+1 jsr$ffbd }
-Setting inferred volatile on symbol affected by address-of: setnam::filename in asm { ldafilename_len ldxfilename ldyfilename+1 jsr$ffbd }
-Setting inferred volatile on symbol affected by address-of: setlfs::device in asm { ldxdevice lda#1 ldy#0 jsr$ffba }
-Setting inferred volatile on symbol affected by address-of: load::address in asm { ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcserror lda#$ff error: stastatus }
-Setting inferred volatile on symbol affected by address-of: load::verify in asm { ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcserror lda#$ff error: stastatus }
-Setting inferred volatile on symbol affected by address-of: load::status in asm { ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcserror lda#$ff error: stastatus }
-Setting inferred volatile on symbol affected by address-of: getin::ch in asm { jsr$ffe4 stach }
+Setting inferred volatile on symbol affected by address-of: memcpy_vram_bram::pos in asm { ldypos ldxlen inx ldaptr sta!ptr++1 ldaptr+1 sta!ptr++2 !ptr: lda$ffff,y staVERA_DATA0 iny dex bne!ptr- }
+Setting inferred volatile on symbol affected by address-of: memcpy_vram_bram::len in asm { ldypos ldxlen inx ldaptr sta!ptr++1 ldaptr+1 sta!ptr++2 !ptr: lda$ffff,y staVERA_DATA0 iny dex bne!ptr- }
+Setting inferred volatile on symbol affected by address-of: memcpy_vram_bram::ptr in asm { ldypos ldxlen inx ldaptr sta!ptr++1 ldaptr+1 sta!ptr++2 !ptr: lda$ffff,y staVERA_DATA0 iny dex bne!ptr- }
+Setting inferred volatile on symbol affected by address-of: memcpy_vram_bram::num in asm { ldy#0 ldxnum inx ldaptr sta!ptr++1 ldaptr+1 sta!ptr++2 !ptr: lda$ffff,y staVERA_DATA0 iny dex bne!ptr- }
+Setting inferred volatile on symbol affected by address-of: cbm_k_setlfs::device in asm { ldxdevice ldachannel ldycommand jsrCBM_SETLFS }
+Setting inferred volatile on symbol affected by address-of: cbm_k_setlfs::channel in asm { ldxdevice ldachannel ldycommand jsrCBM_SETLFS }
+Setting inferred volatile on symbol affected by address-of: cbm_k_setlfs::command in asm { ldxdevice ldachannel ldycommand jsrCBM_SETLFS }
+Setting inferred volatile on symbol affected by address-of: cbm_k_setnam::filename_len in asm { ldafilename_len ldxfilename ldyfilename+1 jsrCBM_SETNAM }
+Setting inferred volatile on symbol affected by address-of: cbm_k_setnam::filename in asm { ldafilename_len ldxfilename ldyfilename+1 jsrCBM_SETNAM }
+Setting inferred volatile on symbol affected by address-of: cbm_k_close::channel in asm { ldachannel jsrCBM_CLOSE }
+Setting inferred volatile on symbol affected by address-of: cbm_k_chkin::channel in asm { ldxchannel jsrCBM_CHKIN stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_chkin::status in asm { ldxchannel jsrCBM_CHKIN stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_chrin::ch in asm { jsrCBM_CHRIN stach }
+Setting inferred volatile on symbol affected by address-of: cbm_k_getin::ch in asm { jsrCBM_GETIN stach }
+Setting inferred volatile on symbol affected by address-of: cbm_k_readst::status in asm { jsrCBM_READST stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_load::address in asm { .byte$db ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcs!error+ lda#$ff !error: stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_load::verify in asm { .byte$db ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcs!error+ lda#$ff !error: stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_load::status in asm { .byte$db ldxaddress ldyaddress+1 ldaverify jsr$ffd5 bcs!error+ lda#$ff !error: stastatus }
+Setting inferred volatile on symbol affected by address-of: cbm_k_plot_get::x in kickasm( uses cbm_k_plot_get::x uses cbm_k_plot_get::y uses CBM_PLOT) {{ sec
+ jsr CBM_PLOT
+ stx y
+ sty x
+ }}
+Setting inferred volatile on symbol affected by address-of: cbm_k_plot_get::y in kickasm( uses cbm_k_plot_get::x uses cbm_k_plot_get::y uses CBM_PLOT) {{ sec
+ jsr CBM_PLOT
+ stx y
+ sty x
+ }}
+Setting inferred volatile on symbol affected by address-of: cbm_k_plot_set::x in kickasm( uses cbm_k_plot_set::x uses cbm_k_plot_set::y uses CBM_PLOT) {{ ldx y
+ ldy x
+ clc
+ jsr CBM_PLOT
+ }}
+Setting inferred volatile on symbol affected by address-of: cbm_k_plot_set::y in kickasm( uses cbm_k_plot_set::x uses cbm_k_plot_set::y uses CBM_PLOT) {{ ldx y
+ ldy x
+ clc
+ jsr CBM_PLOT
+ }}
+Setting inferred volatile on symbol affected by address-of: cbm_k_chrout::ch in asm { ldach jsrCBM_CHROUT }
+Setting inferred volatile on symbol affected by address-of: cx16_k_macptr::bytes in asm { ldabytes ldxbuffer ldybuffer+1 clc jsrCX16_MACPTR stxbytes_read stybytes_read+1 bcc!+ lda#$FF stabytes_read stabytes_read+1 !: }
+Setting inferred volatile on symbol affected by address-of: cx16_k_macptr::buffer in asm { ldabytes ldxbuffer ldybuffer+1 clc jsrCX16_MACPTR stxbytes_read stybytes_read+1 bcc!+ lda#$FF stabytes_read stabytes_read+1 !: }
+Setting inferred volatile on symbol affected by address-of: cx16_k_macptr::bytes_read in asm { ldabytes ldxbuffer ldybuffer+1 clc jsrCX16_MACPTR stxbytes_read stybytes_read+1 bcc!+ lda#$FF stabytes_read stabytes_read+1 !: }
+Setting inferred volatile on symbol affected by address-of: cx16_k_screen_set_charset::charset in asm { ldacharset ldxoffset jsrCX16_SCREEN_SET_CHARSET }
+Setting inferred volatile on symbol affected by address-of: cx16_k_screen_set_charset::offset in asm { ldacharset ldxoffset jsrCX16_SCREEN_SET_CHARSET }
+Inlined call call bank_set_bram(bank_bram_ptr_inc::bank)
+Inlined call memcpy_vram_bram::bank = call bank_get_bram
+Inlined call call bank_set_bram(memcpy_vram_bram::sbank_bram)
+Inlined call call bank_set_bram(memcpy_vram_bram::sbank_bram)
+Inlined call call bank_set_bram(memcpy_vram_bram::sbank_bram)
+Inlined call call bank_set_bram(memcpy_vram_bram::bank)
Inlined call call SEI
Inlined call call CLI
Inlined call call __init
@@ -57,6 +100,16 @@ memset::@return: scope:[memset] from memset::@1
return
to:@return
+void cx16_init()
+cx16_init: scope:[cx16_init] from __start::__init1
+ isr_vsync#0 = *((unsigned int *)$314)
+ to:cx16_init::@return
+cx16_init::@return: scope:[cx16_init] from cx16_init
+ isr_vsync#5 = phi( cx16_init/isr_vsync#0 )
+ isr_vsync#1 = isr_vsync#5
+ return
+ to:@return
+
void main()
main: scope:[main] from __start::@1
to:main::SEI1
@@ -206,26 +259,44 @@ void __start()
__start: scope:[__start] from
to:__start::__init1
__start::__init1: scope:[__start] from __start
+ BRAM = 0
+ BROM = 4
+ isr_vsync#2 = $314
hstart = (char)0/4
hstop = (char)$280/4
vstart = (char)0/2
vstop = (char)$1e0/2
cnt = 2
sin_idx = $64
- to:__start::@1
-__start::@1: scope:[__start] from __start::__init1
- call main
+ call cx16_init
to:__start::@2
-__start::@2: scope:[__start] from __start::@1
+__start::@2: scope:[__start] from __start::__init1
+ isr_vsync#6 = phi( __start::__init1/isr_vsync#1 )
+ isr_vsync#3 = isr_vsync#6
+ to:__start::@1
+__start::@1: scope:[__start] from __start::@2
+ isr_vsync#9 = phi( __start::@2/isr_vsync#3 )
+ call main
+ to:__start::@3
+__start::@3: scope:[__start] from __start::@1
+ isr_vsync#8 = phi( __start::@1/isr_vsync#9 )
to:__start::@return
-__start::@return: scope:[__start] from __start::@2
+__start::@return: scope:[__start] from __start::@3
+ isr_vsync#7 = phi( __start::@3/isr_vsync#8 )
+ isr_vsync#4 = isr_vsync#7
return
to:@return
SYMBOL TABLE SSA
__constant char BAR[$20] = { $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f, $1f, $1e, $1d, $1c, $1b, $1a, $19, $18, $17, $16, $15, $14, $13, $12, $11, $10 }
__constant char BARS[$e6] = { fill( $e6, 0) }
+__loadstore volatile char BRAM // !zp[-1]:0
+__loadstore volatile char BROM // !zp[-1]:1
__constant void (** const KERNEL_IRQ)() = (void (**)())$314
+__constant char RADIX::BINARY = 2
+__constant char RADIX::DECIMAL = $a
+__constant char RADIX::HEXADECIMAL = $10
+__constant char RADIX::OCTAL = 8
__constant char SIN[$100] = kickasm {{ .fill 256, 99+99*sin(i*2*PI/256)
}}
__constant char * const VERA_CTRL = (char *)$9f25
@@ -241,6 +312,7 @@ __constant char * const VERA_ISR = (char *)$9f27
__constant const char VERA_LINE = 2
void __start()
__loadstore volatile char cnt
+void cx16_init()
__loadstore volatile char hstart
__loadstore volatile char hstop
__interrupt(rom_min_cx16) void irq_line()
@@ -301,6 +373,17 @@ char irq_line::l#6
char irq_line::l#7
char irq_line::l#8
char irq_line::l#9
+unsigned int isr_vsync
+unsigned int isr_vsync#0
+unsigned int isr_vsync#1
+unsigned int isr_vsync#2
+unsigned int isr_vsync#3
+unsigned int isr_vsync#4
+unsigned int isr_vsync#5
+unsigned int isr_vsync#6
+unsigned int isr_vsync#7
+unsigned int isr_vsync#8
+unsigned int isr_vsync#9
void main()
void * memset(void *str , char c , unsigned int num)
bool memset::$0
@@ -361,6 +444,7 @@ Inlining cast *VERA_DC_BORDER = (unumber)0
Inlining cast memset::c#0 = (unumber)0
Inlining cast cnt = (unumber)2
Successful SSA optimization Pass2InlineCast
+Simplifying constant pointer cast (void (**)()) 788
Simplifying constant pointer cast (char *) 40741
Simplifying constant pointer cast (char *) 40742
Simplifying constant pointer cast (char *) 40743
@@ -370,8 +454,8 @@ Simplifying constant pointer cast (char *) 40745
Simplifying constant pointer cast (char *) 40746
Simplifying constant pointer cast (char *) 40747
Simplifying constant pointer cast (char *) 40748
-Simplifying constant pointer cast (void (**)()) 788
Simplifying constant integer cast 0
+Simplifying constant pointer cast (unsigned int *) 788
Simplifying constant integer cast 5
Simplifying constant integer cast $e6
Simplifying constant integer cast 0
@@ -396,8 +480,8 @@ Finalized unsigned number type (char) 8
Finalized unsigned number type (char) $d
Successful SSA optimization PassNFinalizeNumberTypeConversions
Inversing boolean not [2] memset::$1 = memset::num#1 <= 0 from [1] memset::$0 = memset::num#1 > 0
-Inversing boolean not [40] irq_line::$1 = cnt != 0 from [39] irq_line::$0 = cnt == 0
-Inversing boolean not [69] irq_line::$8 = hstart > (char)$140/4 from [68] irq_line::$7 = hstart <= (char)$140/4
+Inversing boolean not [44] irq_line::$1 = cnt != 0 from [43] irq_line::$0 = cnt == 0
+Inversing boolean not [73] irq_line::$8 = hstart > (char)$140/4 from [72] irq_line::$7 = hstart <= (char)$140/4
Successful SSA optimization Pass2UnaryNotSimplification
Alias memset::return#0 = memset::str#1 memset::return#3 memset::return#1
Alias memset::str#2 = memset::str#3
@@ -407,6 +491,7 @@ Alias memset::c#1 = memset::c#2
Alias memset::dst#2 = memset::dst#3
Alias memset::end#1 = memset::end#2
Alias memset::str#4 = memset::str#5
+Alias isr_vsync#0 = isr_vsync#5 isr_vsync#1
Alias irq_line::l#2 = irq_line::l#3
Alias irq_line::i#2 = irq_line::i#3
Alias irq_line::l#6 = irq_line::l#9 irq_line::l#8
@@ -419,6 +504,7 @@ Alias irq_line::i2#2 = irq_line::i2#3
Alias irq_line::bar#1 = irq_line::bar#2
Alias irq_line::idx#3 = irq_line::idx#6 irq_line::idx#5
Alias irq_line::b#3 = irq_line::b#6 irq_line::b#4
+Alias isr_vsync#3 = isr_vsync#6 isr_vsync#9 isr_vsync#8 isr_vsync#7 isr_vsync#4
Successful SSA optimization Pass2AliasElimination
Identical Phi Values memset::num#1 memset::num#0
Identical Phi Values memset::str#2 memset::str#0
@@ -431,21 +517,22 @@ Identical Phi Values irq_line::l#4 irq_line::l#6
Identical Phi Values irq_line::bar#1 irq_line::bar#0
Identical Phi Values irq_line::idx#3 irq_line::idx#2
Identical Phi Values irq_line::b#3 irq_line::b#2
+Identical Phi Values isr_vsync#3 isr_vsync#0
Successful SSA optimization Pass2IdenticalPhiElimination
Identical Phi Values memset::return#0 memset::str#0
Successful SSA optimization Pass2IdenticalPhiElimination
Simple Condition memset::$1 [2] if(memset::num#0<=0) goto memset::@1
Simple Condition memset::$3 [9] if(memset::dst#2!=memset::end#0) goto memset::@4
-Simple Condition irq_line::$4 [28] if(irq_line::l#2!=$e6) goto irq_line::@3
-Simple Condition irq_line::$1 [33] if(cnt!=0) goto irq_line::@1
-Simple Condition irq_line::$5 [36] if(irq_line::i#2<$18) goto irq_line::@6
-Simple Condition irq_line::$6 [42] if(irq_line::i1#2<$17) goto irq_line::@9
-Simple Condition irq_line::$8 [56] if(hstart>(char)$140/4) goto irq_line::@1
-Simple Condition irq_line::$9 [63] if(irq_line::b#2<8) goto irq_line::@14
-Simple Condition irq_line::$12 [70] if(irq_line::i2#2(char)$140/4) goto irq_line::@1
+Simple Condition irq_line::$9 [65] if(irq_line::b#2<8) goto irq_line::@14
+Simple Condition irq_line::$12 [72] if(irq_line::i2#2(char)$140/4) goto irq_line::@1
-Simplifying constant evaluating to zero (char)0/4 in [76] hstart = (char)0/4
-Simplifying constant evaluating to zero (char)0/2 in [78] vstart = (char)0/2
+Rewriting conditional comparison [58] if(hstart>(char)$140/4) goto irq_line::@1
+Simplifying constant evaluating to zero (char)0/4 in [81] hstart = (char)0/4
+Simplifying constant evaluating to zero (char)0/2 in [83] vstart = (char)0/2
Successful SSA optimization PassNSimplifyConstantZero
+Removing call to empty/unused procedure [87] call cx16_init
+Successful SSA optimization PassNEliminateUnusedConstructors
+Eliminating variable isr_vsync#0 from unused block cx16_init
+Removing unused procedure cx16_init
+Removing unused procedure block cx16_init
+Removing unused procedure block cx16_init::@return
Removing unused block main::@return
Successful SSA optimization Pass2EliminateUnusedBlocks
Eliminating unused constant memset::return#2
@@ -510,6 +604,10 @@ Constant inlined irq_line::i1#0 = 0
Constant inlined memset::dst#0 = (char *)memset::str#0
Constant inlined irq_line::b#0 = 0
Successful SSA optimization Pass2ConstantInlining
+Finalized unsigned number type (char) 2
+Finalized unsigned number type (char) 8
+Finalized unsigned number type (char) $a
+Finalized unsigned number type (char) $10
Finalized unsigned number type (unsigned int) $100
Finalized unsigned number type (char) $e6
Finalized unsigned number type (char) $e6
@@ -522,8 +620,9 @@ Finalized unsigned number type (unsigned int) $1e0
Finalized unsigned number type (char) 2
Successful SSA optimization PassNFinalizeNumberTypeConversions
Adding NOP phi() at start of __start
-Adding NOP phi() at start of __start::@1
Adding NOP phi() at start of __start::@2
+Adding NOP phi() at start of __start::@1
+Adding NOP phi() at start of __start::@3
Adding NOP phi() at start of irq_line::@1
Adding NOP phi() at start of main
Adding NOP phi() at start of main::@1
@@ -531,20 +630,21 @@ Adding NOP phi() at start of memset
Adding NOP phi() at start of memset::@2
Adding NOP phi() at start of memset::@1
CALL GRAPH
-Calls in [__start] to main:8
-Calls in [irq_line] to memset:28
+Calls in [__start] to main:11
+Calls in [irq_line] to memset:31
Created 7 initial phi equivalence classes
-Coalesced [31] irq_line::idx#8 = irq_line::idx#0
-Coalesced [41] irq_line::b#7 = irq_line::b#1
-Coalesced [42] irq_line::idx#7 = irq_line::idx#1
-Coalesced [45] irq_line::i2#4 = irq_line::i2#1
-Coalesced [54] irq_line::l#10 = irq_line::l#1
-Coalesced [56] irq_line::i1#4 = irq_line::i1#1
-Coalesced [58] irq_line::i#4 = irq_line::i#1
-Coalesced [74] memset::dst#4 = memset::dst#1
+Coalesced [34] irq_line::idx#8 = irq_line::idx#0
+Coalesced [44] irq_line::b#7 = irq_line::b#1
+Coalesced [45] irq_line::idx#7 = irq_line::idx#1
+Coalesced [48] irq_line::i2#4 = irq_line::i2#1
+Coalesced [57] irq_line::l#10 = irq_line::l#1
+Coalesced [59] irq_line::i1#4 = irq_line::i1#1
+Coalesced [61] irq_line::i#4 = irq_line::i#1
+Coalesced [77] memset::dst#4 = memset::dst#1
Coalesced down to 7 phi equivalence classes
Culled Empty Block label __start::@2
+Culled Empty Block label __start::@3
Culled Empty Block label memset::@2
Culled Empty Block label memset::@1
Renumbering block memset::@3 to memset::@1
@@ -563,144 +663,148 @@ __start: scope:[__start] from
[0] phi()
to:__start::__init1
__start::__init1: scope:[__start] from __start
- [1] hstart = 0
- [2] hstop = (char)$280/4
- [3] vstart = 0
- [4] vstop = (char)$1e0/2
- [5] cnt = 2
- [6] sin_idx = $64
+ [1] BRAM = 0
+ [2] BROM = 4
+ [3] hstart = 0
+ [4] hstop = (char)$280/4
+ [5] vstart = 0
+ [6] vstop = (char)$1e0/2
+ [7] cnt = 2
+ [8] sin_idx = $64
to:__start::@1
__start::@1: scope:[__start] from __start::__init1
- [7] phi()
- [8] call main
+ [9] phi()
+ [10] call main
to:__start::@return
__start::@return: scope:[__start] from __start::@1
- [9] return
+ [11] return
to:@return
__interrupt(rom_min_cx16) void irq_line()
irq_line: scope:[irq_line] from
- [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL
- [11] *VERA_DC_HSTART = hstart
- [12] *VERA_DC_HSTOP = hstop
- [13] *VERA_DC_VSTART = vstart
- [14] *VERA_DC_VSTOP = vstop
- [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL
+ [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL
+ [13] *VERA_DC_HSTART = hstart
+ [14] *VERA_DC_HSTOP = hstop
+ [15] *VERA_DC_VSTART = vstart
+ [16] *VERA_DC_VSTOP = vstop
+ [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL
to:irq_line::@2
irq_line::@2: scope:[irq_line] from irq_line irq_line::@10
- [16] irq_line::l#2 = phi( irq_line/0, irq_line::@10/irq_line::l#1 )
- [17] if(irq_line::l#2!=$e6) goto irq_line::@3
+ [18] irq_line::l#2 = phi( irq_line/0, irq_line::@10/irq_line::l#1 )
+ [19] if(irq_line::l#2!=$e6) goto irq_line::@3
to:irq_line::@4
irq_line::@4: scope:[irq_line] from irq_line::@2
- [18] cnt = -- cnt
- [19] if(cnt!=0) goto irq_line::@1
+ [20] cnt = -- cnt
+ [21] if(cnt!=0) goto irq_line::@1
to:irq_line::@11
irq_line::@11: scope:[irq_line] from irq_line::@4
- [20] cnt = 2
- [21] if(hstart>=(char)$140/4+1) goto irq_line::@1
+ [22] cnt = 2
+ [23] if(hstart>=(char)$140/4+1) goto irq_line::@1
to:irq_line::@12
irq_line::@12: scope:[irq_line] from irq_line::@11
- [22] hstart = ++ hstart
- [23] hstop = -- hstop
- [24] vstart = ++ vstart
- [25] vstop = -- vstop
+ [24] hstart = ++ hstart
+ [25] hstop = -- hstop
+ [26] vstart = ++ vstart
+ [27] vstop = -- vstop
to:irq_line::@1
irq_line::@1: scope:[irq_line] from irq_line::@11 irq_line::@12 irq_line::@4
- [26] phi()
- [27] call memset
+ [28] phi()
+ [29] call memset
to:irq_line::@19
irq_line::@19: scope:[irq_line] from irq_line::@1
- [28] irq_line::idx#0 = sin_idx
- [29] sin_idx = -- sin_idx
+ [30] irq_line::idx#0 = sin_idx
+ [31] sin_idx = -- sin_idx
to:irq_line::@13
irq_line::@13: scope:[irq_line] from irq_line::@18 irq_line::@19
- [30] irq_line::idx#2 = phi( irq_line::@18/irq_line::idx#1, irq_line::@19/irq_line::idx#0 )
- [30] irq_line::b#2 = phi( irq_line::@18/irq_line::b#1, irq_line::@19/0 )
- [31] if(irq_line::b#2<8) goto irq_line::@14
+ [32] irq_line::idx#2 = phi( irq_line::@18/irq_line::idx#1, irq_line::@19/irq_line::idx#0 )
+ [32] irq_line::b#2 = phi( irq_line::@18/irq_line::b#1, irq_line::@19/0 )
+ [33] if(irq_line::b#2<8) goto irq_line::@14
to:irq_line::@15
irq_line::@15: scope:[irq_line] from irq_line::@13
- [32] *VERA_ISR = VERA_LINE
+ [34] *VERA_ISR = VERA_LINE
to:irq_line::@return
irq_line::@return: scope:[irq_line] from irq_line::@15
- [33] return
+ [35] return
to:@return
irq_line::@14: scope:[irq_line] from irq_line::@13
- [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2]
+ [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2]
to:irq_line::@16
irq_line::@16: scope:[irq_line] from irq_line::@14 irq_line::@17
- [35] irq_line::i2#2 = phi( irq_line::@14/0, irq_line::@17/irq_line::i2#1 )
- [36] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17
+ [37] irq_line::i2#2 = phi( irq_line::@14/0, irq_line::@17/irq_line::i2#1 )
+ [38] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17
to:irq_line::@18
irq_line::@18: scope:[irq_line] from irq_line::@16
- [37] irq_line::idx#1 = irq_line::idx#2 + $d
- [38] irq_line::b#1 = ++ irq_line::b#2
+ [39] irq_line::idx#1 = irq_line::idx#2 + $d
+ [40] irq_line::b#1 = ++ irq_line::b#2
to:irq_line::@13
irq_line::@17: scope:[irq_line] from irq_line::@16
- [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2]
- [40] irq_line::i2#1 = ++ irq_line::i2#2
+ [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2]
+ [42] irq_line::i2#1 = ++ irq_line::i2#2
to:irq_line::@16
irq_line::@3: scope:[irq_line] from irq_line::@2
- [41] *VERA_DC_BORDER = BARS[irq_line::l#2]
+ [43] *VERA_DC_BORDER = BARS[irq_line::l#2]
to:irq_line::@5
irq_line::@5: scope:[irq_line] from irq_line::@3 irq_line::@6
- [42] irq_line::i#2 = phi( irq_line::@3/0, irq_line::@6/irq_line::i#1 )
- [43] if(irq_line::i#2<$18) goto irq_line::@6
+ [44] irq_line::i#2 = phi( irq_line::@3/0, irq_line::@6/irq_line::i#1 )
+ [45] if(irq_line::i#2<$18) goto irq_line::@6
to:irq_line::@7
irq_line::@7: scope:[irq_line] from irq_line::@5
- [44] *VERA_DC_BORDER = 0
+ [46] *VERA_DC_BORDER = 0
to:irq_line::@8
irq_line::@8: scope:[irq_line] from irq_line::@7 irq_line::@9
- [45] irq_line::i1#2 = phi( irq_line::@7/0, irq_line::@9/irq_line::i1#1 )
- [46] if(irq_line::i1#2<$17) goto irq_line::@9
+ [47] irq_line::i1#2 = phi( irq_line::@7/0, irq_line::@9/irq_line::i1#1 )
+ [48] if(irq_line::i1#2<$17) goto irq_line::@9
to:irq_line::@10
irq_line::@10: scope:[irq_line] from irq_line::@8
asm { nop nop }
- [48] irq_line::l#1 = ++ irq_line::l#2
+ [50] irq_line::l#1 = ++ irq_line::l#2
to:irq_line::@2
irq_line::@9: scope:[irq_line] from irq_line::@8
- [49] irq_line::i1#1 = ++ irq_line::i1#2
+ [51] irq_line::i1#1 = ++ irq_line::i1#2
to:irq_line::@8
irq_line::@6: scope:[irq_line] from irq_line::@5
- [50] irq_line::i#1 = ++ irq_line::i#2
+ [52] irq_line::i#1 = ++ irq_line::i#2
to:irq_line::@5
void main()
main: scope:[main] from __start::@1
- [51] phi()
+ [53] phi()
to:main::SEI1
main::SEI1: scope:[main] from main
asm { sei }
to:main::@2
main::@2: scope:[main] from main::SEI1
- [53] *KERNEL_IRQ = &irq_line
- [54] *VERA_IEN = VERA_LINE
- [55] *VERA_IRQLINE_L = 5
+ [55] *KERNEL_IRQ = &irq_line
+ [56] *VERA_IEN = VERA_LINE
+ [57] *VERA_IRQLINE_L = 5
to:main::CLI1
main::CLI1: scope:[main] from main::@2
asm { cli }
to:main::@1
main::@1: scope:[main] from main::@1 main::CLI1
- [57] phi()
+ [59] phi()
to:main::@1
void * memset(void *str , char c , unsigned int num)
memset: scope:[memset] from irq_line::@1
- [58] phi()
+ [60] phi()
to:memset::@1
memset::@1: scope:[memset] from memset memset::@2
- [59] memset::dst#2 = phi( memset/(char *)memset::str#0, memset::@2/memset::dst#1 )
- [60] if(memset::dst#2!=memset::end#0) goto memset::@2
+ [61] memset::dst#2 = phi( memset/(char *)memset::str#0, memset::@2/memset::dst#1 )
+ [62] if(memset::dst#2!=memset::end#0) goto memset::@2
to:memset::@return
memset::@return: scope:[memset] from memset::@1
- [61] return
+ [63] return
to:@return
memset::@2: scope:[memset] from memset::@1
- [62] *memset::dst#2 = memset::c#0
- [63] memset::dst#1 = ++ memset::dst#2
+ [64] *memset::dst#2 = memset::c#0
+ [65] memset::dst#1 = ++ memset::dst#2
to:memset::@1
VARIABLE REGISTER WEIGHTS
+__loadstore volatile char BRAM // !zp[-1]:0 20.0
+__loadstore volatile char BROM // !zp[-1]:1 20.0
void __start()
__loadstore volatile char cnt // 0.5263157894736842
__loadstore volatile char hstart // 0.4545454545454546
@@ -727,6 +831,7 @@ char irq_line::idx#2 // 5.0
char irq_line::l
char irq_line::l#1 // 22.0
char irq_line::l#2 // 4.0
+unsigned int isr_vsync
void main()
void * memset(void *str , char c , unsigned int num)
char memset::c
@@ -749,6 +854,8 @@ Initial phi equivalence classes
[ irq_line::i#2 irq_line::i#1 ]
[ irq_line::i1#2 irq_line::i1#1 ]
[ memset::dst#2 memset::dst#1 ]
+Added variable BRAM to live range equivalence class [ BRAM ]
+Added variable BROM to live range equivalence class [ BROM ]
Added variable hstart to live range equivalence class [ hstart ]
Added variable hstop to live range equivalence class [ hstop ]
Added variable vstart to live range equivalence class [ vstart ]
@@ -764,6 +871,8 @@ Complete equivalence classes
[ irq_line::i#2 irq_line::i#1 ]
[ irq_line::i1#2 irq_line::i1#1 ]
[ memset::dst#2 memset::dst#1 ]
+[ BRAM ]
+[ BROM ]
[ hstart ]
[ hstop ]
[ vstart ]
@@ -771,134 +880,146 @@ Complete equivalence classes
[ cnt ]
[ sin_idx ]
[ irq_line::bar#0 ]
-Allocated zp[1]:2 [ irq_line::i2#2 irq_line::i2#1 ]
-Allocated zp[1]:3 [ irq_line::i#2 irq_line::i#1 ]
-Allocated zp[1]:4 [ irq_line::i1#2 irq_line::i1#1 ]
-Allocated zp[2]:5 [ memset::dst#2 memset::dst#1 ]
-Allocated zp[1]:7 [ irq_line::b#2 irq_line::b#1 ]
-Allocated zp[1]:8 [ irq_line::l#2 irq_line::l#1 ]
-Allocated zp[2]:9 [ irq_line::bar#0 ]
-Allocated zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Allocated zp[1]:12 [ cnt ]
-Allocated zp[1]:13 [ hstart ]
-Allocated zp[1]:14 [ hstop ]
-Allocated zp[1]:15 [ vstart ]
-Allocated zp[1]:16 [ vstop ]
-Allocated zp[1]:17 [ sin_idx ]
+Allocated zp[1]:34 [ irq_line::i2#2 irq_line::i2#1 ]
+Allocated zp[1]:35 [ irq_line::i#2 irq_line::i#1 ]
+Allocated zp[1]:36 [ irq_line::i1#2 irq_line::i1#1 ]
+Allocated zp[2]:37 [ memset::dst#2 memset::dst#1 ]
+Allocated zp[1]:39 [ irq_line::b#2 irq_line::b#1 ]
+Allocated zp[1]:40 [ irq_line::l#2 irq_line::l#1 ]
+Allocated zp[2]:41 [ irq_line::bar#0 ]
+Allocated zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Allocated zp[1]:44 [ cnt ]
+Allocated zp[1]:45 [ hstart ]
+Allocated zp[1]:46 [ hstop ]
+Allocated zp[1]:47 [ vstart ]
+Allocated zp[1]:48 [ vstop ]
+Allocated zp[1]:49 [ sin_idx ]
REGISTER UPLIFT POTENTIAL REGISTERS
-Statement [1] hstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [2] hstop = (char)$280/4 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [3] vstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [4] vstop = (char)$1e0/2 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [5] cnt = 2 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [6] sin_idx = $64 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [11] *VERA_DC_HSTART = hstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [12] *VERA_DC_HSTOP = hstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [13] *VERA_DC_VSTART = vstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [14] *VERA_DC_VSTOP = vstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [19] if(cnt!=0) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [20] cnt = 2 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [21] if(hstart>=(char)$140/4+1) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [32] *VERA_ISR = VERA_LINE [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] { } ) always clobbers reg byte a
-Removing always clobbered register reg byte a as potential for zp[1]:7 [ irq_line::b#2 irq_line::b#1 ]
-Removing always clobbered register reg byte a as potential for zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Statement [37] irq_line::idx#1 = irq_line::idx#2 + $d [ irq_line::b#2 irq_line::idx#1 ] ( [ irq_line::b#2 irq_line::idx#1 ] { } ) always clobbers reg byte a
-Statement [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] { } ) always clobbers reg byte a
-Removing always clobbered register reg byte a as potential for zp[1]:2 [ irq_line::i2#2 irq_line::i2#1 ]
-Statement [41] *VERA_DC_BORDER = BARS[irq_line::l#2] [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
-Removing always clobbered register reg byte a as potential for zp[1]:8 [ irq_line::l#2 irq_line::l#1 ]
-Statement [44] *VERA_DC_BORDER = 0 [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
-Statement [53] *KERNEL_IRQ = &irq_line [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [54] *VERA_IEN = VERA_LINE [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [55] *VERA_IRQLINE_L = 5 [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [60] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::dst#2 ] ( memset:27 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a
-Statement [62] *memset::dst#2 = memset::c#0 [ memset::dst#2 ] ( memset:27 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
-Statement [1] hstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [2] hstop = (char)$280/4 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [3] vstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [4] vstop = (char)$1e0/2 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [5] cnt = 2 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [6] sin_idx = $64 [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [11] *VERA_DC_HSTART = hstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [12] *VERA_DC_HSTOP = hstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [13] *VERA_DC_VSTART = vstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [14] *VERA_DC_VSTOP = vstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
-Statement [19] if(cnt!=0) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [20] cnt = 2 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [21] if(hstart>=(char)$140/4+1) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
-Statement [32] *VERA_ISR = VERA_LINE [ ] ( [ ] { } ) always clobbers reg byte a
-Statement [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] { } ) always clobbers reg byte a
-Statement [37] irq_line::idx#1 = irq_line::idx#2 + $d [ irq_line::b#2 irq_line::idx#1 ] ( [ irq_line::b#2 irq_line::idx#1 ] { } ) always clobbers reg byte a
-Statement [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] { } ) always clobbers reg byte a
-Statement [41] *VERA_DC_BORDER = BARS[irq_line::l#2] [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
-Statement [44] *VERA_DC_BORDER = 0 [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
-Statement [53] *KERNEL_IRQ = &irq_line [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [54] *VERA_IEN = VERA_LINE [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [55] *VERA_IRQLINE_L = 5 [ ] ( main:8 [ ] { } ) always clobbers reg byte a
-Statement [60] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::dst#2 ] ( memset:27 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a
-Statement [62] *memset::dst#2 = memset::c#0 [ memset::dst#2 ] ( memset:27 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
-Potential registers zp[1]:8 [ irq_line::l#2 irq_line::l#1 ] : zp[1]:8 , reg byte x , reg byte y ,
-Potential registers zp[1]:7 [ irq_line::b#2 irq_line::b#1 ] : zp[1]:7 , reg byte x , reg byte y ,
-Potential registers zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ] : zp[1]:11 , reg byte x , reg byte y ,
-Potential registers zp[1]:2 [ irq_line::i2#2 irq_line::i2#1 ] : zp[1]:2 , reg byte x , reg byte y ,
-Potential registers zp[1]:3 [ irq_line::i#2 irq_line::i#1 ] : zp[1]:3 , reg byte a , reg byte x , reg byte y ,
-Potential registers zp[1]:4 [ irq_line::i1#2 irq_line::i1#1 ] : zp[1]:4 , reg byte a , reg byte x , reg byte y ,
-Potential registers zp[2]:5 [ memset::dst#2 memset::dst#1 ] : zp[2]:5 ,
-Potential registers zp[1]:13 [ hstart ] : zp[1]:13 ,
-Potential registers zp[1]:14 [ hstop ] : zp[1]:14 ,
-Potential registers zp[1]:15 [ vstart ] : zp[1]:15 ,
-Potential registers zp[1]:16 [ vstop ] : zp[1]:16 ,
-Potential registers zp[1]:12 [ cnt ] : zp[1]:12 ,
-Potential registers zp[1]:17 [ sin_idx ] : zp[1]:17 ,
-Potential registers zp[2]:9 [ irq_line::bar#0 ] : zp[2]:9 ,
+Statement [1] BRAM = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [2] BROM = 4 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [3] hstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [4] hstop = (char)$280/4 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [5] vstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [6] vstop = (char)$1e0/2 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [7] cnt = 2 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [8] sin_idx = $64 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [13] *VERA_DC_HSTART = hstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [14] *VERA_DC_HSTOP = hstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [15] *VERA_DC_VSTART = vstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [16] *VERA_DC_VSTOP = vstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [21] if(cnt!=0) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [22] cnt = 2 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [23] if(hstart>=(char)$140/4+1) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [34] *VERA_ISR = VERA_LINE [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] { } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:39 [ irq_line::b#2 irq_line::b#1 ]
+Removing always clobbered register reg byte a as potential for zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Statement [39] irq_line::idx#1 = irq_line::idx#2 + $d [ irq_line::b#2 irq_line::idx#1 ] ( [ irq_line::b#2 irq_line::idx#1 ] { } ) always clobbers reg byte a
+Statement [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] { } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:34 [ irq_line::i2#2 irq_line::i2#1 ]
+Statement [43] *VERA_DC_BORDER = BARS[irq_line::l#2] [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
+Removing always clobbered register reg byte a as potential for zp[1]:40 [ irq_line::l#2 irq_line::l#1 ]
+Statement [46] *VERA_DC_BORDER = 0 [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
+Statement [55] *KERNEL_IRQ = &irq_line [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [56] *VERA_IEN = VERA_LINE [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [57] *VERA_IRQLINE_L = 5 [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [62] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::dst#2 ] ( memset:29 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a
+Statement [64] *memset::dst#2 = memset::c#0 [ memset::dst#2 ] ( memset:29 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
+Statement [1] BRAM = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [2] BROM = 4 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [3] hstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [4] hstop = (char)$280/4 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [5] vstart = 0 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [6] vstop = (char)$1e0/2 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [7] cnt = 2 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [8] sin_idx = $64 [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [13] *VERA_DC_HSTART = hstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [14] *VERA_DC_HSTOP = hstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [15] *VERA_DC_VSTART = vstart [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [16] *VERA_DC_VSTOP = vstop [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL [ hstart hstop vstart vstop cnt sin_idx ] ( [ hstart hstop vstart vstop cnt sin_idx ] { } ) always clobbers reg byte a
+Statement [21] if(cnt!=0) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [22] cnt = 2 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [23] if(hstart>=(char)$140/4+1) goto irq_line::@1 [ hstart hstop vstart vstop sin_idx ] ( [ hstart hstop vstart vstop sin_idx ] { } ) always clobbers reg byte a
+Statement [34] *VERA_ISR = VERA_LINE [ ] ( [ ] { } ) always clobbers reg byte a
+Statement [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 ] { } ) always clobbers reg byte a
+Statement [39] irq_line::idx#1 = irq_line::idx#2 + $d [ irq_line::b#2 irq_line::idx#1 ] ( [ irq_line::b#2 irq_line::idx#1 ] { } ) always clobbers reg byte a
+Statement [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] ( [ irq_line::b#2 irq_line::idx#2 irq_line::bar#0 irq_line::i2#2 ] { } ) always clobbers reg byte a
+Statement [43] *VERA_DC_BORDER = BARS[irq_line::l#2] [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
+Statement [46] *VERA_DC_BORDER = 0 [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] ( [ hstart hstop vstart vstop cnt sin_idx irq_line::l#2 ] { } ) always clobbers reg byte a
+Statement [55] *KERNEL_IRQ = &irq_line [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [56] *VERA_IEN = VERA_LINE [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [57] *VERA_IRQLINE_L = 5 [ ] ( main:10 [ ] { } ) always clobbers reg byte a
+Statement [62] if(memset::dst#2!=memset::end#0) goto memset::@2 [ memset::dst#2 ] ( memset:29 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a
+Statement [64] *memset::dst#2 = memset::c#0 [ memset::dst#2 ] ( memset:29 [ sin_idx memset::dst#2 ] { } ) always clobbers reg byte a reg byte y
+Potential registers zp[1]:40 [ irq_line::l#2 irq_line::l#1 ] : zp[1]:40 , reg byte x , reg byte y ,
+Potential registers zp[1]:39 [ irq_line::b#2 irq_line::b#1 ] : zp[1]:39 , reg byte x , reg byte y ,
+Potential registers zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ] : zp[1]:43 , reg byte x , reg byte y ,
+Potential registers zp[1]:34 [ irq_line::i2#2 irq_line::i2#1 ] : zp[1]:34 , reg byte x , reg byte y ,
+Potential registers zp[1]:35 [ irq_line::i#2 irq_line::i#1 ] : zp[1]:35 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[1]:36 [ irq_line::i1#2 irq_line::i1#1 ] : zp[1]:36 , reg byte a , reg byte x , reg byte y ,
+Potential registers zp[2]:37 [ memset::dst#2 memset::dst#1 ] : zp[2]:37 ,
+Potential registers zp[1]:0 [ BRAM ] : zp[1]:0 ,
+Potential registers zp[1]:1 [ BROM ] : zp[1]:1 ,
+Potential registers zp[1]:45 [ hstart ] : zp[1]:45 ,
+Potential registers zp[1]:46 [ hstop ] : zp[1]:46 ,
+Potential registers zp[1]:47 [ vstart ] : zp[1]:47 ,
+Potential registers zp[1]:48 [ vstop ] : zp[1]:48 ,
+Potential registers zp[1]:44 [ cnt ] : zp[1]:44 ,
+Potential registers zp[1]:49 [ sin_idx ] : zp[1]:49 ,
+Potential registers zp[2]:41 [ irq_line::bar#0 ] : zp[2]:41 ,
REGISTER UPLIFT SCOPES
-Uplift Scope [irq_line] 370.33: zp[1]:2 [ irq_line::i2#2 irq_line::i2#1 ] 353.5: zp[1]:3 [ irq_line::i#2 irq_line::i#1 ] 353.5: zp[1]:4 [ irq_line::i1#2 irq_line::i1#1 ] 26.12: zp[1]:7 [ irq_line::b#2 irq_line::b#1 ] 26: zp[1]:8 [ irq_line::l#2 irq_line::l#1 ] 22.4: zp[2]:9 [ irq_line::bar#0 ] 18: zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Uplift Scope [memset] 336.67: zp[2]:5 [ memset::dst#2 memset::dst#1 ]
-Uplift Scope [] 0.53: zp[1]:12 [ cnt ] 0.45: zp[1]:13 [ hstart ] 0.35: zp[1]:14 [ hstop ] 0.33: zp[1]:15 [ vstart ] 0.32: zp[1]:16 [ vstop ] 0.28: zp[1]:17 [ sin_idx ]
-Uplift Scope [VERA_SPRITE]
+Uplift Scope [irq_line] 370.33: zp[1]:34 [ irq_line::i2#2 irq_line::i2#1 ] 353.5: zp[1]:35 [ irq_line::i#2 irq_line::i#1 ] 353.5: zp[1]:36 [ irq_line::i1#2 irq_line::i1#1 ] 26.12: zp[1]:39 [ irq_line::b#2 irq_line::b#1 ] 26: zp[1]:40 [ irq_line::l#2 irq_line::l#1 ] 22.4: zp[2]:41 [ irq_line::bar#0 ] 18: zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Uplift Scope [memset] 336.67: zp[2]:37 [ memset::dst#2 memset::dst#1 ]
+Uplift Scope [] 20: zp[1]:0 [ BRAM ] 20: zp[1]:1 [ BROM ] 0.53: zp[1]:44 [ cnt ] 0.45: zp[1]:45 [ hstart ] 0.35: zp[1]:46 [ hstop ] 0.33: zp[1]:47 [ vstart ] 0.32: zp[1]:48 [ vstop ] 0.28: zp[1]:49 [ sin_idx ]
Uplift Scope [MOS6522_VIA]
+Uplift Scope [RADIX]
+Uplift Scope [VERA_SPRITE]
Uplift Scope [main]
Uplift Scope [__start]
-Uplifting [irq_line] best 8201 combination reg byte y [ irq_line::i2#2 irq_line::i2#1 ] reg byte a [ irq_line::i#2 irq_line::i#1 ] reg byte a [ irq_line::i1#2 irq_line::i1#1 ] reg byte x [ irq_line::b#2 irq_line::b#1 ] zp[1]:8 [ irq_line::l#2 irq_line::l#1 ] zp[2]:9 [ irq_line::bar#0 ] zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Uplifting [irq_line] best 8211 combination reg byte y [ irq_line::i2#2 irq_line::i2#1 ] reg byte a [ irq_line::i#2 irq_line::i#1 ] reg byte a [ irq_line::i1#2 irq_line::i1#1 ] reg byte x [ irq_line::b#2 irq_line::b#1 ] zp[1]:40 [ irq_line::l#2 irq_line::l#1 ] zp[2]:41 [ irq_line::bar#0 ] zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
Limited combination testing to 100 combinations of 1296 possible.
-Uplifting [memset] best 8201 combination zp[2]:5 [ memset::dst#2 memset::dst#1 ]
-Uplifting [] best 8201 combination zp[1]:12 [ cnt ] zp[1]:13 [ hstart ] zp[1]:14 [ hstop ] zp[1]:15 [ vstart ] zp[1]:16 [ vstop ] zp[1]:17 [ sin_idx ]
-Uplifting [VERA_SPRITE] best 8201 combination
-Uplifting [MOS6522_VIA] best 8201 combination
-Uplifting [main] best 8201 combination
-Uplifting [__start] best 8201 combination
-Attempting to uplift remaining variables inzp[1]:8 [ irq_line::l#2 irq_line::l#1 ]
-Uplifting [irq_line] best 8081 combination reg byte x [ irq_line::l#2 irq_line::l#1 ]
-Attempting to uplift remaining variables inzp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Uplifting [irq_line] best 8081 combination zp[1]:11 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Attempting to uplift remaining variables inzp[1]:12 [ cnt ]
-Uplifting [] best 8081 combination zp[1]:12 [ cnt ]
-Attempting to uplift remaining variables inzp[1]:13 [ hstart ]
-Uplifting [] best 8081 combination zp[1]:13 [ hstart ]
-Attempting to uplift remaining variables inzp[1]:14 [ hstop ]
-Uplifting [] best 8081 combination zp[1]:14 [ hstop ]
-Attempting to uplift remaining variables inzp[1]:15 [ vstart ]
-Uplifting [] best 8081 combination zp[1]:15 [ vstart ]
-Attempting to uplift remaining variables inzp[1]:16 [ vstop ]
-Uplifting [] best 8081 combination zp[1]:16 [ vstop ]
-Attempting to uplift remaining variables inzp[1]:17 [ sin_idx ]
-Uplifting [] best 8081 combination zp[1]:17 [ sin_idx ]
-Coalescing zero page register [ zp[2]:9 [ irq_line::bar#0 ] ] with [ zp[2]:5 [ memset::dst#2 memset::dst#1 ] ]
-Allocated (was zp[2]:9) zp[2]:2 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
-Allocated (was zp[1]:11) zp[1]:4 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
-Allocated (was zp[1]:12) zp[1]:5 [ cnt ]
-Allocated (was zp[1]:13) zp[1]:6 [ hstart ]
-Allocated (was zp[1]:14) zp[1]:7 [ hstop ]
-Allocated (was zp[1]:15) zp[1]:8 [ vstart ]
-Allocated (was zp[1]:16) zp[1]:9 [ vstop ]
-Allocated (was zp[1]:17) zp[1]:10 [ sin_idx ]
+Uplifting [memset] best 8211 combination zp[2]:37 [ memset::dst#2 memset::dst#1 ]
+Uplifting [] best 8211 combination zp[1]:0 [ BRAM ] zp[1]:1 [ BROM ] zp[1]:44 [ cnt ] zp[1]:45 [ hstart ] zp[1]:46 [ hstop ] zp[1]:47 [ vstart ] zp[1]:48 [ vstop ] zp[1]:49 [ sin_idx ]
+Uplifting [MOS6522_VIA] best 8211 combination
+Uplifting [RADIX] best 8211 combination
+Uplifting [VERA_SPRITE] best 8211 combination
+Uplifting [main] best 8211 combination
+Uplifting [__start] best 8211 combination
+Attempting to uplift remaining variables inzp[1]:40 [ irq_line::l#2 irq_line::l#1 ]
+Uplifting [irq_line] best 8091 combination reg byte x [ irq_line::l#2 irq_line::l#1 ]
+Attempting to uplift remaining variables inzp[1]:0 [ BRAM ]
+Uplifting [] best 8091 combination zp[1]:0 [ BRAM ]
+Attempting to uplift remaining variables inzp[1]:1 [ BROM ]
+Uplifting [] best 8091 combination zp[1]:1 [ BROM ]
+Attempting to uplift remaining variables inzp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Uplifting [irq_line] best 8091 combination zp[1]:43 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Attempting to uplift remaining variables inzp[1]:44 [ cnt ]
+Uplifting [] best 8091 combination zp[1]:44 [ cnt ]
+Attempting to uplift remaining variables inzp[1]:45 [ hstart ]
+Uplifting [] best 8091 combination zp[1]:45 [ hstart ]
+Attempting to uplift remaining variables inzp[1]:46 [ hstop ]
+Uplifting [] best 8091 combination zp[1]:46 [ hstop ]
+Attempting to uplift remaining variables inzp[1]:47 [ vstart ]
+Uplifting [] best 8091 combination zp[1]:47 [ vstart ]
+Attempting to uplift remaining variables inzp[1]:48 [ vstop ]
+Uplifting [] best 8091 combination zp[1]:48 [ vstop ]
+Attempting to uplift remaining variables inzp[1]:49 [ sin_idx ]
+Uplifting [] best 8091 combination zp[1]:49 [ sin_idx ]
+Coalescing zero page register [ zp[2]:41 [ irq_line::bar#0 ] ] with [ zp[2]:37 [ memset::dst#2 memset::dst#1 ] ]
+Allocated (was zp[2]:41) zp[2]:34 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
+Allocated (was zp[1]:43) zp[1]:36 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+Allocated (was zp[1]:44) zp[1]:37 [ cnt ]
+Allocated (was zp[1]:45) zp[1]:38 [ hstart ]
+Allocated (was zp[1]:46) zp[1]:39 [ hstop ]
+Allocated (was zp[1]:47) zp[1]:40 [ vstart ]
+Allocated (was zp[1]:48) zp[1]:41 [ vstop ]
+Allocated (was zp[1]:49) zp[1]:42 [ sin_idx ]
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
@@ -906,7 +1027,7 @@ ASSEMBLER BEFORE OPTIMIZATION
// Displays raster bars in the border
// Upstart
.cpu _65c02
- // Commodore 64 PRG executable file
+ // Commander X16 PRG executable file
.file [name="cx16-rasterbars.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
@@ -914,10 +1035,14 @@ ASSEMBLER BEFORE OPTIMIZATION
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(__start)
+
// Global Constants & labels
.const VERA_DCSEL = 2
.const VERA_LINE = 2
+ .const isr_vsync = $314
.const SIZEOF_CHAR = 1
+ /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
+ .label KERNEL_IRQ = $314
/// $9F25 CTRL Control
/// Bit 7: Reset
/// Bit 1: DCSEL
@@ -954,173 +1079,179 @@ ASSEMBLER BEFORE OPTIMIZATION
.label VERA_DC_VSTART = $9f2b
/// $9F2C DC_VSTOP (DCSEL=1) Active Display V-Stop (8:1)
.label VERA_DC_VSTOP = $9f2c
- /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
- .label KERNEL_IRQ = $314
+ .label BRAM = 0
+ .label BROM = 1
// The horizontal start
- .label hstart = 6
+ .label hstart = $26
// The horizontal stop
- .label hstop = 7
+ .label hstop = $27
// The vertical start
- .label vstart = 8
+ .label vstart = $28
// The vertical stop
- .label vstop = 9
+ .label vstop = $29
// The countdown
- .label cnt = 5
+ .label cnt = $25
// The sin idx
- .label sin_idx = $a
+ .label sin_idx = $2a
.segment Code
// __start
__start: {
jmp __init1
// __start::__init1
__init1:
- // [1] hstart = 0 -- vbuz1=vbuc1
+ // [1] BRAM = 0 -- vbuz1=vbuc1
+ lda #0
+ sta.z BRAM
+ // [2] BROM = 4 -- vbuz1=vbuc1
+ lda #4
+ sta.z BROM
+ // [3] hstart = 0 -- vbuz1=vbuc1
lda #0
sta.z hstart
- // [2] hstop = (char)$280/4 -- vbuz1=vbuc1
+ // [4] hstop = (char)$280/4 -- vbuz1=vbuc1
lda #$280/4
sta.z hstop
- // [3] vstart = 0 -- vbuz1=vbuc1
+ // [5] vstart = 0 -- vbuz1=vbuc1
lda #0
sta.z vstart
- // [4] vstop = (char)$1e0/2 -- vbuz1=vbuc1
+ // [6] vstop = (char)$1e0/2 -- vbuz1=vbuc1
lda #$1e0/2
sta.z vstop
- // [5] cnt = 2 -- vbuz1=vbuc1
+ // [7] cnt = 2 -- vbuz1=vbuc1
lda #2
sta.z cnt
- // [6] sin_idx = $64 -- vbuz1=vbuc1
+ // [8] sin_idx = $64 -- vbuz1=vbuc1
lda #$64
sta.z sin_idx
- // [7] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
+ // [9] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
__b1_from___init1:
jmp __b1
// __start::@1
__b1:
- // [8] call main
- // [51] phi from __start::@1 to main [phi:__start::@1->main]
+ // [10] call main
+ // [53] phi from __start::@1 to main [phi:__start::@1->main]
main_from___b1:
jsr main
jmp __breturn
// __start::@return
__breturn:
- // [9] return
+ // [11] return
rts
}
// irq_line
// LINE Interrupt Routine
irq_line: {
- .label idx = 4
- .label bar = 2
+ .label idx = $24
+ .label bar = $22
// interrupt(isr_rom_min_cx16_entry) -- isr_rom_min_cx16_entry
- // [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2
+ // [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2
// Update the border
lda #VERA_DCSEL
ora VERA_CTRL
sta VERA_CTRL
- // [11] *VERA_DC_HSTART = hstart -- _deref_pbuc1=vbuz1
+ // [13] *VERA_DC_HSTART = hstart -- _deref_pbuc1=vbuz1
lda.z hstart
sta VERA_DC_HSTART
- // [12] *VERA_DC_HSTOP = hstop -- _deref_pbuc1=vbuz1
+ // [14] *VERA_DC_HSTOP = hstop -- _deref_pbuc1=vbuz1
lda.z hstop
sta VERA_DC_HSTOP
- // [13] *VERA_DC_VSTART = vstart -- _deref_pbuc1=vbuz1
+ // [15] *VERA_DC_VSTART = vstart -- _deref_pbuc1=vbuz1
lda.z vstart
sta VERA_DC_VSTART
- // [14] *VERA_DC_VSTOP = vstop -- _deref_pbuc1=vbuz1
+ // [16] *VERA_DC_VSTOP = vstop -- _deref_pbuc1=vbuz1
lda.z vstop
sta VERA_DC_VSTOP
- // [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
+ // [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
// Show color raster bars in the border
lda #VERA_DCSEL^$ff
and VERA_CTRL
sta VERA_CTRL
- // [16] phi from irq_line to irq_line::@2 [phi:irq_line->irq_line::@2]
+ // [18] phi from irq_line to irq_line::@2 [phi:irq_line->irq_line::@2]
__b2_from_irq_line:
- // [16] phi irq_line::l#2 = 0 [phi:irq_line->irq_line::@2#0] -- vbuxx=vbuc1
+ // [18] phi irq_line::l#2 = 0 [phi:irq_line->irq_line::@2#0] -- vbuxx=vbuc1
ldx #0
jmp __b2
// irq_line::@2
__b2:
- // [17] if(irq_line::l#2!=$e6) goto irq_line::@3 -- vbuxx_neq_vbuc1_then_la1
+ // [19] if(irq_line::l#2!=$e6) goto irq_line::@3 -- vbuxx_neq_vbuc1_then_la1
cpx #$e6
bne __b3
jmp __b4
// irq_line::@4
__b4:
- // [18] cnt = -- cnt -- vbuz1=_dec_vbuz1
+ // [20] cnt = -- cnt -- vbuz1=_dec_vbuz1
dec.z cnt
- // [19] if(cnt!=0) goto irq_line::@1 -- vbuz1_neq_0_then_la1
+ // [21] if(cnt!=0) goto irq_line::@1 -- vbuz1_neq_0_then_la1
lda.z cnt
bne __b1_from___b4
jmp __b11
// irq_line::@11
__b11:
- // [20] cnt = 2 -- vbuz1=vbuc1
+ // [22] cnt = 2 -- vbuz1=vbuc1
lda #2
sta.z cnt
- // [21] if(hstart>=(char)$140/4+1) goto irq_line::@1 -- vbuz1_ge_vbuc1_then_la1
+ // [23] if(hstart>=(char)$140/4+1) goto irq_line::@1 -- vbuz1_ge_vbuc1_then_la1
lda.z hstart
cmp #$140/4+1
bcs __b1_from___b11
jmp __b12
// irq_line::@12
__b12:
- // [22] hstart = ++ hstart -- vbuz1=_inc_vbuz1
+ // [24] hstart = ++ hstart -- vbuz1=_inc_vbuz1
inc.z hstart
- // [23] hstop = -- hstop -- vbuz1=_dec_vbuz1
+ // [25] hstop = -- hstop -- vbuz1=_dec_vbuz1
dec.z hstop
- // [24] vstart = ++ vstart -- vbuz1=_inc_vbuz1
+ // [26] vstart = ++ vstart -- vbuz1=_inc_vbuz1
inc.z vstart
- // [25] vstop = -- vstop -- vbuz1=_dec_vbuz1
+ // [27] vstop = -- vstop -- vbuz1=_dec_vbuz1
dec.z vstop
- // [26] phi from irq_line::@11 irq_line::@12 irq_line::@4 to irq_line::@1 [phi:irq_line::@11/irq_line::@12/irq_line::@4->irq_line::@1]
+ // [28] phi from irq_line::@11 irq_line::@12 irq_line::@4 to irq_line::@1 [phi:irq_line::@11/irq_line::@12/irq_line::@4->irq_line::@1]
__b1_from___b11:
__b1_from___b12:
__b1_from___b4:
jmp __b1
// irq_line::@1
__b1:
- // [27] call memset
+ // [29] call memset
// Animate the bars
- // [58] phi from irq_line::@1 to memset [phi:irq_line::@1->memset]
+ // [60] phi from irq_line::@1 to memset [phi:irq_line::@1->memset]
memset_from___b1:
jsr memset
jmp __b19
// irq_line::@19
__b19:
- // [28] irq_line::idx#0 = sin_idx -- vbuz1=vbuz2
+ // [30] irq_line::idx#0 = sin_idx -- vbuz1=vbuz2
lda.z sin_idx
sta.z idx
- // [29] sin_idx = -- sin_idx -- vbuz1=_dec_vbuz1
+ // [31] sin_idx = -- sin_idx -- vbuz1=_dec_vbuz1
dec.z sin_idx
- // [30] phi from irq_line::@19 to irq_line::@13 [phi:irq_line::@19->irq_line::@13]
+ // [32] phi from irq_line::@19 to irq_line::@13 [phi:irq_line::@19->irq_line::@13]
__b13_from___b19:
- // [30] phi irq_line::idx#2 = irq_line::idx#0 [phi:irq_line::@19->irq_line::@13#0] -- register_copy
- // [30] phi irq_line::b#2 = 0 [phi:irq_line::@19->irq_line::@13#1] -- vbuxx=vbuc1
+ // [32] phi irq_line::idx#2 = irq_line::idx#0 [phi:irq_line::@19->irq_line::@13#0] -- register_copy
+ // [32] phi irq_line::b#2 = 0 [phi:irq_line::@19->irq_line::@13#1] -- vbuxx=vbuc1
ldx #0
jmp __b13
// irq_line::@13
__b13:
- // [31] if(irq_line::b#2<8) goto irq_line::@14 -- vbuxx_lt_vbuc1_then_la1
+ // [33] if(irq_line::b#2<8) goto irq_line::@14 -- vbuxx_lt_vbuc1_then_la1
cpx #8
bcc __b14
jmp __b15
// irq_line::@15
__b15:
- // [32] *VERA_ISR = VERA_LINE -- _deref_pbuc1=vbuc2
+ // [34] *VERA_ISR = VERA_LINE -- _deref_pbuc1=vbuc2
// Reset the LINE interrupt
lda #VERA_LINE
sta VERA_ISR
jmp __breturn
// irq_line::@return
__breturn:
- // [33] return
+ // [35] return
// interrupt(isr_rom_min_cx16_exit) -- isr_rom_min_cx16_exit
jmp $e049
// irq_line::@14
__b14:
- // [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] -- pbuz1=pbuc1_plus_pbuc2_derefidx_vbuz2
+ // [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] -- pbuz1=pbuc1_plus_pbuc2_derefidx_vbuz2
ldy.z idx
lda SIN,y
clc
@@ -1129,72 +1260,72 @@ irq_line: {
lda #>BARS
adc #0
sta.z bar+1
- // [35] phi from irq_line::@14 to irq_line::@16 [phi:irq_line::@14->irq_line::@16]
+ // [37] phi from irq_line::@14 to irq_line::@16 [phi:irq_line::@14->irq_line::@16]
__b16_from___b14:
- // [35] phi irq_line::i2#2 = 0 [phi:irq_line::@14->irq_line::@16#0] -- vbuyy=vbuc1
+ // [37] phi irq_line::i2#2 = 0 [phi:irq_line::@14->irq_line::@16#0] -- vbuyy=vbuc1
ldy #0
jmp __b16
// irq_line::@16
__b16:
- // [36] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17 -- vbuyy_lt_vbuc1_then_la1
+ // [38] if(irq_line::i2#2<$20*SIZEOF_CHAR) goto irq_line::@17 -- vbuyy_lt_vbuc1_then_la1
cpy #$20*SIZEOF_CHAR
bcc __b17
jmp __b18
// irq_line::@18
__b18:
- // [37] irq_line::idx#1 = irq_line::idx#2 + $d -- vbuz1=vbuz1_plus_vbuc1
+ // [39] irq_line::idx#1 = irq_line::idx#2 + $d -- vbuz1=vbuz1_plus_vbuc1
lda #$d
clc
adc.z idx
sta.z idx
- // [38] irq_line::b#1 = ++ irq_line::b#2 -- vbuxx=_inc_vbuxx
+ // [40] irq_line::b#1 = ++ irq_line::b#2 -- vbuxx=_inc_vbuxx
inx
- // [30] phi from irq_line::@18 to irq_line::@13 [phi:irq_line::@18->irq_line::@13]
+ // [32] phi from irq_line::@18 to irq_line::@13 [phi:irq_line::@18->irq_line::@13]
__b13_from___b18:
- // [30] phi irq_line::idx#2 = irq_line::idx#1 [phi:irq_line::@18->irq_line::@13#0] -- register_copy
- // [30] phi irq_line::b#2 = irq_line::b#1 [phi:irq_line::@18->irq_line::@13#1] -- register_copy
+ // [32] phi irq_line::idx#2 = irq_line::idx#1 [phi:irq_line::@18->irq_line::@13#0] -- register_copy
+ // [32] phi irq_line::b#2 = irq_line::b#1 [phi:irq_line::@18->irq_line::@13#1] -- register_copy
jmp __b13
// irq_line::@17
__b17:
- // [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] -- pbuz1_derefidx_vbuyy=pbuc1_derefidx_vbuyy
+ // [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] -- pbuz1_derefidx_vbuyy=pbuc1_derefidx_vbuyy
lda BAR,y
sta (bar),y
- // [40] irq_line::i2#1 = ++ irq_line::i2#2 -- vbuyy=_inc_vbuyy
+ // [42] irq_line::i2#1 = ++ irq_line::i2#2 -- vbuyy=_inc_vbuyy
iny
- // [35] phi from irq_line::@17 to irq_line::@16 [phi:irq_line::@17->irq_line::@16]
+ // [37] phi from irq_line::@17 to irq_line::@16 [phi:irq_line::@17->irq_line::@16]
__b16_from___b17:
- // [35] phi irq_line::i2#2 = irq_line::i2#1 [phi:irq_line::@17->irq_line::@16#0] -- register_copy
+ // [37] phi irq_line::i2#2 = irq_line::i2#1 [phi:irq_line::@17->irq_line::@16#0] -- register_copy
jmp __b16
// irq_line::@3
__b3:
- // [41] *VERA_DC_BORDER = BARS[irq_line::l#2] -- _deref_pbuc1=pbuc2_derefidx_vbuxx
+ // [43] *VERA_DC_BORDER = BARS[irq_line::l#2] -- _deref_pbuc1=pbuc2_derefidx_vbuxx
lda BARS,x
sta VERA_DC_BORDER
- // [42] phi from irq_line::@3 to irq_line::@5 [phi:irq_line::@3->irq_line::@5]
+ // [44] phi from irq_line::@3 to irq_line::@5 [phi:irq_line::@3->irq_line::@5]
__b5_from___b3:
- // [42] phi irq_line::i#2 = 0 [phi:irq_line::@3->irq_line::@5#0] -- vbuaa=vbuc1
+ // [44] phi irq_line::i#2 = 0 [phi:irq_line::@3->irq_line::@5#0] -- vbuaa=vbuc1
lda #0
jmp __b5
// irq_line::@5
__b5:
- // [43] if(irq_line::i#2<$18) goto irq_line::@6 -- vbuaa_lt_vbuc1_then_la1
+ // [45] if(irq_line::i#2<$18) goto irq_line::@6 -- vbuaa_lt_vbuc1_then_la1
cmp #$18
bcc __b6
jmp __b7
// irq_line::@7
__b7:
- // [44] *VERA_DC_BORDER = 0 -- _deref_pbuc1=vbuc2
+ // [46] *VERA_DC_BORDER = 0 -- _deref_pbuc1=vbuc2
// Wait exactly long enough to go to the next raster line
lda #0
sta VERA_DC_BORDER
- // [45] phi from irq_line::@7 to irq_line::@8 [phi:irq_line::@7->irq_line::@8]
+ // [47] phi from irq_line::@7 to irq_line::@8 [phi:irq_line::@7->irq_line::@8]
__b8_from___b7:
- // [45] phi irq_line::i1#2 = 0 [phi:irq_line::@7->irq_line::@8#0] -- vbuaa=vbuc1
+ // [47] phi irq_line::i1#2 = 0 [phi:irq_line::@7->irq_line::@8#0] -- vbuaa=vbuc1
lda #0
jmp __b8
// irq_line::@8
__b8:
- // [46] if(irq_line::i1#2<$17) goto irq_line::@9 -- vbuaa_lt_vbuc1_then_la1
+ // [48] if(irq_line::i1#2<$17) goto irq_line::@9 -- vbuaa_lt_vbuc1_then_la1
cmp #$17
bcc __b9
jmp __b10
@@ -1204,27 +1335,27 @@ irq_line: {
// Wait exactly long enough to go to the next raster line
nop
nop
- // [48] irq_line::l#1 = ++ irq_line::l#2 -- vbuxx=_inc_vbuxx
+ // [50] irq_line::l#1 = ++ irq_line::l#2 -- vbuxx=_inc_vbuxx
inx
- // [16] phi from irq_line::@10 to irq_line::@2 [phi:irq_line::@10->irq_line::@2]
+ // [18] phi from irq_line::@10 to irq_line::@2 [phi:irq_line::@10->irq_line::@2]
__b2_from___b10:
- // [16] phi irq_line::l#2 = irq_line::l#1 [phi:irq_line::@10->irq_line::@2#0] -- register_copy
+ // [18] phi irq_line::l#2 = irq_line::l#1 [phi:irq_line::@10->irq_line::@2#0] -- register_copy
jmp __b2
// irq_line::@9
__b9:
- // [49] irq_line::i1#1 = ++ irq_line::i1#2 -- vbuaa=_inc_vbuaa
+ // [51] irq_line::i1#1 = ++ irq_line::i1#2 -- vbuaa=_inc_vbuaa
inc
- // [45] phi from irq_line::@9 to irq_line::@8 [phi:irq_line::@9->irq_line::@8]
+ // [47] phi from irq_line::@9 to irq_line::@8 [phi:irq_line::@9->irq_line::@8]
__b8_from___b9:
- // [45] phi irq_line::i1#2 = irq_line::i1#1 [phi:irq_line::@9->irq_line::@8#0] -- register_copy
+ // [47] phi irq_line::i1#2 = irq_line::i1#1 [phi:irq_line::@9->irq_line::@8#0] -- register_copy
jmp __b8
// irq_line::@6
__b6:
- // [50] irq_line::i#1 = ++ irq_line::i#2 -- vbuaa=_inc_vbuaa
+ // [52] irq_line::i#1 = ++ irq_line::i#2 -- vbuaa=_inc_vbuaa
inc
- // [42] phi from irq_line::@6 to irq_line::@5 [phi:irq_line::@6->irq_line::@5]
+ // [44] phi from irq_line::@6 to irq_line::@5 [phi:irq_line::@6->irq_line::@5]
__b5_from___b6:
- // [42] phi irq_line::i#2 = irq_line::i#1 [phi:irq_line::@6->irq_line::@5#0] -- register_copy
+ // [44] phi irq_line::i#2 = irq_line::i#1 [phi:irq_line::@6->irq_line::@5#0] -- register_copy
jmp __b5
}
// main
@@ -1237,15 +1368,15 @@ main: {
jmp __b2
// main::@2
__b2:
- // [53] *KERNEL_IRQ = &irq_line -- _deref_qprc1=pprc2
+ // [55] *KERNEL_IRQ = &irq_line -- _deref_qprc1=pprc2
lda #irq_line
sta KERNEL_IRQ+1
- // [54] *VERA_IEN = VERA_LINE -- _deref_pbuc1=vbuc2
+ // [56] *VERA_IEN = VERA_LINE -- _deref_pbuc1=vbuc2
lda #VERA_LINE
sta VERA_IEN
- // [55] *VERA_IRQLINE_L = 5 -- _deref_pbuc1=vbuc2
+ // [57] *VERA_IRQLINE_L = 5 -- _deref_pbuc1=vbuc2
lda #5
sta VERA_IRQLINE_L
jmp CLI1
@@ -1253,7 +1384,7 @@ main: {
CLI1:
// asm { cli }
cli
- // [57] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1]
+ // [59] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1]
__b1_from___b1:
__b1_from_CLI1:
jmp __b1
@@ -1269,10 +1400,10 @@ memset: {
.const c = 0
.label str = BARS
.label end = str+num
- .label dst = 2
- // [59] phi from memset to memset::@1 [phi:memset->memset::@1]
+ .label dst = $22
+ // [61] phi from memset to memset::@1 [phi:memset->memset::@1]
__b1_from_memset:
- // [59] phi memset::dst#2 = (char *)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
+ // [61] phi memset::dst#2 = (char *)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
lda #str
@@ -1280,7 +1411,7 @@ memset: {
jmp __b1
// memset::@1
__b1:
- // [60] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
+ // [62] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
lda.z dst+1
cmp #>end
bne __b2
@@ -1290,22 +1421,22 @@ memset: {
jmp __breturn
// memset::@return
__breturn:
- // [61] return
+ // [63] return
rts
// memset::@2
__b2:
- // [62] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuc1
+ // [64] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuc1
lda #c
ldy #0
sta (dst),y
- // [63] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
+ // [65] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
inc.z dst
bne !+
inc.z dst+1
!:
- // [59] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
+ // [61] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
__b1_from___b2:
- // [59] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
+ // [61] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
jmp __b1
}
// File Data
@@ -1392,7 +1523,13 @@ Succesful ASM optimization Pass5UnnecesaryLoadElimination
FINAL SYMBOL TABLE
__constant char BAR[$20] = { $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f, $1f, $1e, $1d, $1c, $1b, $1a, $19, $18, $17, $16, $15, $14, $13, $12, $11, $10 }
__constant char BARS[$e6] = { fill( $e6, 0) }
+__loadstore volatile char BRAM // !zp[-1]:0 zp[1]:0 20.0
+__loadstore volatile char BROM // !zp[-1]:1 zp[1]:1 20.0
__constant void (** const KERNEL_IRQ)() = (void (**)()) 788
+__constant char RADIX::BINARY = 2
+__constant char RADIX::DECIMAL = $a
+__constant char RADIX::HEXADECIMAL = $10
+__constant char RADIX::OCTAL = 8
__constant char SIN[$100] = kickasm {{ .fill 256, 99+99*sin(i*2*PI/256)
}}
__constant char SIZEOF_CHAR = 1
@@ -1408,15 +1545,15 @@ __constant char * const VERA_IRQLINE_L = (char *) 40744
__constant char * const VERA_ISR = (char *) 40743
__constant const char VERA_LINE = 2
void __start()
-__loadstore volatile char cnt // zp[1]:5 0.5263157894736842
-__loadstore volatile char hstart // zp[1]:6 0.4545454545454546
-__loadstore volatile char hstop // zp[1]:7 0.34782608695652173
+__loadstore volatile char cnt // zp[1]:37 0.5263157894736842
+__loadstore volatile char hstart // zp[1]:38 0.4545454545454546
+__loadstore volatile char hstop // zp[1]:39 0.34782608695652173
__interrupt(rom_min_cx16) void irq_line()
char irq_line::b
char irq_line::b#1 // reg byte x 22.0
char irq_line::b#2 // reg byte x 4.125
char *irq_line::bar
-char *irq_line::bar#0 // bar zp[2]:2 22.4
+char *irq_line::bar#0 // bar zp[2]:34 22.4
char irq_line::i
char irq_line::i#1 // reg byte a 202.0
char irq_line::i#2 // reg byte a 151.5
@@ -1427,19 +1564,21 @@ char irq_line::i2
char irq_line::i2#1 // reg byte y 202.0
char irq_line::i2#2 // reg byte y 168.33333333333331
char irq_line::idx
-char irq_line::idx#0 // idx zp[1]:4 2.0
-char irq_line::idx#1 // idx zp[1]:4 11.0
-char irq_line::idx#2 // idx zp[1]:4 5.0
+char irq_line::idx#0 // idx zp[1]:36 2.0
+char irq_line::idx#1 // idx zp[1]:36 11.0
+char irq_line::idx#2 // idx zp[1]:36 5.0
char irq_line::l
char irq_line::l#1 // reg byte x 22.0
char irq_line::l#2 // reg byte x 4.0
+unsigned int isr_vsync
+__constant unsigned int isr_vsync#2 = $314 // isr_vsync
void main()
void * memset(void *str , char c , unsigned int num)
char memset::c
__constant char memset::c#0 = 0 // c
char *memset::dst
-char *memset::dst#1 // dst zp[2]:2 202.0
-char *memset::dst#2 // dst zp[2]:2 134.66666666666666
+char *memset::dst#1 // dst zp[2]:34 202.0
+char *memset::dst#2 // dst zp[2]:34 134.66666666666666
char *memset::end
__constant char *memset::end#0 = (char *)memset::str#0+memset::num#0 // end
unsigned int memset::num
@@ -1447,34 +1586,36 @@ __constant unsigned int memset::num#0 = $e6*SIZEOF_CHAR // num
void *memset::return
void *memset::str
__constant void *memset::str#0 = (void *)BARS // str
-__loadstore volatile char sin_idx // zp[1]:10 0.27586206896551724
-__loadstore volatile char vstart // zp[1]:8 0.3333333333333333
-__loadstore volatile char vstop // zp[1]:9 0.32
+__loadstore volatile char sin_idx // zp[1]:42 0.27586206896551724
+__loadstore volatile char vstart // zp[1]:40 0.3333333333333333
+__loadstore volatile char vstop // zp[1]:41 0.32
reg byte x [ irq_line::l#2 irq_line::l#1 ]
reg byte x [ irq_line::b#2 irq_line::b#1 ]
-zp[1]:4 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+zp[1]:36 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
reg byte y [ irq_line::i2#2 irq_line::i2#1 ]
reg byte a [ irq_line::i#2 irq_line::i#1 ]
reg byte a [ irq_line::i1#2 irq_line::i1#1 ]
-zp[1]:6 [ hstart ]
-zp[1]:7 [ hstop ]
-zp[1]:8 [ vstart ]
-zp[1]:9 [ vstop ]
-zp[1]:5 [ cnt ]
-zp[1]:10 [ sin_idx ]
-zp[2]:2 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
+zp[1]:0 [ BRAM ]
+zp[1]:1 [ BROM ]
+zp[1]:38 [ hstart ]
+zp[1]:39 [ hstop ]
+zp[1]:40 [ vstart ]
+zp[1]:41 [ vstop ]
+zp[1]:37 [ cnt ]
+zp[1]:42 [ sin_idx ]
+zp[2]:34 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
FINAL ASSEMBLER
-Score: 5784
+Score: 5794
// File Comments
// Example program for the Commander X16
// Displays raster bars in the border
// Upstart
.cpu _65c02
- // Commodore 64 PRG executable file
+ // Commander X16 PRG executable file
.file [name="cx16-rasterbars.prg", type="prg", segments="Program"]
.segmentdef Program [segments="Basic, Code, Data"]
.segmentdef Basic [start=$0801]
@@ -1482,10 +1623,14 @@ Score: 5784
.segmentdef Data [startAfter="Code"]
.segment Basic
:BasicUpstart(__start)
+
// Global Constants & labels
.const VERA_DCSEL = 2
.const VERA_LINE = 2
+ .const isr_vsync = $314
.const SIZEOF_CHAR = 1
+ /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
+ .label KERNEL_IRQ = $314
/// $9F25 CTRL Control
/// Bit 7: Reset
/// Bit 1: DCSEL
@@ -1522,170 +1667,178 @@ Score: 5784
.label VERA_DC_VSTART = $9f2b
/// $9F2C DC_VSTOP (DCSEL=1) Active Display V-Stop (8:1)
.label VERA_DC_VSTOP = $9f2c
- /// $0314 (RAM) IRQ vector - The vector used when the KERNAL serves IRQ interrupts
- .label KERNEL_IRQ = $314
+ .label BRAM = 0
+ .label BROM = 1
// The horizontal start
- .label hstart = 6
+ .label hstart = $26
// The horizontal stop
- .label hstop = 7
+ .label hstop = $27
// The vertical start
- .label vstart = 8
+ .label vstart = $28
// The vertical stop
- .label vstop = 9
+ .label vstop = $29
// The countdown
- .label cnt = 5
+ .label cnt = $25
// The sin idx
- .label sin_idx = $a
+ .label sin_idx = $2a
.segment Code
// __start
__start: {
// __start::__init1
+ // __export volatile __address(0x00) unsigned char BRAM = 0
+ // [1] BRAM = 0 -- vbuz1=vbuc1
+ lda #0
+ sta.z BRAM
+ // __export volatile __address(0x01) unsigned char BROM = 4
+ // [2] BROM = 4 -- vbuz1=vbuc1
+ lda #4
+ sta.z BROM
// volatile char hstart = 0/4
- // [1] hstart = 0 -- vbuz1=vbuc1
+ // [3] hstart = 0 -- vbuz1=vbuc1
lda #0
sta.z hstart
// volatile char hstop = 640/4
- // [2] hstop = (char)$280/4 -- vbuz1=vbuc1
+ // [4] hstop = (char)$280/4 -- vbuz1=vbuc1
lda #$280/4
sta.z hstop
// volatile char vstart = 0/2
- // [3] vstart = 0 -- vbuz1=vbuc1
+ // [5] vstart = 0 -- vbuz1=vbuc1
lda #0
sta.z vstart
// volatile char vstop = 480/2
- // [4] vstop = (char)$1e0/2 -- vbuz1=vbuc1
+ // [6] vstop = (char)$1e0/2 -- vbuz1=vbuc1
lda #$1e0/2
sta.z vstop
// volatile char cnt = 2
- // [5] cnt = 2 -- vbuz1=vbuc1
+ // [7] cnt = 2 -- vbuz1=vbuc1
lda #2
sta.z cnt
// volatile char sin_idx = 100
- // [6] sin_idx = $64 -- vbuz1=vbuc1
+ // [8] sin_idx = $64 -- vbuz1=vbuc1
lda #$64
sta.z sin_idx
- // [7] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
+ // [9] phi from __start::__init1 to __start::@1 [phi:__start::__init1->__start::@1]
// __start::@1
- // [8] call main
- // [51] phi from __start::@1 to main [phi:__start::@1->main]
+ // [10] call main
+ // [53] phi from __start::@1 to main [phi:__start::@1->main]
jsr main
// __start::@return
- // [9] return
+ // [11] return
rts
}
// irq_line
// LINE Interrupt Routine
irq_line: {
- .label idx = 4
- .label bar = 2
+ .label idx = $24
+ .label bar = $22
// interrupt(isr_rom_min_cx16_entry) -- isr_rom_min_cx16_entry
// *VERA_CTRL |= VERA_DCSEL
- // [10] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2
+ // [12] *VERA_CTRL = *VERA_CTRL | VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_bor_vbuc2
// Update the border
lda #VERA_DCSEL
ora VERA_CTRL
sta VERA_CTRL
// *VERA_DC_HSTART = hstart
- // [11] *VERA_DC_HSTART = hstart -- _deref_pbuc1=vbuz1
+ // [13] *VERA_DC_HSTART = hstart -- _deref_pbuc1=vbuz1
lda.z hstart
sta VERA_DC_HSTART
// *VERA_DC_HSTOP = hstop
- // [12] *VERA_DC_HSTOP = hstop -- _deref_pbuc1=vbuz1
+ // [14] *VERA_DC_HSTOP = hstop -- _deref_pbuc1=vbuz1
lda.z hstop
sta VERA_DC_HSTOP
// *VERA_DC_VSTART = vstart
- // [13] *VERA_DC_VSTART = vstart -- _deref_pbuc1=vbuz1
+ // [15] *VERA_DC_VSTART = vstart -- _deref_pbuc1=vbuz1
lda.z vstart
sta VERA_DC_VSTART
// *VERA_DC_VSTOP = vstop
- // [14] *VERA_DC_VSTOP = vstop -- _deref_pbuc1=vbuz1
+ // [16] *VERA_DC_VSTOP = vstop -- _deref_pbuc1=vbuz1
lda.z vstop
sta VERA_DC_VSTOP
// *VERA_CTRL &= ~VERA_DCSEL
- // [15] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
+ // [17] *VERA_CTRL = *VERA_CTRL & ~VERA_DCSEL -- _deref_pbuc1=_deref_pbuc1_band_vbuc2
// Show color raster bars in the border
lda #VERA_DCSEL^$ff
and VERA_CTRL
sta VERA_CTRL
- // [16] phi from irq_line to irq_line::@2 [phi:irq_line->irq_line::@2]
- // [16] phi irq_line::l#2 = 0 [phi:irq_line->irq_line::@2#0] -- vbuxx=vbuc1
+ // [18] phi from irq_line to irq_line::@2 [phi:irq_line->irq_line::@2]
+ // [18] phi irq_line::l#2 = 0 [phi:irq_line->irq_line::@2#0] -- vbuxx=vbuc1
ldx #0
// irq_line::@2
__b2:
// for(char l=0;l!=230;l++)
- // [17] if(irq_line::l#2!=$e6) goto irq_line::@3 -- vbuxx_neq_vbuc1_then_la1
+ // [19] if(irq_line::l#2!=$e6) goto irq_line::@3 -- vbuxx_neq_vbuc1_then_la1
cpx #$e6
bne __b3
// irq_line::@4
// if(--cnt==0)
- // [18] cnt = -- cnt -- vbuz1=_dec_vbuz1
+ // [20] cnt = -- cnt -- vbuz1=_dec_vbuz1
dec.z cnt
- // [19] if(cnt!=0) goto irq_line::@1 -- vbuz1_neq_0_then_la1
+ // [21] if(cnt!=0) goto irq_line::@1 -- vbuz1_neq_0_then_la1
lda.z cnt
bne __b1
// irq_line::@11
// cnt = 2
- // [20] cnt = 2 -- vbuz1=vbuc1
+ // [22] cnt = 2 -- vbuz1=vbuc1
lda #2
sta.z cnt
// if(hstart<=320/4)
- // [21] if(hstart>=(char)$140/4+1) goto irq_line::@1 -- vbuz1_ge_vbuc1_then_la1
+ // [23] if(hstart>=(char)$140/4+1) goto irq_line::@1 -- vbuz1_ge_vbuc1_then_la1
lda.z hstart
cmp #$140/4+1
bcs __b1
// irq_line::@12
// hstart++;
- // [22] hstart = ++ hstart -- vbuz1=_inc_vbuz1
+ // [24] hstart = ++ hstart -- vbuz1=_inc_vbuz1
inc.z hstart
// hstop--;
- // [23] hstop = -- hstop -- vbuz1=_dec_vbuz1
+ // [25] hstop = -- hstop -- vbuz1=_dec_vbuz1
dec.z hstop
// vstart++;
- // [24] vstart = ++ vstart -- vbuz1=_inc_vbuz1
+ // [26] vstart = ++ vstart -- vbuz1=_inc_vbuz1
inc.z vstart
// vstop--;
- // [25] vstop = -- vstop -- vbuz1=_dec_vbuz1
+ // [27] vstop = -- vstop -- vbuz1=_dec_vbuz1
dec.z vstop
- // [26] phi from irq_line::@11 irq_line::@12 irq_line::@4 to irq_line::@1 [phi:irq_line::@11/irq_line::@12/irq_line::@4->irq_line::@1]
+ // [28] phi from irq_line::@11 irq_line::@12 irq_line::@4 to irq_line::@1 [phi:irq_line::@11/irq_line::@12/irq_line::@4->irq_line::@1]
// irq_line::@1
__b1:
// memset(BARS, 0, sizeof(BARS))
- // [27] call memset
+ // [29] call memset
// Animate the bars
- // [58] phi from irq_line::@1 to memset [phi:irq_line::@1->memset]
+ // [60] phi from irq_line::@1 to memset [phi:irq_line::@1->memset]
jsr memset
// irq_line::@19
// char idx = sin_idx--
- // [28] irq_line::idx#0 = sin_idx -- vbuz1=vbuz2
+ // [30] irq_line::idx#0 = sin_idx -- vbuz1=vbuz2
lda.z sin_idx
sta.z idx
- // [29] sin_idx = -- sin_idx -- vbuz1=_dec_vbuz1
+ // [31] sin_idx = -- sin_idx -- vbuz1=_dec_vbuz1
dec.z sin_idx
- // [30] phi from irq_line::@19 to irq_line::@13 [phi:irq_line::@19->irq_line::@13]
- // [30] phi irq_line::idx#2 = irq_line::idx#0 [phi:irq_line::@19->irq_line::@13#0] -- register_copy
- // [30] phi irq_line::b#2 = 0 [phi:irq_line::@19->irq_line::@13#1] -- vbuxx=vbuc1
+ // [32] phi from irq_line::@19 to irq_line::@13 [phi:irq_line::@19->irq_line::@13]
+ // [32] phi irq_line::idx#2 = irq_line::idx#0 [phi:irq_line::@19->irq_line::@13#0] -- register_copy
+ // [32] phi irq_line::b#2 = 0 [phi:irq_line::@19->irq_line::@13#1] -- vbuxx=vbuc1
ldx #0
// irq_line::@13
__b13:
// for(char b=0;b<8;b++)
- // [31] if(irq_line::b#2<8) goto irq_line::@14 -- vbuxx_lt_vbuc1_then_la1
+ // [33] if(irq_line::b#2<8) goto irq_line::@14 -- vbuxx_lt_vbuc1_then_la1
cpx #8
bcc __b14
// irq_line::@15
// *VERA_ISR = VERA_LINE
- // [32] *VERA_ISR = VERA_LINE -- _deref_pbuc1=vbuc2
+ // [34] *VERA_ISR = VERA_LINE -- _deref_pbuc1=vbuc2
// Reset the LINE interrupt
lda #VERA_LINE
sta VERA_ISR
// irq_line::@return
// }
- // [33] return
+ // [35] return
// interrupt(isr_rom_min_cx16_exit) -- isr_rom_min_cx16_exit
jmp $e049
// irq_line::@14
__b14:
// char * bar = BARS + SIN[idx]
- // [34] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] -- pbuz1=pbuc1_plus_pbuc2_derefidx_vbuz2
+ // [36] irq_line::bar#0 = BARS + SIN[irq_line::idx#2] -- pbuz1=pbuc1_plus_pbuc2_derefidx_vbuz2
ldy.z idx
lda SIN,y
clc
@@ -1694,68 +1847,68 @@ irq_line: {
lda #>BARS
adc #0
sta.z bar+1
- // [35] phi from irq_line::@14 to irq_line::@16 [phi:irq_line::@14->irq_line::@16]
- // [35] phi irq_line::i2#2 = 0 [phi:irq_line::@14->irq_line::@16#0] -- vbuyy=vbuc1
+ // [37] phi from irq_line::@14 to irq_line::@16 [phi:irq_line::@14->irq_line::@16]
+ // [37] phi irq_line::i2#2 = 0 [phi:irq_line::@14->irq_line::@16#0] -- vbuyy=vbuc1
ldy #0
// irq_line::@16
__b16:
// for(char i=0;iirq_line::@13]
- // [30] phi irq_line::idx#2 = irq_line::idx#1 [phi:irq_line::@18->irq_line::@13#0] -- register_copy
- // [30] phi irq_line::b#2 = irq_line::b#1 [phi:irq_line::@18->irq_line::@13#1] -- register_copy
+ // [32] phi from irq_line::@18 to irq_line::@13 [phi:irq_line::@18->irq_line::@13]
+ // [32] phi irq_line::idx#2 = irq_line::idx#1 [phi:irq_line::@18->irq_line::@13#0] -- register_copy
+ // [32] phi irq_line::b#2 = irq_line::b#1 [phi:irq_line::@18->irq_line::@13#1] -- register_copy
jmp __b13
// irq_line::@17
__b17:
// bar[i] = BAR[i]
- // [39] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] -- pbuz1_derefidx_vbuyy=pbuc1_derefidx_vbuyy
+ // [41] irq_line::bar#0[irq_line::i2#2] = BAR[irq_line::i2#2] -- pbuz1_derefidx_vbuyy=pbuc1_derefidx_vbuyy
lda BAR,y
sta (bar),y
// for(char i=0;iirq_line::@16]
- // [35] phi irq_line::i2#2 = irq_line::i2#1 [phi:irq_line::@17->irq_line::@16#0] -- register_copy
+ // [37] phi from irq_line::@17 to irq_line::@16 [phi:irq_line::@17->irq_line::@16]
+ // [37] phi irq_line::i2#2 = irq_line::i2#1 [phi:irq_line::@17->irq_line::@16#0] -- register_copy
jmp __b16
// irq_line::@3
__b3:
// *VERA_DC_BORDER = BARS[l]
- // [41] *VERA_DC_BORDER = BARS[irq_line::l#2] -- _deref_pbuc1=pbuc2_derefidx_vbuxx
+ // [43] *VERA_DC_BORDER = BARS[irq_line::l#2] -- _deref_pbuc1=pbuc2_derefidx_vbuxx
lda BARS,x
sta VERA_DC_BORDER
- // [42] phi from irq_line::@3 to irq_line::@5 [phi:irq_line::@3->irq_line::@5]
- // [42] phi irq_line::i#2 = 0 [phi:irq_line::@3->irq_line::@5#0] -- vbuaa=vbuc1
+ // [44] phi from irq_line::@3 to irq_line::@5 [phi:irq_line::@3->irq_line::@5]
+ // [44] phi irq_line::i#2 = 0 [phi:irq_line::@3->irq_line::@5#0] -- vbuaa=vbuc1
lda #0
// irq_line::@5
__b5:
// for(char i=0;i<24;i++)
- // [43] if(irq_line::i#2<$18) goto irq_line::@6 -- vbuaa_lt_vbuc1_then_la1
+ // [45] if(irq_line::i#2<$18) goto irq_line::@6 -- vbuaa_lt_vbuc1_then_la1
cmp #$18
bcc __b6
// irq_line::@7
// *VERA_DC_BORDER = 0
- // [44] *VERA_DC_BORDER = 0 -- _deref_pbuc1=vbuc2
+ // [46] *VERA_DC_BORDER = 0 -- _deref_pbuc1=vbuc2
// Wait exactly long enough to go to the next raster line
lda #0
sta VERA_DC_BORDER
- // [45] phi from irq_line::@7 to irq_line::@8 [phi:irq_line::@7->irq_line::@8]
- // [45] phi irq_line::i1#2 = 0 [phi:irq_line::@7->irq_line::@8#0] -- vbuaa=vbuc1
+ // [47] phi from irq_line::@7 to irq_line::@8 [phi:irq_line::@7->irq_line::@8]
+ // [47] phi irq_line::i1#2 = 0 [phi:irq_line::@7->irq_line::@8#0] -- vbuaa=vbuc1
// irq_line::@8
__b8:
// for(char i=0;i<23;i++)
- // [46] if(irq_line::i1#2<$17) goto irq_line::@9 -- vbuaa_lt_vbuc1_then_la1
+ // [48] if(irq_line::i1#2<$17) goto irq_line::@9 -- vbuaa_lt_vbuc1_then_la1
cmp #$17
bcc __b9
// irq_line::@10
@@ -1765,26 +1918,26 @@ irq_line: {
nop
nop
// for(char l=0;l!=230;l++)
- // [48] irq_line::l#1 = ++ irq_line::l#2 -- vbuxx=_inc_vbuxx
+ // [50] irq_line::l#1 = ++ irq_line::l#2 -- vbuxx=_inc_vbuxx
inx
- // [16] phi from irq_line::@10 to irq_line::@2 [phi:irq_line::@10->irq_line::@2]
- // [16] phi irq_line::l#2 = irq_line::l#1 [phi:irq_line::@10->irq_line::@2#0] -- register_copy
+ // [18] phi from irq_line::@10 to irq_line::@2 [phi:irq_line::@10->irq_line::@2]
+ // [18] phi irq_line::l#2 = irq_line::l#1 [phi:irq_line::@10->irq_line::@2#0] -- register_copy
jmp __b2
// irq_line::@9
__b9:
// for(char i=0;i<23;i++)
- // [49] irq_line::i1#1 = ++ irq_line::i1#2 -- vbuaa=_inc_vbuaa
+ // [51] irq_line::i1#1 = ++ irq_line::i1#2 -- vbuaa=_inc_vbuaa
inc
- // [45] phi from irq_line::@9 to irq_line::@8 [phi:irq_line::@9->irq_line::@8]
- // [45] phi irq_line::i1#2 = irq_line::i1#1 [phi:irq_line::@9->irq_line::@8#0] -- register_copy
+ // [47] phi from irq_line::@9 to irq_line::@8 [phi:irq_line::@9->irq_line::@8]
+ // [47] phi irq_line::i1#2 = irq_line::i1#1 [phi:irq_line::@9->irq_line::@8#0] -- register_copy
jmp __b8
// irq_line::@6
__b6:
// for(char i=0;i<24;i++)
- // [50] irq_line::i#1 = ++ irq_line::i#2 -- vbuaa=_inc_vbuaa
+ // [52] irq_line::i#1 = ++ irq_line::i#2 -- vbuaa=_inc_vbuaa
inc
- // [42] phi from irq_line::@6 to irq_line::@5 [phi:irq_line::@6->irq_line::@5]
- // [42] phi irq_line::i#2 = irq_line::i#1 [phi:irq_line::@6->irq_line::@5#0] -- register_copy
+ // [44] phi from irq_line::@6 to irq_line::@5 [phi:irq_line::@6->irq_line::@5]
+ // [44] phi irq_line::i#2 = irq_line::i#1 [phi:irq_line::@6->irq_line::@5#0] -- register_copy
jmp __b5
}
// main
@@ -1795,24 +1948,24 @@ main: {
sei
// main::@2
// *KERNEL_IRQ = &irq_line
- // [53] *KERNEL_IRQ = &irq_line -- _deref_qprc1=pprc2
+ // [55] *KERNEL_IRQ = &irq_line -- _deref_qprc1=pprc2
lda #irq_line
sta KERNEL_IRQ+1
// *VERA_IEN = VERA_LINE
- // [54] *VERA_IEN = VERA_LINE -- _deref_pbuc1=vbuc2
+ // [56] *VERA_IEN = VERA_LINE -- _deref_pbuc1=vbuc2
lda #VERA_LINE
sta VERA_IEN
// *VERA_IRQLINE_L = 5
- // [55] *VERA_IRQLINE_L = 5 -- _deref_pbuc1=vbuc2
+ // [57] *VERA_IRQLINE_L = 5 -- _deref_pbuc1=vbuc2
lda #5
sta VERA_IRQLINE_L
// main::CLI1
// asm
// asm { cli }
cli
- // [57] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1]
+ // [59] phi from main::@1 main::CLI1 to main::@1 [phi:main::@1/main::CLI1->main::@1]
// main::@1
__b1:
jmp __b1
@@ -1825,9 +1978,9 @@ memset: {
.const c = 0
.label str = BARS
.label end = str+num
- .label dst = 2
- // [59] phi from memset to memset::@1 [phi:memset->memset::@1]
- // [59] phi memset::dst#2 = (char *)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
+ .label dst = $22
+ // [61] phi from memset to memset::@1 [phi:memset->memset::@1]
+ // [61] phi memset::dst#2 = (char *)memset::str#0 [phi:memset->memset::@1#0] -- pbuz1=pbuc1
lda #str
@@ -1835,7 +1988,7 @@ memset: {
// memset::@1
__b1:
// for(char* dst = str; dst!=end; dst++)
- // [60] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
+ // [62] if(memset::dst#2!=memset::end#0) goto memset::@2 -- pbuz1_neq_pbuc1_then_la1
lda.z dst+1
cmp #>end
bne __b2
@@ -1844,23 +1997,23 @@ memset: {
bne __b2
// memset::@return
// }
- // [61] return
+ // [63] return
rts
// memset::@2
__b2:
// *dst = c
- // [62] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuc1
+ // [64] *memset::dst#2 = memset::c#0 -- _deref_pbuz1=vbuc1
lda #c
ldy #0
sta (dst),y
// for(char* dst = str; dst!=end; dst++)
- // [63] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
+ // [65] memset::dst#1 = ++ memset::dst#2 -- pbuz1=_inc_pbuz1
inc.z dst
bne !+
inc.z dst+1
!:
- // [59] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
- // [59] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
+ // [61] phi from memset::@2 to memset::@1 [phi:memset::@2->memset::@1]
+ // [61] phi memset::dst#2 = memset::dst#1 [phi:memset::@2->memset::@1#0] -- register_copy
jmp __b1
}
// File Data
diff --git a/src/test/ref/examples/cx16/cx16-rasterbars.sym b/src/test/ref/examples/cx16/cx16-rasterbars.sym
index b6ea05022..09568ee77 100644
--- a/src/test/ref/examples/cx16/cx16-rasterbars.sym
+++ b/src/test/ref/examples/cx16/cx16-rasterbars.sym
@@ -1,6 +1,12 @@
__constant char BAR[$20] = { $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $1a, $1b, $1c, $1d, $1e, $1f, $1f, $1e, $1d, $1c, $1b, $1a, $19, $18, $17, $16, $15, $14, $13, $12, $11, $10 }
__constant char BARS[$e6] = { fill( $e6, 0) }
+__loadstore volatile char BRAM // !zp[-1]:0 zp[1]:0 20.0
+__loadstore volatile char BROM // !zp[-1]:1 zp[1]:1 20.0
__constant void (** const KERNEL_IRQ)() = (void (**)()) 788
+__constant char RADIX::BINARY = 2
+__constant char RADIX::DECIMAL = $a
+__constant char RADIX::HEXADECIMAL = $10
+__constant char RADIX::OCTAL = 8
__constant char SIN[$100] = kickasm {{ .fill 256, 99+99*sin(i*2*PI/256)
}}
__constant char SIZEOF_CHAR = 1
@@ -16,15 +22,15 @@ __constant char * const VERA_IRQLINE_L = (char *) 40744
__constant char * const VERA_ISR = (char *) 40743
__constant const char VERA_LINE = 2
void __start()
-__loadstore volatile char cnt // zp[1]:5 0.5263157894736842
-__loadstore volatile char hstart // zp[1]:6 0.4545454545454546
-__loadstore volatile char hstop // zp[1]:7 0.34782608695652173
+__loadstore volatile char cnt // zp[1]:37 0.5263157894736842
+__loadstore volatile char hstart // zp[1]:38 0.4545454545454546
+__loadstore volatile char hstop // zp[1]:39 0.34782608695652173
__interrupt(rom_min_cx16) void irq_line()
char irq_line::b
char irq_line::b#1 // reg byte x 22.0
char irq_line::b#2 // reg byte x 4.125
char *irq_line::bar
-char *irq_line::bar#0 // bar zp[2]:2 22.4
+char *irq_line::bar#0 // bar zp[2]:34 22.4
char irq_line::i
char irq_line::i#1 // reg byte a 202.0
char irq_line::i#2 // reg byte a 151.5
@@ -35,19 +41,21 @@ char irq_line::i2
char irq_line::i2#1 // reg byte y 202.0
char irq_line::i2#2 // reg byte y 168.33333333333331
char irq_line::idx
-char irq_line::idx#0 // idx zp[1]:4 2.0
-char irq_line::idx#1 // idx zp[1]:4 11.0
-char irq_line::idx#2 // idx zp[1]:4 5.0
+char irq_line::idx#0 // idx zp[1]:36 2.0
+char irq_line::idx#1 // idx zp[1]:36 11.0
+char irq_line::idx#2 // idx zp[1]:36 5.0
char irq_line::l
char irq_line::l#1 // reg byte x 22.0
char irq_line::l#2 // reg byte x 4.0
+unsigned int isr_vsync
+__constant unsigned int isr_vsync#2 = $314 // isr_vsync
void main()
void * memset(void *str , char c , unsigned int num)
char memset::c
__constant char memset::c#0 = 0 // c
char *memset::dst
-char *memset::dst#1 // dst zp[2]:2 202.0
-char *memset::dst#2 // dst zp[2]:2 134.66666666666666
+char *memset::dst#1 // dst zp[2]:34 202.0
+char *memset::dst#2 // dst zp[2]:34 134.66666666666666
char *memset::end
__constant char *memset::end#0 = (char *)memset::str#0+memset::num#0 // end
unsigned int memset::num
@@ -55,20 +63,22 @@ __constant unsigned int memset::num#0 = $e6*SIZEOF_CHAR // num
void *memset::return
void *memset::str
__constant void *memset::str#0 = (void *)BARS // str
-__loadstore volatile char sin_idx // zp[1]:10 0.27586206896551724
-__loadstore volatile char vstart // zp[1]:8 0.3333333333333333
-__loadstore volatile char vstop // zp[1]:9 0.32
+__loadstore volatile char sin_idx // zp[1]:42 0.27586206896551724
+__loadstore volatile char vstart // zp[1]:40 0.3333333333333333
+__loadstore volatile char vstop // zp[1]:41 0.32
reg byte x [ irq_line::l#2 irq_line::l#1 ]
reg byte x [ irq_line::b#2 irq_line::b#1 ]
-zp[1]:4 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
+zp[1]:36 [ irq_line::idx#2 irq_line::idx#1 irq_line::idx#0 ]
reg byte y [ irq_line::i2#2 irq_line::i2#1 ]
reg byte a [ irq_line::i#2 irq_line::i#1 ]
reg byte a [ irq_line::i1#2 irq_line::i1#1 ]
-zp[1]:6 [ hstart ]
-zp[1]:7 [ hstop ]
-zp[1]:8 [ vstart ]
-zp[1]:9 [ vstop ]
-zp[1]:5 [ cnt ]
-zp[1]:10 [ sin_idx ]
-zp[2]:2 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
+zp[1]:0 [ BRAM ]
+zp[1]:1 [ BROM ]
+zp[1]:38 [ hstart ]
+zp[1]:39 [ hstop ]
+zp[1]:40 [ vstart ]
+zp[1]:41 [ vstop ]
+zp[1]:37 [ cnt ]
+zp[1]:42 [ sin_idx ]
+zp[2]:34 [ irq_line::bar#0 memset::dst#2 memset::dst#1 ]
diff --git a/src/test/ref/examples/cx16/veralib/bitmap_8bpp_320_x_240.asm b/src/test/ref/examples/cx16/veralib/bitmap_8bpp_320_x_240.asm
deleted file mode 100644
index 9930fed7a..000000000
--- a/src/test/ref/examples/cx16/veralib/bitmap_8bpp_320_x_240.asm
+++ /dev/null
@@ -1,3510 +0,0 @@
-// Example program for the Commander X16.
-// Demonstrates the usage of the VERA tile map modes and layering.
-.cpu _65c02
- // Commodore 64 PRG executable file
-.file [name="bitmap_8bpp_320_x_240.prg", type="prg", segments="Program"]
-.segmentdef Program [segments="Basic, Code, Data"]
-.segmentdef Basic [start=$0801]
-.segmentdef Code [start=$80d]
-.segmentdef Data [startAfter="Code"]
-.segment Basic
-:BasicUpstart(__start)
- /// The colors of the CX16
- .const BLACK = 0
- .const WHITE = 1
- .const BLUE = 6
- .const YELLOW = 7
- .const VERA_INC_1 = $10
- .const VERA_ADDRSEL = 1
- .const VERA_LAYER1_ENABLE = $20
- .const VERA_LAYER0_ENABLE = $10
- .const VERA_LAYER_WIDTH_64 = $10
- .const VERA_LAYER_WIDTH_128 = $20
- .const VERA_LAYER_WIDTH_256 = $30
- .const VERA_LAYER_WIDTH_MASK = $30
- .const VERA_LAYER_HEIGHT_64 = $40
- .const VERA_LAYER_HEIGHT_128 = $80
- .const VERA_LAYER_HEIGHT_256 = $c0
- .const VERA_LAYER_HEIGHT_MASK = $c0
- /// Bit 0-1: Color Depth (0: 1 bpp, 1: 2 bpp, 2: 4 bpp, 3: 8 bpp)
- .const VERA_LAYER_COLOR_DEPTH_1BPP = 0
- .const VERA_LAYER_COLOR_DEPTH_8BPP = 3
- .const VERA_LAYER_COLOR_DEPTH_MASK = 3
- .const VERA_LAYER_CONFIG_MODE_BITMAP = 4
- .const VERA_LAYER_CONFIG_256C = 8
- .const VERA_TILEBASE_WIDTH_16 = 1
- .const VERA_TILEBASE_HEIGHT_16 = 2
- .const VERA_LAYER_TILEBASE_MASK = $fc
- .const SIZEOF_POINTER = 2
- .const STACK_BASE = $103
- /// $9F20 VRAM Address (7:0)
- .label VERA_ADDRX_L = $9f20
- /// $9F21 VRAM Address (15:8)
- .label VERA_ADDRX_M = $9f21
- /// $9F22 VRAM Address (7:0)
- /// Bit 4-7: Address Increment The following is the amount incremented per value value:increment
- /// 0:0, 1:1, 2:2, 3:4, 4:8, 5:16, 6:32, 7:64, 8:128, 9:256, 10:512, 11:40, 12:80, 13:160, 14:320, 15:640
- /// Bit 3: DECR Setting the DECR bit, will decrement instead of increment by the value set by the 'Address Increment' field.
- /// Bit 0: VRAM Address (16)
- .label VERA_ADDRX_H = $9f22
- /// $9F23 DATA0 VRAM Data port 0
- .label VERA_DATA0 = $9f23
- /// $9F24 DATA1 VRAM Data port 1
- .label VERA_DATA1 = $9f24
- /// $9F25 CTRL Control
- /// Bit 7: Reset
- /// Bit 1: DCSEL
- /// Bit 2: ADDRSEL
- .label VERA_CTRL = $9f25
- /// $9F29 DC_VIDEO (DCSEL=0)
- /// Bit 7: Current Field Read-only bit which reflects the active interlaced field in composite and RGB modes. (0: even, 1: odd)
- /// Bit 6: Sprites Enable Enable output from the Sprites renderer
- /// Bit 5: Layer1 Enable Enable output from the Layer1 renderer
- /// Bit 4: Layer0 Enable Enable output from the Layer0 renderer
- /// Bit 2: Chroma Disable Setting 'Chroma Disable' disables output of chroma in NTSC composite mode and will give a better picture on a monochrome display. (Setting this bit will also disable the chroma output on the S-video output.)
- /// Bit 0-1: Output Mode 0: Video disabled, 1: VGA output, 2: NTSC composite, 3: RGB interlaced, composite sync (via VGA connector)
- .label VERA_DC_VIDEO = $9f29
- /// $9F2A DC_HSCALE (DCSEL=0) Active Display H-Scale
- .label VERA_DC_HSCALE = $9f2a
- /// $9F2B DC_VSCALE (DCSEL=0) Active Display V-Scale
- .label VERA_DC_VSCALE = $9f2b
- /// $9F2D L0_CONFIG Layer 0 Configuration
- .label VERA_L0_CONFIG = $9f2d
- /// $9F2E L0_MAPBASE Layer 0 Map Base Address (16:9)
- .label VERA_L0_MAPBASE = $9f2e
- /// Bit 0: Tile Width (0:8 pixels, 1:16 pixels)
- .label VERA_L0_TILEBASE = $9f2f
- /// $9F34 L1_CONFIG Layer 1 Configuration
- .label VERA_L1_CONFIG = $9f34
- /// $9F35 L1_MAPBASE Layer 1 Map Base Address (16:9)
- .label VERA_L1_MAPBASE = $9f35
- /// $9F36 L1_TILEBASE Layer 1 Tile Base
- /// Bit 2-7: Tile Base Address (16:11)
- /// Bit 1: Tile Height (0:8 pixels, 1:16 pixels)
- /// Bit 0: Tile Width (0:8 pixels, 1:16 pixels)
- .label VERA_L1_TILEBASE = $9f36
- // Variable holding the screen width;
- .label conio_screen_width = $24
- // Variable holding the screen height;
- .label conio_screen_height = $31
- // Variable holding the screen layer on the VERA card with which conio interacts;
- .label conio_screen_layer = $30
- // Variables holding the current map width and map height of the layer.
- .label conio_width = $a5
- .label conio_height = $33
- .label conio_rowshift = $2d
- .label conio_rowskip = $2e
- .label __bitmap_address = $ac
- .label __bitmap_layer = $96
- .label __bitmap_hscale = $b0
- .label __bitmap_vscale = $b1
- .label __bitmap_color_depth = $a7
- // The random state variable
- .label rand_state = $35
- // Remainder after unsigned 16-bit division
- .label rem16u = $41
- // The screen width
- // The screen height
- // The text screen base address, which is a 16:0 bit value in VERA VRAM.
- // That is 128KB addressable space, thus 17 bits in total.
- // CONIO_SCREEN_TEXT contains bits 15:0 of the address.
- // CONIO_SCREEN_BANK contains bit 16, the the 64K memory bank in VERA VRAM (the upper 17th bit).
- // !!! note that these values are not const for the cx16!
- // This conio implements the two layers of VERA, which can be layer 0 or layer 1.
- // Configuring conio to output to a different layer, will change these fields to the address base
- // configured using VERA_L0_MAPBASE = 0x9f2e or VERA_L1_MAPBASE = 0x9f35.
- // Using the function setscreenlayer(layer) will re-calculate using CONIO_SCREEN_TEXT and CONIO_SCREEN_BASE
- // based on the values of VERA_L0_MAPBASE or VERA_L1_MAPBASE, mapping the base address of the selected layer.
- // The function setscreenlayermapbase(layer,mapbase) allows to configure bit 16:9 of the
- // mapbase address of the time map in VRAM of the selected layer VERA_L0_MAPBASE or VERA_L1_MAPBASE.
- .label CONIO_SCREEN_TEXT = $2b
- .label CONIO_SCREEN_BANK = $88
- .label CONIO_SCREEN_BANK_1 = $ab
- // The screen width
- // The screen height
- // The text screen base address, which is a 16:0 bit value in VERA VRAM.
- // That is 128KB addressable space, thus 17 bits in total.
- // CONIO_SCREEN_TEXT contains bits 15:0 of the address.
- // CONIO_SCREEN_BANK contains bit 16, the the 64K memory bank in VERA VRAM (the upper 17th bit).
- // !!! note that these values are not const for the cx16!
- // This conio implements the two layers of VERA, which can be layer 0 or layer 1.
- // Configuring conio to output to a different layer, will change these fields to the address base
- // configured using VERA_L0_MAPBASE = 0x9f2e or VERA_L1_MAPBASE = 0x9f35.
- // Using the function setscreenlayer(layer) will re-calculate using CONIO_SCREEN_TEXT and CONIO_SCREEN_BASE
- // based on the values of VERA_L0_MAPBASE or VERA_L1_MAPBASE, mapping the base address of the selected layer.
- // The function setscreenlayermapbase(layer,mapbase) allows to configure bit 16:9 of the
- // mapbase address of the time map in VRAM of the selected layer VERA_L0_MAPBASE or VERA_L1_MAPBASE.
- .label CONIO_SCREEN_TEXT_1 = $b2
-.segment Code
-__start: {
- // __ma unsigned byte conio_screen_width = 0
- lda #0
- sta.z conio_screen_width
- // __ma unsigned byte conio_screen_height = 0
- sta.z conio_screen_height
- // __ma unsigned byte conio_screen_layer = 1
- lda #1
- sta.z conio_screen_layer
- // __ma word conio_width = 0
- lda #<0
- sta.z conio_width
- sta.z conio_width+1
- // __ma word conio_height = 0
- sta.z conio_height
- sta.z conio_height+1
- // __ma byte conio_rowshift = 0
- sta.z conio_rowshift
- // __ma word conio_rowskip = 0
- sta.z conio_rowskip
- sta.z conio_rowskip+1
- // __ma dword __bitmap_address = 0
- sta.z __bitmap_address
- sta.z __bitmap_address+1
- lda #<0>>$10
- sta.z __bitmap_address+2
- lda #>0>>$10
- sta.z __bitmap_address+3
- // __ma byte __bitmap_layer = 0
- lda #0
- sta.z __bitmap_layer
- // __ma byte __bitmap_hscale = 0
- sta.z __bitmap_hscale
- // __ma byte __bitmap_vscale = 0
- sta.z __bitmap_vscale
- // __ma byte __bitmap_color_depth = 0
- sta.z __bitmap_color_depth
- // #pragma constructor_for(conio_x16_init, cputc, clrscr, cscroll)
- jsr conio_x16_init
- jsr main
- rts
-}
-// Set initial cursor position
-conio_x16_init: {
- // Position cursor at current line
- .label BASIC_CURSOR_LINE = $d6
- .label line = $a8
- // char line = *BASIC_CURSOR_LINE
- lda.z BASIC_CURSOR_LINE
- sta.z line
- // vera_layer_mode_text(1,(dword)0x00000,(dword)0x0F800,128,64,8,8,16)
- jsr vera_layer_mode_text
- // screensize(&conio_screen_width, &conio_screen_height)
- jsr screensize
- // screenlayer(1)
- jsr screenlayer
- // vera_layer_set_textcolor(1, WHITE)
- lda #WHITE
- ldx #1
- jsr vera_layer_set_textcolor
- // vera_layer_set_backcolor(1, BLUE)
- lda #BLUE
- ldx #1
- jsr vera_layer_set_backcolor
- // vera_layer_set_mapbase(0,0x20)
- ldx #$20
- lda #0
- jsr vera_layer_set_mapbase
- // vera_layer_set_mapbase(1,0x00)
- ldx #0
- lda #1
- jsr vera_layer_set_mapbase
- // if(line>=CONIO_HEIGHT)
- lda.z line
- cmp.z conio_screen_height
- bcc __b1
- // line=CONIO_HEIGHT-1
- ldx.z conio_screen_height
- dex
- stx.z line
- __b1:
- // gotoxy(0, line)
- ldx.z line
- jsr gotoxy
- // }
- rts
-}
-// Output one character at the current cursor position
-// Moves the cursor forward. Scrolls the entire screen if needed
-// void cputc(__zp($69) char c)
-cputc: {
- .const OFFSET_STACK_C = 0
- .label __16 = $29
- .label c = $69
- .label conio_addr = $1e
- tsx
- lda STACK_BASE+OFFSET_STACK_C,x
- sta.z c
- // char color = vera_layer_get_color( conio_screen_layer)
- ldx.z conio_screen_layer
- jsr vera_layer_get_color
- // char color = vera_layer_get_color( conio_screen_layer)
- tax
- // char* conio_addr = CONIO_SCREEN_TEXT + conio_line_text[conio_screen_layer]
- lda.z conio_screen_layer
- asl
- tay
- clc
- lda.z CONIO_SCREEN_TEXT
- adc conio_line_text,y
- sta.z conio_addr
- lda.z CONIO_SCREEN_TEXT+1
- adc conio_line_text+1,y
- sta.z conio_addr+1
- // conio_cursor_x[conio_screen_layer] << 1
- ldy.z conio_screen_layer
- lda conio_cursor_x,y
- asl
- // conio_addr += conio_cursor_x[conio_screen_layer] << 1
- clc
- adc.z conio_addr
- sta.z conio_addr
- bcc !+
- inc.z conio_addr+1
- !:
- // if(c=='\n')
- lda #'\n'
- cmp.z c
- beq __b1
- // *VERA_CTRL &= ~VERA_ADDRSEL
- // Select DATA0
- lda #VERA_ADDRSEL^$ff
- and VERA_CTRL
- sta VERA_CTRL
- // BYTE0(conio_addr)
- lda.z conio_addr
- // *VERA_ADDRX_L = BYTE0(conio_addr)
- // Set address
- sta VERA_ADDRX_L
- // BYTE1(conio_addr)
- lda.z conio_addr+1
- // *VERA_ADDRX_M = BYTE1(conio_addr)
- sta VERA_ADDRX_M
- // CONIO_SCREEN_BANK | VERA_INC_1
- lda #VERA_INC_1
- ora.z CONIO_SCREEN_BANK
- // *VERA_ADDRX_H = CONIO_SCREEN_BANK | VERA_INC_1
- sta VERA_ADDRX_H
- // *VERA_DATA0 = c
- lda.z c
- sta VERA_DATA0
- // *VERA_DATA0 = color
- stx VERA_DATA0
- // conio_cursor_x[conio_screen_layer]++;
- ldx.z conio_screen_layer
- inc conio_cursor_x,x
- // byte scroll_enable = conio_scroll_enable[conio_screen_layer]
- ldy.z conio_screen_layer
- lda conio_scroll_enable,y
- // if(scroll_enable)
- cmp #0
- bne __b5
- // (unsigned int)conio_cursor_x[conio_screen_layer] == conio_width
- lda conio_cursor_x,y
- sta.z __16
- lda #0
- sta.z __16+1
- // if((unsigned int)conio_cursor_x[conio_screen_layer] == conio_width)
- cmp.z conio_width+1
- bne __breturn
- lda.z __16
- cmp.z conio_width
- bne __breturn
- // cputln()
- jsr cputln
- __breturn:
- // }
- rts
- __b5:
- // if(conio_cursor_x[conio_screen_layer] == CONIO_WIDTH)
- lda.z conio_screen_width
- ldy.z conio_screen_layer
- cmp conio_cursor_x,y
- bne __breturn
- // cputln()
- jsr cputln
- rts
- __b1:
- // cputln()
- jsr cputln
- rts
-}
-main: {
- .label __40 = $6e
- .label color = $7e
- .label x = $78
- // memcpy_in_vram(1, (char*)0xF000, VERA_INC_1, 0, (char*)0xF800, VERA_INC_1, 256*8)
- // Before we configure the bitmap pane into vera memory we need to re-arrange a few things!
- // It is better to load all in bank 0, but then there is an issue.
- // So the default CX16 character set is located in bank 0, at address 0xF800.
- // So we need to move this character set to bank 1, suggested is at address 0xF000.
- // The CX16 by default writes textual output to layer 1 in text mode, so we need to
- // realign the moved character set to 0xf000 as the new tile base for layer 1.
- // We also will need to realign for layer 1 the map base from 0x00000 to 0x14000.
- // This is now all easily done with a few statements in the new kickc vera lib ...
- lda #<$100*8
- sta.z memcpy_in_vram.num
- lda #>$100*8
- sta.z memcpy_in_vram.num+1
- ldy #1
- lda #<$f000
- sta.z memcpy_in_vram.dest
- lda #>$f000
- sta.z memcpy_in_vram.dest+1
- lda #<$f800
- sta.z memcpy_in_vram.src
- lda #>$f800
- sta.z memcpy_in_vram.src+1
- jsr memcpy_in_vram
- // vera_layer_mode_tile(1, 0x14000, 0x1F000, 128, 64, 8, 8, 1)
- // We copy the 128 character set of 8 bytes each.
- lda #8
- sta.z vera_layer_mode_tile.tileheight
- sta.z vera_layer_mode_tile.tilewidth
- lda #<$1f000
- sta.z vera_layer_mode_tile.tilebase_address
- lda #>$1f000
- sta.z vera_layer_mode_tile.tilebase_address+1
- lda #<$1f000>>$10
- sta.z vera_layer_mode_tile.tilebase_address+2
- lda #>$1f000>>$10
- sta.z vera_layer_mode_tile.tilebase_address+3
- lda #<$14000
- sta.z vera_layer_mode_tile.mapbase_address
- lda #>$14000
- sta.z vera_layer_mode_tile.mapbase_address+1
- lda #<$14000>>$10
- sta.z vera_layer_mode_tile.mapbase_address+2
- lda #>$14000>>$10
- sta.z vera_layer_mode_tile.mapbase_address+3
- lda #<$40
- sta.z vera_layer_mode_tile.mapheight
- lda #>$40
- sta.z vera_layer_mode_tile.mapheight+1
- lda #1
- sta.z vera_layer_mode_tile.layer
- lda #<$80
- sta.z vera_layer_mode_tile.mapwidth
- lda #>$80
- sta.z vera_layer_mode_tile.mapwidth+1
- jsr vera_layer_mode_tile
- // vera_layer_mode_bitmap(0, (dword)0x00000, 320, 8)
- jsr vera_layer_mode_bitmap
- // screenlayer(1)
- jsr screenlayer
- // vera_layer_set_textcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #WHITE
- jsr vera_layer_set_textcolor
- // vera_layer_set_backcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #BLACK
- jsr vera_layer_set_backcolor
- // clrscr()
- jsr clrscr
- // gotoxy(0,25)
- ldx #$19
- jsr gotoxy
- // printf("vera in bitmap mode,\n")
- lda #s
- sta.z printf_str.s+1
- jsr printf_str
- // printf("color depth 8 bits per pixel.\n")
- lda #s1
- sta.z printf_str.s+1
- jsr printf_str
- // printf("in this mode, it is possible to display\n")
- lda #s2
- sta.z printf_str.s+1
- jsr printf_str
- // printf("graphics in 256 colors.\n")
- lda #s3
- sta.z printf_str.s+1
- jsr printf_str
- // *VERA_DC_VIDEO |= vera_layer_enable[layer]
- lda VERA_DC_VIDEO
- ora vera_layer_enable
- sta VERA_DC_VIDEO
- // bitmap_init(0, 0x00000)
- jsr bitmap_init
- // bitmap_clear()
- jsr bitmap_clear
- // gotoxy(0,29)
- ldx #$1d
- jsr gotoxy
- // vera_layer_set_textcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #YELLOW
- jsr vera_layer_set_textcolor
- // printf("press a key ...")
- lda #s4
- sta.z printf_str.s+1
- jsr printf_str
- lda #<1
- sta.z rand_state
- lda #>1
- sta.z rand_state+1
- __b1:
- // kbhit()
- jsr kbhit
- // while(!kbhit())
- cmp #0
- bne !__b2+
- jmp __b2
- !__b2:
- // vera_layer_set_textcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #WHITE
- jsr vera_layer_set_textcolor
- // vera_layer_set_backcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #BLACK
- jsr vera_layer_set_backcolor
- // clrscr()
- jsr clrscr
- // gotoxy(0,26)
- ldx #$1a
- jsr gotoxy
- // printf("here you see all the colors possible.\n")
- lda #s5
- sta.z printf_str.s+1
- jsr printf_str
- // gotoxy(0,29)
- ldx #$1d
- jsr gotoxy
- // vera_layer_set_textcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #YELLOW
- jsr vera_layer_set_textcolor
- // printf("press a key ...")
- lda #s4
- sta.z printf_str.s+1
- jsr printf_str
- lda #0
- sta.z color
- sta.z x
- sta.z x+1
- __b3:
- // kbhit()
- jsr kbhit
- // while(!kbhit())
- cmp #0
- beq __b4
- // screenlayer(1)
- jsr screenlayer
- // vera_layer_set_textcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #WHITE
- jsr vera_layer_set_textcolor
- // vera_layer_set_backcolor(conio_screen_layer, color)
- ldx.z conio_screen_layer
- lda #BLUE
- jsr vera_layer_set_backcolor
- // clrscr()
- jsr clrscr
- // }
- rts
- __b4:
- // bitmap_line(x, x, 0, 199, color)
- lda.z x
- sta.z bitmap_line.x0
- lda.z x+1
- sta.z bitmap_line.x0+1
- lda.z x
- sta.z bitmap_line.x1
- lda.z x+1
- sta.z bitmap_line.x1+1
- ldx.z color
- lda #<$c7
- sta.z bitmap_line.y1
- lda #>$c7
- sta.z bitmap_line.y1+1
- lda #<0
- sta.z bitmap_line.y0
- sta.z bitmap_line.y0+1
- jsr bitmap_line
- // color++;
- inc.z color
- // x++;
- inc.z x
- bne !+
- inc.z x+1
- !:
- // if(x>319)
- lda.z x+1
- cmp #>$13f
- bne !+
- lda.z x
- cmp #<$13f
- !:
- bcc __b3
- beq __b3
- lda #<0
- sta.z x
- sta.z x+1
- jmp __b3
- __b2:
- // rand()
- jsr rand
- // rand()
- // modr16u(rand(),320,0)
- lda.z rand.return
- sta.z modr16u.dividend
- lda.z rand.return+1
- sta.z modr16u.dividend+1
- lda #<$140
- sta.z modr16u.divisor
- lda #>$140
- sta.z modr16u.divisor+1
- jsr modr16u
- // modr16u(rand(),320,0)
- // bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255)
- lda.z modr16u.return
- sta.z bitmap_line.x0
- lda.z modr16u.return+1
- sta.z bitmap_line.x0+1
- // rand()
- jsr rand
- // rand()
- // modr16u(rand(),320,0)
- lda.z rand.return
- sta.z modr16u.dividend
- lda.z rand.return+1
- sta.z modr16u.dividend+1
- lda #<$140
- sta.z modr16u.divisor
- lda #>$140
- sta.z modr16u.divisor+1
- jsr modr16u
- // modr16u(rand(),320,0)
- // bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255)
- lda.z modr16u.return
- sta.z bitmap_line.x1
- lda.z modr16u.return+1
- sta.z bitmap_line.x1+1
- // rand()
- jsr rand
- // rand()
- // modr16u(rand(),200,0)
- lda.z rand.return
- sta.z modr16u.dividend
- lda.z rand.return+1
- sta.z modr16u.dividend+1
- lda #<$c8
- sta.z modr16u.divisor
- lda #>$c8
- sta.z modr16u.divisor+1
- jsr modr16u
- // modr16u(rand(),200,0)
- // bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255)
- lda.z modr16u.return
- sta.z bitmap_line.y0
- lda.z modr16u.return+1
- sta.z bitmap_line.y0+1
- // rand()
- jsr rand
- // rand()
- // modr16u(rand(),200,0)
- lda.z rand.return
- sta.z modr16u.dividend
- lda.z rand.return+1
- sta.z modr16u.dividend+1
- lda #<$c8
- sta.z modr16u.divisor
- lda #>$c8
- sta.z modr16u.divisor+1
- jsr modr16u
- // modr16u(rand(),200,0)
- // bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255)
- lda.z modr16u.return
- sta.z bitmap_line.y1
- lda.z modr16u.return+1
- sta.z bitmap_line.y1+1
- // rand()
- jsr rand
- // rand()
- // bitmap_line(modr16u(rand(),320,0), modr16u(rand(),320,0), modr16u(rand(),200,0), modr16u(rand(),200,0), rand()&255)
- lda #$ff
- and.z __40
- tax
- jsr bitmap_line
- jmp __b1
- .segment Data
- s: .text @"vera in bitmap mode,\n"
- .byte 0
- s1: .text @"color depth 8 bits per pixel.\n"
- .byte 0
- s2: .text @"in this mode, it is possible to display\n"
- .byte 0
- s3: .text @"graphics in 256 colors.\n"
- .byte 0
- s4: .text "press a key ..."
- .byte 0
- s5: .text @"here you see all the colors possible.\n"
- .byte 0
-}
-.segment Code
-// Set a vera layer in text mode and configure the:
-// - layer: Value of 0 or 1.
-// - mapbase_address: A dword typed address (4 bytes), that specifies the full address of the map base.
-// The function does the translation from the dword that contains the 17 bit address,
-// to the respective mapbase vera register.
-// Note that the register only specifies bits 16:9 of the address,
-// so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
-// - tilebase_address: A dword typed address (4 bytes), that specifies the base address of the tile map.
-// The function does the translation from the dword that contains the 17 bit address,
-// to the respective tilebase vera register.
-// Note that the resulting vera register holds only specifies bits 16:11 of the address,
-// so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
-// - mapwidth: The width of the map in number of tiles.
-// - mapheight: The height of the map in number of tiles.
-// - tilewidth: The width of a tile, which can be 8 or 16 pixels.
-// - tileheight: The height of a tile, which can be 8 or 16 pixels.
-// - color_mode: The color mode, which can be 16 or 256.
-// void vera_layer_mode_text(char layer, unsigned long mapbase_address, unsigned long tilebase_address, unsigned int mapwidth, unsigned int mapheight, char tilewidth, char tileheight, unsigned int color_mode)
-vera_layer_mode_text: {
- .const mapbase_address = 0
- .const tilebase_address = $f800
- .const mapwidth = $80
- .const mapheight = $40
- .const tilewidth = 8
- .const tileheight = 8
- .label layer = 1
- // vera_layer_mode_tile( layer, mapbase_address, tilebase_address, mapwidth, mapheight, tilewidth, tileheight, 1 )
- lda #tileheight
- sta.z vera_layer_mode_tile.tileheight
- lda #tilewidth
- sta.z vera_layer_mode_tile.tilewidth
- lda #tilebase_address
- sta.z vera_layer_mode_tile.tilebase_address+1
- lda #>$10
- sta.z vera_layer_mode_tile.tilebase_address+2
- lda #>tilebase_address>>$10
- sta.z vera_layer_mode_tile.tilebase_address+3
- lda #mapbase_address
- sta.z vera_layer_mode_tile.mapbase_address+1
- lda #>$10
- sta.z vera_layer_mode_tile.mapbase_address+2
- lda #>mapbase_address>>$10
- sta.z vera_layer_mode_tile.mapbase_address+3
- lda #mapheight
- sta.z vera_layer_mode_tile.mapheight+1
- lda #layer
- sta.z vera_layer_mode_tile.layer
- lda #mapwidth
- sta.z vera_layer_mode_tile.mapwidth+1
- jsr vera_layer_mode_tile
- // vera_layer_set_text_color_mode( layer, VERA_LAYER_CONFIG_16C )
- jsr vera_layer_set_text_color_mode
- // }
- rts
-}
-// Return the current screen size.
-// void screensize(char *x, char *y)
-screensize: {
- .label x = conio_screen_width
- .label y = conio_screen_height
- // char hscale = (*VERA_DC_HSCALE) >> 7
- // VERA returns in VERA_DC_HSCALE the value of 128 when 80 columns is used in text mode,
- // and the value of 64 when 40 columns is used in text mode.
- // Basically, 40 columns mode in the VERA is a double scan mode.
- // Same for the VERA_DC_VSCALE mode, but then the subdivision is 60 or 30 rows.
- // I still need to test the other modes, but this will suffice for now for the pure text modes.
- lda VERA_DC_HSCALE
- rol
- rol
- and #1
- // 40 << hscale
- tay
- lda #$28
- cpy #0
- beq !e+
- !:
- asl
- dey
- bne !-
- !e:
- // *x = 40 << hscale
- sta.z x
- // char vscale = (*VERA_DC_VSCALE) >> 7
- lda VERA_DC_VSCALE
- rol
- rol
- and #1
- // 30 << vscale
- tay
- lda #$1e
- cpy #0
- beq !e+
- !:
- asl
- dey
- bne !-
- !e:
- // *y = 30 << vscale
- sta.z y
- // }
- rts
-}
-// Set the layer with which the conio will interact.
-// - layer: value of 0 or 1.
-// void screenlayer(char layer)
-screenlayer: {
- .label __2 = $89
- .label __4 = $7f
- .label __5 = $8b
- .label vera_layer_get_width1_config = $97
- .label vera_layer_get_width1_return = $89
- .label vera_layer_get_height1_config = $99
- .label vera_layer_get_height1_return = $8b
- // conio_screen_layer = layer
- lda #1
- sta.z conio_screen_layer
- // vera_layer_get_mapbase_bank(conio_screen_layer)
- tax
- jsr vera_layer_get_mapbase_bank
- sta.z CONIO_SCREEN_BANK_1
- // vera_layer_get_mapbase_offset(conio_screen_layer)
- lda.z conio_screen_layer
- jsr vera_layer_get_mapbase_offset
- lda.z vera_layer_get_mapbase_offset.return
- sta.z CONIO_SCREEN_TEXT_1
- lda.z vera_layer_get_mapbase_offset.return+1
- sta.z CONIO_SCREEN_TEXT_1+1
- // vera_layer_get_width(conio_screen_layer)
- lda.z conio_screen_layer
- // byte* config = vera_layer_config[layer]
- asl
- tay
- lda vera_layer_config,y
- sta.z vera_layer_get_width1_config
- lda vera_layer_config+1,y
- sta.z vera_layer_get_width1_config+1
- // *config & VERA_LAYER_WIDTH_MASK
- lda #VERA_LAYER_WIDTH_MASK
- ldy #0
- and (vera_layer_get_width1_config),y
- // (*config & VERA_LAYER_WIDTH_MASK) >> 4
- lsr
- lsr
- lsr
- lsr
- // return VERA_LAYER_WIDTH[ (*config & VERA_LAYER_WIDTH_MASK) >> 4];
- asl
- tay
- lda VERA_LAYER_WIDTH,y
- sta.z vera_layer_get_width1_return
- lda VERA_LAYER_WIDTH+1,y
- sta.z vera_layer_get_width1_return+1
- // }
- // vera_layer_get_width(conio_screen_layer)
- // conio_width = vera_layer_get_width(conio_screen_layer)
- lda.z __2
- sta.z conio_width
- lda.z __2+1
- sta.z conio_width+1
- // vera_layer_get_rowshift(conio_screen_layer)
- ldx.z conio_screen_layer
- jsr vera_layer_get_rowshift
- // conio_rowshift = vera_layer_get_rowshift(conio_screen_layer)
- sta.z conio_rowshift
- // vera_layer_get_rowskip(conio_screen_layer)
- lda.z conio_screen_layer
- jsr vera_layer_get_rowskip
- // conio_rowskip = vera_layer_get_rowskip(conio_screen_layer)
- lda.z __4
- sta.z conio_rowskip
- lda.z __4+1
- sta.z conio_rowskip+1
- // vera_layer_get_height(conio_screen_layer)
- lda.z conio_screen_layer
- // byte* config = vera_layer_config[layer]
- asl
- tay
- lda vera_layer_config,y
- sta.z vera_layer_get_height1_config
- lda vera_layer_config+1,y
- sta.z vera_layer_get_height1_config+1
- // *config & VERA_LAYER_HEIGHT_MASK
- lda #VERA_LAYER_HEIGHT_MASK
- ldy #0
- and (vera_layer_get_height1_config),y
- // (*config & VERA_LAYER_HEIGHT_MASK) >> 6
- rol
- rol
- rol
- and #3
- // return VERA_LAYER_HEIGHT[ (*config & VERA_LAYER_HEIGHT_MASK) >> 6];
- asl
- tay
- lda VERA_LAYER_HEIGHT,y
- sta.z vera_layer_get_height1_return
- lda VERA_LAYER_HEIGHT+1,y
- sta.z vera_layer_get_height1_return+1
- // }
- // vera_layer_get_height(conio_screen_layer)
- // conio_height = vera_layer_get_height(conio_screen_layer)
- lda.z __5
- sta.z conio_height
- lda.z __5+1
- sta.z conio_height+1
- // }
- rts
-}
-// Set the front color for text output. The old front text color setting is returned.
-// - layer: Value of 0 or 1.
-// - color: a 4 bit value ( decimal between 0 and 15) when the VERA works in 16x16 color text mode.
-// An 8 bit value (decimal between 0 and 255) when the VERA works in 256 text mode.
-// Note that on the VERA, the transparent color has value 0.
-// char vera_layer_set_textcolor(__register(X) char layer, __register(A) char color)
-vera_layer_set_textcolor: {
- // vera_layer_textcolor[layer] = color
- sta vera_layer_textcolor,x
- // }
- rts
-}
-// Set the back color for text output. The old back text color setting is returned.
-// - layer: Value of 0 or 1.
-// - color: a 4 bit value ( decimal between 0 and 15).
-// This will only work when the VERA is in 16 color mode!
-// Note that on the VERA, the transparent color has value 0.
-// char vera_layer_set_backcolor(__register(X) char layer, __register(A) char color)
-vera_layer_set_backcolor: {
- // vera_layer_backcolor[layer] = color
- sta vera_layer_backcolor,x
- // }
- rts
-}
-// Set the base of the map layer with which the conio will interact.
-// - layer: Value of 0 or 1.
-// - mapbase: Specifies the base address of the tile map.
-// Note that the register only specifies bits 16:9 of the address,
-// so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
-// void vera_layer_set_mapbase(__register(A) char layer, __register(X) char mapbase)
-vera_layer_set_mapbase: {
- .label addr = $25
- // byte* addr = vera_layer_mapbase[layer]
- asl
- tay
- lda vera_layer_mapbase,y
- sta.z addr
- lda vera_layer_mapbase+1,y
- sta.z addr+1
- // *addr = mapbase
- txa
- ldy #0
- sta (addr),y
- // }
- rts
-}
-// Set the cursor to the specified position
-// void gotoxy(char x, __register(X) char y)
-gotoxy: {
- .label __6 = $25
- .label line_offset = $25
- // if(y>CONIO_HEIGHT)
- lda.z conio_screen_height
- stx.z $ff
- cmp.z $ff
- bcs __b1
- ldx #0
- __b1:
- // if(x>=CONIO_WIDTH)
- lda.z conio_screen_width
- // conio_cursor_x[conio_screen_layer] = x
- lda #0
- ldy.z conio_screen_layer
- sta conio_cursor_x,y
- // conio_cursor_y[conio_screen_layer] = y
- txa
- sta conio_cursor_y,y
- // unsigned int line_offset = (unsigned int)y << conio_rowshift
- txa
- sta.z __6
- lda #0
- sta.z __6+1
- ldy.z conio_rowshift
- beq !e+
- !:
- asl.z line_offset
- rol.z line_offset+1
- dey
- bne !-
- !e:
- // conio_line_text[conio_screen_layer] = line_offset
- lda.z conio_screen_layer
- asl
- tay
- lda.z line_offset
- sta conio_line_text,y
- lda.z line_offset+1
- sta conio_line_text+1,y
- // }
- rts
-}
-// Get the text and back color for text output in 16 color mode.
-// - layer: Value of 0 or 1.
-// - return: an 8 bit value with bit 7:4 containing the back color and bit 3:0 containing the front color.
-// This will only work when the VERA is in 16 color mode!
-// Note that on the VERA, the transparent color has value 0.
-// __register(A) char vera_layer_get_color(__register(X) char layer)
-vera_layer_get_color: {
- .label addr = 6
- // byte* addr = vera_layer_config[layer]
- txa
- asl
- tay
- lda vera_layer_config,y
- sta.z addr
- lda vera_layer_config+1,y
- sta.z addr+1
- // *addr & VERA_LAYER_CONFIG_256C
- lda #VERA_LAYER_CONFIG_256C
- ldy #0
- and (addr),y
- // if( *addr & VERA_LAYER_CONFIG_256C )
- cmp #0
- bne __b1
- // vera_layer_backcolor[layer] << 4
- lda vera_layer_backcolor,x
- asl
- asl
- asl
- asl
- // return ((vera_layer_backcolor[layer] << 4) | vera_layer_textcolor[layer]);
- ora vera_layer_textcolor,x
- // }
- rts
- __b1:
- // return (vera_layer_textcolor[layer]);
- lda vera_layer_textcolor,x
- rts
-}
-// Print a newline
-cputln: {
- .label temp = 6
- // word temp = conio_line_text[conio_screen_layer]
- lda.z conio_screen_layer
- asl
- // TODO: This needs to be optimized! other variations don't compile because of sections not available!
- tay
- lda conio_line_text,y
- sta.z temp
- lda conio_line_text+1,y
- sta.z temp+1
- // temp += conio_rowskip
- clc
- lda.z temp
- adc.z conio_rowskip
- sta.z temp
- lda.z temp+1
- adc.z conio_rowskip+1
- sta.z temp+1
- // conio_line_text[conio_screen_layer] = temp
- lda.z conio_screen_layer
- asl
- tay
- lda.z temp
- sta conio_line_text,y
- lda.z temp+1
- sta conio_line_text+1,y
- // conio_cursor_x[conio_screen_layer] = 0
- lda #0
- ldy.z conio_screen_layer
- sta conio_cursor_x,y
- // conio_cursor_y[conio_screen_layer]++;
- ldx.z conio_screen_layer
- inc conio_cursor_y,x
- // cscroll()
- jsr cscroll
- // }
- rts
-}
-// Copy block of memory (from VRAM to VRAM)
-// Copies the values from the location pointed by src to the location pointed by dest.
-// The method uses the VERA access ports 0 and 1 to copy data from and to in VRAM.
-// - src_bank: 64K VRAM bank number to copy from (0/1).
-// - src: pointer to the location to copy from. Note that the address is a 16 bit value!
-// - src_increment: the increment indicator, VERA needs this because addressing increment is automated by VERA at each access.
-// - dest_bank: 64K VRAM bank number to copy to (0/1).
-// - dest: pointer to the location to copy to. Note that the address is a 16 bit value!
-// - dest_increment: the increment indicator, VERA needs this because addressing increment is automated by VERA at each access.
-// - num: The number of bytes to copy
-// void memcpy_in_vram(__register(Y) char dest_bank, __zp($a) void *dest, char dest_increment, char src_bank, __zp(6) char *src, char src_increment, __zp(8) unsigned int num)
-memcpy_in_vram: {
- .label i = 2
- .label dest = $a
- .label src = 6
- .label num = 8
- // *VERA_CTRL &= ~VERA_ADDRSEL
- // Select DATA0
- lda #VERA_ADDRSEL^$ff
- and VERA_CTRL
- sta VERA_CTRL
- // BYTE0(src)
- lda.z src
- // *VERA_ADDRX_L = BYTE0(src)
- // Set address
- sta VERA_ADDRX_L
- // BYTE1(src)
- lda.z src+1
- // *VERA_ADDRX_M = BYTE1(src)
- sta VERA_ADDRX_M
- // *VERA_ADDRX_H = src_increment | src_bank
- lda #VERA_INC_1
- sta VERA_ADDRX_H
- // *VERA_CTRL |= VERA_ADDRSEL
- // Select DATA1
- lda #VERA_ADDRSEL
- ora VERA_CTRL
- sta VERA_CTRL
- // BYTE0(dest)
- lda.z dest
- // *VERA_ADDRX_L = BYTE0(dest)
- // Set address
- sta VERA_ADDRX_L
- // BYTE1(dest)
- lda.z dest+1
- // *VERA_ADDRX_M = BYTE1(dest)
- sta VERA_ADDRX_M
- // dest_increment | dest_bank
- tya
- ora #VERA_INC_1
- // *VERA_ADDRX_H = dest_increment | dest_bank
- sta VERA_ADDRX_H
- lda #<0
- sta.z i
- sta.z i+1
- // Transfer the data
- __b1:
- // for(unsigned int i=0; i$100
- bne __b1
- lda.z mapwidth
- cmp #<$100
- bne __b1
- // vera_layer_rowshift[layer] = 9
- lda #9
- ldy.z layer
- sta vera_layer_rowshift,y
- // vera_layer_rowskip[layer] = 512
- tya
- asl
- tay
- lda #<$200
- sta vera_layer_rowskip,y
- lda #>$200
- sta vera_layer_rowskip+1,y
- ldx #VERA_LAYER_WIDTH_256
- jmp __b9
- __b1:
- ldx #VERA_LAYER_COLOR_DEPTH_1BPP
- __b9:
- // case 32:
- // config |= VERA_LAYER_HEIGHT_32;
- // break;
- lda.z mapheight+1
- bne !+
- lda.z mapheight
- cmp #$20
- beq __b16
- !:
- // case 64:
- // config |= VERA_LAYER_HEIGHT_64;
- // break;
- lda.z mapheight+1
- bne !+
- lda.z mapheight
- cmp #$40
- bne !__b13+
- jmp __b13
- !__b13:
- !:
- // case 128:
- // config |= VERA_LAYER_HEIGHT_128;
- // break;
- lda.z mapheight+1
- bne !+
- lda.z mapheight
- cmp #$80
- bne !__b14+
- jmp __b14
- !__b14:
- !:
- // case 256:
- // config |= VERA_LAYER_HEIGHT_256;
- // break;
- lda.z mapheight+1
- cmp #>$100
- bne __b16
- lda.z mapheight
- cmp #<$100
- bne __b16
- // config |= VERA_LAYER_HEIGHT_256
- txa
- ora #VERA_LAYER_HEIGHT_256
- tax
- __b16:
- // vera_layer_set_config(layer, config)
- lda.z layer
- jsr vera_layer_set_config
- // WORD0(mapbase_address)
- lda.z mapbase_address
- sta.z __1
- lda.z mapbase_address+1
- sta.z __1+1
- // vera_mapbase_offset[layer] = WORD0(mapbase_address)
- lda.z layer
- asl
- sta.z __17
- // mapbase
- tay
- lda.z __1
- sta vera_mapbase_offset,y
- lda.z __1+1
- sta vera_mapbase_offset+1,y
- // BYTE2(mapbase_address)
- lda.z mapbase_address+2
- // vera_mapbase_bank[layer] = BYTE2(mapbase_address)
- ldy.z layer
- sta vera_mapbase_bank,y
- // vera_mapbase_address[layer] = mapbase_address
- tya
- asl
- asl
- sta.z __18
- tay
- lda.z mapbase_address
- sta vera_mapbase_address,y
- lda.z mapbase_address+1
- sta vera_mapbase_address+1,y
- lda.z mapbase_address+2
- sta vera_mapbase_address+2,y
- lda.z mapbase_address+3
- sta vera_mapbase_address+3,y
- // mapbase_address = mapbase_address >> 1
- lsr.z mapbase_address+3
- ror.z mapbase_address+2
- ror.z mapbase_address+1
- ror.z mapbase_address
- // byte mapbase = BYTE1(mapbase_address)
- ldx.z mapbase_address+1
- // vera_layer_set_mapbase(layer,mapbase)
- lda.z layer
- jsr vera_layer_set_mapbase
- // WORD0(tilebase_address)
- lda.z tilebase_address
- sta.z __6
- lda.z tilebase_address+1
- sta.z __6+1
- // vera_tilebase_offset[layer] = WORD0(tilebase_address)
- // tilebase
- ldy.z __17
- lda.z __6
- sta vera_tilebase_offset,y
- lda.z __6+1
- sta vera_tilebase_offset+1,y
- // BYTE2(tilebase_address)
- lda.z tilebase_address+2
- // vera_tilebase_bank[layer] = BYTE2(tilebase_address)
- ldy.z layer
- sta vera_tilebase_bank,y
- // vera_tilebase_address[layer] = tilebase_address
- ldy.z __18
- lda.z tilebase_address
- sta vera_tilebase_address,y
- lda.z tilebase_address+1
- sta vera_tilebase_address+1,y
- lda.z tilebase_address+2
- sta vera_tilebase_address+2,y
- lda.z tilebase_address+3
- sta vera_tilebase_address+3,y
- // tilebase_address = tilebase_address >> 1
- lsr.z tilebase_address+3
- ror.z tilebase_address+2
- ror.z tilebase_address+1
- ror.z tilebase_address
- // byte tilebase = BYTE1(tilebase_address)
- lda.z tilebase_address+1
- // tilebase &= VERA_LAYER_TILEBASE_MASK
- and #VERA_LAYER_TILEBASE_MASK
- tax
- // case 8:
- // tilebase |= VERA_TILEBASE_WIDTH_8;
- // break;
- lda #8
- cmp.z tilewidth
- beq __b19
- // case 16:
- // tilebase |= VERA_TILEBASE_WIDTH_16;
- // break;
- lda #$10
- cmp.z tilewidth
- bne __b19
- // tilebase |= VERA_TILEBASE_WIDTH_16
- txa
- ora #VERA_TILEBASE_WIDTH_16
- tax
- __b19:
- // case 8:
- // tilebase |= VERA_TILEBASE_HEIGHT_8;
- // break;
- lda #8
- cmp.z tileheight
- beq __b22
- // case 16:
- // tilebase |= VERA_TILEBASE_HEIGHT_16;
- // break;
- lda #$10
- cmp.z tileheight
- bne __b22
- // tilebase |= VERA_TILEBASE_HEIGHT_16
- txa
- ora #VERA_TILEBASE_HEIGHT_16
- tax
- __b22:
- // vera_layer_set_tilebase(layer,tilebase)
- lda.z layer
- jsr vera_layer_set_tilebase
- // }
- rts
- __b14:
- // config |= VERA_LAYER_HEIGHT_128
- txa
- ora #VERA_LAYER_HEIGHT_128
- tax
- jmp __b16
- __b13:
- // config |= VERA_LAYER_HEIGHT_64
- txa
- ora #VERA_LAYER_HEIGHT_64
- tax
- jmp __b16
- __b7:
- // vera_layer_rowshift[layer] = 8
- lda #8
- ldy.z layer
- sta vera_layer_rowshift,y
- // vera_layer_rowskip[layer] = 256
- tya
- asl
- tay
- lda #<$100
- sta vera_layer_rowskip,y
- lda #>$100
- sta vera_layer_rowskip+1,y
- ldx #VERA_LAYER_WIDTH_128
- jmp __b9
- __b6:
- // vera_layer_rowshift[layer] = 7
- lda #7
- ldy.z layer
- sta vera_layer_rowshift,y
- // vera_layer_rowskip[layer] = 128
- tya
- asl
- tay
- lda #$80
- sta vera_layer_rowskip,y
- lda #0
- sta vera_layer_rowskip+1,y
- ldx #VERA_LAYER_WIDTH_64
- jmp __b9
- __b5:
- // vera_layer_rowshift[layer] = 6
- lda #6
- ldy.z layer
- sta vera_layer_rowshift,y
- // vera_layer_rowskip[layer] = 64
- tya
- asl
- tay
- lda #$40
- sta vera_layer_rowskip,y
- lda #0
- sta vera_layer_rowskip+1,y
- jmp __b1
-}
-// Set a vera layer in bitmap mode and configure the:
-// - layer: Value of 0 or 1.
-// - mapbase_address: A dword typed address (4 bytes), that specifies the full address of the map base.
-// The function does the translation from the dword that contains the 17 bit address,
-// to the respective mapbase vera register.
-// Note that the register only specifies bits 16:9 of the address,
-// so the resulting address in the VERA VRAM is always aligned to a multiple of 512 bytes.
-// - tilebase_address: A dword typed address (4 bytes), that specifies the base address of the tile map.
-// The function does the translation from the dword that contains the 17 bit address,
-// to the respective tilebase vera register.
-// Note that the resulting vera register holds only specifies bits 16:11 of the address,
-// so the resulting address in the VERA VRAM is always aligned to a multiple of 2048 bytes!
-// - mapwidth: The width of the map in number of tiles.
-// - mapheight: The height of the map in number of tiles.
-// - tilewidth: The width of a tile, which can be 8 or 16 pixels.
-// - tileheight: The height of a tile, which can be 8 or 16 pixels.
-// - color_mode: The color mode, which can be 16 or 256.
-// void vera_layer_mode_bitmap(char layer, unsigned long bitmap_address, unsigned int mapwidth, unsigned int color_depth)
-vera_layer_mode_bitmap: {
- .const layer = 0
- .const bitmap_address = 0
- // config
- .const config = VERA_LAYER_COLOR_DEPTH_8BPP|VERA_LAYER_CONFIG_MODE_BITMAP
- .const tilebase = 0
- // vera_tilebase_offset[layer] = WORD0(bitmap_address)
- // tilebase
- lda #<0
- sta vera_tilebase_offset
- sta vera_tilebase_offset+1
- // vera_tilebase_bank[layer] = BYTE2(bitmap_address)
- sta vera_tilebase_bank
- // vera_tilebase_address[layer] = bitmap_address
- lda #