1
0
mirror of https://gitlab.com/camelot/kickc.git synced 2025-04-21 11:42:30 +00:00

Added support for all new addressing modes used in CPU's 65C02, 65CE02 and 45GS02.

This commit is contained in:
jespergravgaard 2020-07-28 19:05:58 +02:00
parent a8b5929adf
commit a454ee2cdd
29 changed files with 882 additions and 216 deletions

View File

@ -11,21 +11,24 @@ public enum AsmAddressingMode {
* on the accumulator"
*/
NON("", "%i", 1),
/**
* Immediate
* #imm Immediate <br>
* IMMEDIATE ADDRESSING In immediate addressing, the operand is contained in the second byte of the instruction,
* with no further memory addressing required.
*/
IMM("#imm", "%i #%p", 2),
/**
* Zeropage
* zp Zeropage <br>
* ZERO PAGE ADDRESSING The zero page instructions allow for shorter code and execution times by only fetching the
* second byte of the instruction and assuming a zero high address byte. Careful use of the zero page can result in
* significant increase in code efficiency.
*/
ZP("zp", "%i.z %p", 2),
/**
* X Indexed Zeropage
* zp,x X Indexed Zeropage <br>
* INDEXED ZERO PAGE ADDRESSING - (X, Y indexing) This form of addressing is used in conjunction with the index
* register and is referred to as Zero Page, X" or "Zero Page, Y. The effective address is calculated by adding the
* second byte to the contents of the index register. Since this is a form of "Zero Page" addressing, the content of
@ -33,8 +36,9 @@ public enum AsmAddressingMode {
* mode, no carry is added to the high order 8 bits of memory and crossing of page boundaries does not occur.
*/
ZPX("zp,x", "%i.z %p,x", 2),
/**
* Y Indexed Zeropage
* zp,y Y Indexed Zeropage <br>
* INDEXED ZERO PAGE ADDRESSING - (X, Y indexing) This form of addressing is used in coniunction with the index
* register and is referred to as Zero Page, X" or "Zero Page, Y. The effective address is calculated by adding
* the second byte to the contents of the index register. Since this is a form of "Zero Page" addressing, the content
@ -42,15 +46,17 @@ public enum AsmAddressingMode {
* this mode, no carry is added to the high order 8 bits of memory and crossing of page boundaries does not occur.
*/
ZPY("zp,y", "%i.z %p,y", 2),
/**
* Absolute
* abs Absolute <br>
* ABSOLUTE ADDRESSING In absolute addressing, the second byte of the instruction specifies the eight low order
* bits of the effective address while the third byte specifies the eight high order bits. Thus, the absolute
* addressing mode allows access to the entire 65 K bytes of addressable memory.
*/
ABS("abs", "%i %p", 3),
/**
* Absolute X
* abs,x Absolute X <br>
* INDEX ABSOLUTE ADDRESSING (X, Y indexing) This form of addressing is used in conjunction with X and Y index
* register and is referred to as "Absolute. X," and Absolute. Y." The effective address is formed by adding the
* contents of X and Y to the address contained in the second and third bytes of the instruction. This mode allows
@ -59,8 +65,9 @@ public enum AsmAddressingMode {
* and execution time.
*/
ABX("abs,x", "%i %p,x", 3),
/**
* Absolute Y
* abs,y Absolute Y <br>
* INDEX ABSOLUTE ADDRESSING (X, Y indexing) This form of addressing is used in conjunction with X and Y index
* register and is referred to as "Absolute. X," and Absolute. Y." The effective address is formed by adding the
* contents of X and Y to the address contained in the second and third bytes of the instruction. This mode allows the
@ -69,9 +76,10 @@ public enum AsmAddressingMode {
* execution time.
*/
ABY("abs,y", "%i %p,y", 4),
/**
* Indirect Zeropage X
* INDEXED INDIRECT ADDRESSING - In indexed indirect addressing (referred to as [Indirect, X]), the second byte of
* (zp,x) Indirect Zeropage X <br>
* INDEXED INDIRECT ZEROPAGE ADDRESSING - In indexed indirect addressing (referred to as (Indirect, X)), the second byte of
* the instruction is added to the contents of the.X index register, discarding the carry. The result of this
* addition points to a memory
* location on page zero whose contents is the low order eight bits of the effective address. The next memory
@ -79,32 +87,96 @@ public enum AsmAddressingMode {
* specifying the high and low order bytes of the effective address must be in page zero."
*/
IZX("(zp,x)", "%i (%p,x)", 2),
/**
* Indirect Zeropage Y
* INDIRECT INDEXED ADDRESSING In indirect indexed addressing (referred to as (Indirect, Y]), the second byte of
* (abs,x) Indirect Absolute X <br>
* "ABSOLUTE INDEXED INDIRECT
* With the Absolute Indexed Indirect addressing mode, the X Index Register is added to the second and third bytes of
* the instruction to form an address to a pointer. This address mode is only used with the JMP/JSR instruction and the
* program Counter is loaded with the first and second bytes at this pointer."
*/
IAX("(abs,x)", "%i (%p,x)", 3),
/**
* (zp),y Indirect Zeropage Y
* INDIRECT INDEXED ADDRESSING In indirect indexed addressing (referred to as (Indirect),Y ), the second byte of
* the instruction points to a memory location in page zero. The contents of this memory location is added to the
* contents of the Y index register, the result being the low order eight bits of the effective
* address. The carry from this addition is added to the contents of the next page zero memory location, the result
* being the high order eight bits of the effective address."
*/
IZY("(zp),y", "%i (%p),y", 2),
/**
* Relative
* RELATIVE ADDRESSING Relative addressing is used only with branch instructions and establishes a destination for
* the conditional branch. The second byte of-the instruction becomes the operand which is an Offset"" added to the
* contents of the lower eight bits of the program counter when the counter is set at the next instruction. The range
* of the offset is 128 to + 127 bytes from the next instruction."
* (zp),z Indirect Zeropage Z <br>
* INDIRECT INDEXED ADDRESSING In indirect indexed addressing (referred to as (Indirect),Z ), the second byte of
* the instruction points to a memory location in page zero. The contents of this memory location is added to the
* contents of the Y index register, the result being the low order eight bits of the effective
* address. The carry from this addition is added to the contents of the next page zero memory location, the result
* being the high order eight bits of the effective address."
*/
REL("rel", "%i %p", 2),
IZZ("(zp),z", "%i.z (%p),z", 2),
/**
* Indirect Absolute
* (abs) Indirect Absolute <br>
* ABSOLUTE INDIRECT The second byte of the instruction contains the low order eight bits of a memory location.
* The high order eight bits of that memory location is contained in the third byte of the instruction.
* The contents of the fully specified memory location is the low order byte of the effective address.
* The next memory location contains the high order byte of the effective address which is loaded into the sixteen
* bits of the program counter.
*/
IND("(ind)", "%i (%p)", 3);
IND("(abs)", "%i (%p)", 3),
/**
* (zp) Indirect Zeropage <br>
* ZEROPAGE INDIRECT
* The second byte of the instruction contains address of a zeropage memory location.
*/
INZ("(zp)", "%i.z (%p)", 2),
/**
* ((zp)) 32-bit Indirect Zeropage <br>
* 32BIT ZEROPAGE INDIRECT ADDRESSING
* In indirect addressing the second byte of the instruction points to a memory location in page zero. This mode is
* formed by preceding a Base Page Indirect Mode instruction with NEG NEG NOP instructions.
*/
LIN("((zp))", "%i.z ((%p))", 2),
/**
* ((zp)),z 32-bit Indirect Zeropage Z <br>
* 32BIT INDIRECT INDEXED ADDRESSING
* In indirect indexed addressing the second byte of the instruction points to a memory location in page zero. This
* mode is formed by preceding a Base Page Indirect Z-Indexed Mode instruction with the NOP instruction (opcode $EA).
*/
LIZ("((zp)),z", "%i.z ((%p)),z", 2),
/**
* (zp,sp),y Stack Pointer Indirect Indexed <br>
* STACK POINTER INDIRECT INDEXED - This new mode is similar to indirect indexed addressing. The Stack replaces
* the Base Page and the second instruction byte specifies the displacement from the current stack pointer location
* rather than the location within Base Page. The contents of this displaced stack location are added to the contents
* of the Y index register, the result becomes the low order eight bits ot the effective address. The carry from this
* addition is added to the contents of the next (D -1) stack location the result being the high order eight bits of
* the effective address." STA ($12,SP),Y
*/
ISY("(zp,sp),y", "%i.z (%p,sp),y", 2),
/**
* Relative <br>
* RELATIVE ADDRESSING Relative addressing is used only with branch instructions and establishes a destination for
* the conditional branch. The second byte of-the instruction becomes the operand which is an Offset"" added to the
* contents of the lower eight bits of the program counter when the counter is set at the next instruction. The range
* of the offset is 128 to + 127 bytes from the next instruction."
*/
REL("rel", "%i %p", 2),
/**
* zp,rel Zeropage Test Relative
* ZEROPAGE TEST RELATIVE. It needs two one-byte operands, one for the zero page address that is used for the bit
* test, and one indicating the signed relative PC offset if the branch is taken. This makes BBRi and BBSi the single
* instructions with two explicit operands.
*/
REZ("zp,rel", "%i %p,%q", 3);
/** The short name of the addressing mode. */
private String name;
@ -129,10 +201,22 @@ public enum AsmAddressingMode {
return name;
}
public String getAsm(String mnemnonic, String parameter) {
/**
* Get the printed ASM code for the instruction with an operand value.
* This prints to the syntax that KickAssembler expects.
*
* @param mnemnonic The opcode mnemonic
* @param operand The operand value. Null if addressing mode is Implied/A/None
* @param operand2 The second operand value (only used for addressing mode Zeropage Test Relative)
* @return The printed ASM code for the instruction
*/
public String getAsm(String mnemnonic, String operand, String operand2) {
String replaced = template.replace("%i", mnemnonic);
if(parameter != null) {
replaced = replaced.replace("%p", parameter);
if(operand != null) {
replaced = replaced.replace("%p", operand);
}
if(operand2 != null) {
replaced = replaced.replace("%q", operand2);
}
return replaced;
}

View File

@ -329,7 +329,14 @@ public class AsmInstructionSet {
if(AsmAddressingMode.ABY.equals(mode) && isZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.ZPY);
}
if(AsmAddressingMode.IND.equals(mode) && isZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.INZ);
}
if(AsmAddressingMode.IAX.equals(mode) && isZp) {
asmOpcode = set.getOpcode(mnemonic, AsmAddressingMode.IZX);
}
if(asmOpcode == null) {
// If the ZP-variation does not exist use the ABS-variation
asmOpcode = set.getOpcode(mnemonic, mode);
}
if(asmOpcode == null && AsmAddressingMode.ABS.equals(mode)) {

View File

@ -24,7 +24,7 @@ public class AsmOpcode {
private final double cycles;
/** Which registers/flags of the CPU are clobbered by the instruction. */
private AsmClobber clobber;
private final AsmClobber clobber;
AsmOpcode(int opcode, String mnemonic, AsmAddressingMode addressingMode, double cycles, String clobberString) {
this.opcode = new int[]{opcode};
@ -85,22 +85,24 @@ public class AsmOpcode {
/**
* Determines if this instruction has a specific single byte opcode
*
* @param opcode The byte opcode to check
* @return true if this instruction has a 1-byte opcode that matches the passed value.
*/
public boolean hasOpcode(int opcode) {
return this.opcode.length==1 && this.opcode[0]==(byte)opcode;
return this.opcode.length == 1 && this.opcode[0] == (byte) opcode;
}
/**
* Get the printed ASM code for the instruction with an operand value.
* This prints to the syntax that KickAssembler expects.
*
* @param operand The operand value
* @param operand The operand value. Null if addressing mode is Implied/A/None
* @param operand2 The second operand value (only used for addressing mode Zeropage Test Relative)
* @return The printed ASM code for the instruction
*/
public String getAsm(String operand) {
return addressingMode.getAsm(mnemonic, operand);
public String getAsm(String operand, String operand2) {
return addressingMode.getAsm(mnemonic, operand, operand2);
}
/**
@ -123,13 +125,4 @@ public class AsmOpcode {
return clobber.isRegisterPC();
}
/**
* Set the clobber information of the opcode.
* TODO: Remove this setter and initialize using the constructor instead.
* @param asmClobber The new clobber information
*/
public void setClobber(AsmClobber asmClobber) {
this.clobber = asmClobber;
}
}

View File

@ -7,29 +7,53 @@ import dk.camelot64.kickc.model.InternalError;
/** A specific assembler instruction line (opcode, addressing mode and specific parameter value) */
public class AsmInstruction implements AsmLine {
/** The instruction opcode. */
private AsmOpcode asmOpcode;
private String parameter;
/** The ASM opcode parameter. Null if the opcode addressing mode is Implied/A/None {@link AsmAddressingMode#NON} - eg. DEX */
private String operand1;
/** The second ASM opcode parameter. Null if not used. Only used for addressing mode Zeropage Test Relative {@link AsmAddressingMode#REZ} - eg. BBR0 $12,label */
private String operand2;
/** The index of the instruction in the program. */
private int index;
/** If true the instruction will not be optimized away. */
private boolean dontOptimize;
public AsmInstruction(AsmOpcode asmOpcode, String parameter) {
public AsmInstruction(AsmOpcode asmOpcode) {
this.asmOpcode = asmOpcode;
this.parameter = parameter;
if(AsmAddressingMode.NON.equals(asmOpcode.getAddressingMode()) && parameter != null)
throw new InternalError("Opcode with NON paramter cannot have a parameter");
this.operand1 = null;
this.operand2 = null;
}
public String getParameter() {
return parameter;
public AsmInstruction(AsmOpcode asmOpcode, String operand1) {
this.asmOpcode = asmOpcode;
this.operand1 = operand1;
this.operand2 = null;
}
public void setParameter(String parameter) {
if(AsmAddressingMode.NON.equals(asmOpcode.getAddressingMode()) && parameter != null)
throw new InternalError("Opcode with NON paramter cannot have a parameter");
this.parameter = parameter;
public AsmInstruction(AsmOpcode asmOpcode, String operand1, String operand2) {
this.asmOpcode = asmOpcode;
this.operand1 = operand1;
this.operand2 = operand2;
}
public String getOperand1() {
return operand1;
}
public void setOperand1(String operand1) {
this.operand1 = operand1;
}
public String getOperand2() {
return operand2;
}
public void setOperand2(String operand2) {
this.operand2 = operand2;
}
public AsmOpcode getAsmOpcode() {
@ -52,7 +76,7 @@ public class AsmInstruction implements AsmLine {
@Override
public String getAsm() {
return asmOpcode.getAsm(parameter);
return asmOpcode.getAsm(operand1, operand2);
}
@Override
@ -77,4 +101,44 @@ public class AsmInstruction implements AsmLine {
public void setDontOptimize(boolean dontOptimize) {
this.dontOptimize = dontOptimize;
}
}
/***
* Get the operand value that represents a jump target (if the opcode is a jump as defined by {@link AsmOpcode#isJump()}
* @return The jump target operand
*/
public String getOperandJumpTarget() {
if(asmOpcode.isJump()) {
if(AsmAddressingMode.REZ.equals(asmOpcode.getAddressingMode())) {
// For addressing mode Zeropage Test Relative the jump target is operand2: bbr0 zp,rel
return operand2;
} else {
// For all other jump addressing modes jump target is operand1
return operand1;
}
} else
// Not a jump
return null;
}
/***
* Set the operand value that represents a jump target (if the opcode is a jump as defined by {@link AsmOpcode#isJump()}
* @param operand The new jump target operand
*/
public void setOperandJumpTarget(String operand) {
if(asmOpcode.isJump()) {
if(AsmAddressingMode.REZ.equals(asmOpcode.getAddressingMode())) {
// For addressing mode Zeropage Test Relative the jump target is operand2: bbr0 zp,rel
operand2 = operand;
} else {
// For all other jump addressing modes jump target is operand1
operand1 = operand;
}
} else {
throw new InternalError("Error! Instruction is not a jump "+getAsm());
}
}
}

View File

@ -119,7 +119,7 @@ public class AsmProgramStaticRegisterValues {
String mnemnonic = asmOpcode.getMnemonic();
AsmAddressingMode addressingMode = asmOpcode.getAddressingMode();
if((mnemnonic.equals("inc") || mnemnonic.equals("dec") || mnemnonic.equals("ror") || mnemnonic.equals("rol") || mnemnonic.equals("lsr") || mnemnonic.equals("asl")) && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
String modParam = instruction.getParameter();
String modParam = instruction.getOperand1();
if(current.getaMem() != null && current.getaMem().equals(modParam)) {
current.setaMem(null);
}
@ -131,57 +131,57 @@ public class AsmProgramStaticRegisterValues {
}
}
if(mnemnonic.equals("lda") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setA(instruction.getParameter());
current.setA(instruction.getOperand1());
current.setaMem(null);
Integer immValue = getImmValue(instruction.getParameter());
Integer immValue = getImmValue(instruction.getOperand1());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("lda") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
current.setaMem(instruction.getOperand1());
current.setA(null);
}
if(mnemnonic.equals("sta") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setaMem(instruction.getParameter());
if(instruction.getParameter().equals(current.getyMem())) current.setyMem(null);
if(instruction.getParameter().equals(current.getxMem())) current.setxMem(null);
current.setaMem(instruction.getOperand1());
if(instruction.getOperand1().equals(current.getyMem())) current.setyMem(null);
if(instruction.getOperand1().equals(current.getxMem())) current.setxMem(null);
}
if(mnemnonic.equals("ldx") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setX(instruction.getParameter());
current.setX(instruction.getOperand1());
current.setxMem(null);
Integer immValue = getImmValue(instruction.getParameter());
Integer immValue = getImmValue(instruction.getOperand1());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("ldx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
current.setxMem(instruction.getOperand1());
current.setX(null);
}
if(mnemnonic.equals("stx") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setxMem(instruction.getParameter());
if(instruction.getParameter().equals(current.getyMem())) current.setyMem(null);
if(instruction.getParameter().equals(current.getaMem())) current.setaMem(null);
current.setxMem(instruction.getOperand1());
if(instruction.getOperand1().equals(current.getyMem())) current.setyMem(null);
if(instruction.getOperand1().equals(current.getaMem())) current.setaMem(null);
}
if(mnemnonic.equals("ldy") && addressingMode.equals(AsmAddressingMode.IMM)) {
current.setY(instruction.getParameter());
current.setY(instruction.getOperand1());
current.setyMem(null);
Integer immValue = getImmValue(instruction.getParameter());
Integer immValue = getImmValue(instruction.getOperand1());
if(immValue != null) {
current.setZ(immValue == 0);
current.setN(immValue > 127);
}
}
if(mnemnonic.equals("ldy") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
current.setyMem(instruction.getOperand1());
}
if(mnemnonic.equals("sty") && (addressingMode.equals(AsmAddressingMode.ZP) || addressingMode.equals(AsmAddressingMode.ABS))) {
current.setyMem(instruction.getParameter());
if(instruction.getParameter().equals(current.getxMem())) current.setxMem(null);
if(instruction.getParameter().equals(current.getaMem())) current.setaMem(null);
current.setyMem(instruction.getOperand1());
if(instruction.getOperand1().equals(current.getxMem())) current.setxMem(null);
if(instruction.getOperand1().equals(current.getaMem())) current.setaMem(null);
}
if(mnemnonic.equals("txa")) {
current.setA(current.getX());

View File

@ -227,50 +227,63 @@ public class AsmFragmentInstance {
KickCParser.AsmParamModeContext paramModeCtx = ctx.asmParamMode();
AsmInstruction instruction;
if(paramModeCtx == null) {
final String mnemonic = ctx.ASM_MNEMONIC().getText();
AsmOpcode asmOpcode = AsmInstructionSet.getOpcode(mnemonic, AsmAddressingMode.NON, false);
if(asmOpcode == null) {
throw new InternalError("Error in " + name + ".asm line " + ctx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + AsmAddressingMode.NON);
}
instruction = new AsmInstruction(asmOpcode, null);
instruction = createAsmInstruction(ctx, null, null,AsmAddressingMode.NON);
} else {
instruction = (AsmInstruction) this.visit(paramModeCtx);
}
if(instruction != null) {
program.addLine(instruction);
} else {
throw new RuntimeException("Error parsing ASM fragment line in dk/camelot64/kickc/fragment/asm/" + name + ".asm\n - Line: " + ctx.getText());
throw new RuntimeException("Error parsing ASM fragment line " + name + ".asm\n - Line: " + ctx.getText());
}
return null;
}
@Override
public Object visitAsmModeAbs(KickCParser.AsmModeAbsContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABS);
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.ABS);
}
@Override
public Object visitAsmModeImm(KickCParser.AsmModeImmContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IMM);
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.IMM);
}
@Override
public Object visitAsmModeAbsXY(KickCParser.AsmModeAbsXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if(xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABX);
} else if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.ABY);
final KickCParser.AsmExprContext indexCtx = ctx.asmExpr(1);
if(indexCtx instanceof KickCParser.AsmExprLabelContext) {
final String xy = ((KickCParser.AsmExprLabelContext) indexCtx).ASM_NAME().getText();
if(xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(0), null,AsmAddressingMode.ABX);
} else if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(0), null,AsmAddressingMode.ABY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
} else {
// Test Relative Addressing Mode (2 parameters)
return createAsmInstruction(ctx, ctx.asmExpr(0), ctx.asmExpr(1), AsmAddressingMode.REZ);
}
}
@Override
public Object visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) {
String xy = ctx.ASM_NAME().getText();
if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.IZY);
} else if(xy.equals("z")) {
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.IZZ);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
if(xy.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZY);
public Object visitAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx) {
String xy = ctx.ASM_NAME().getText();
if(xy.equals("z")) {
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.LIZ);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
@ -278,9 +291,20 @@ public class AsmFragmentInstance {
@Override
public Object visitAsmModeIdxIndXY(KickCParser.AsmModeIdxIndXYContext ctx) {
String xy = ctx.getChild(ctx.getChildCount() - 1).getText();
String xy = ctx.ASM_NAME().getText();
if(xy.equals("x")) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IZX);
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.IAX);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
}
@Override
public Object visitAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx) {
String sp = ctx.ASM_NAME(0).getText();
String y = ctx.ASM_NAME(1).getText();
if(sp.equals("sp") && y.equals("y")) {
return createAsmInstruction(ctx, ctx.asmExpr(), null,AsmAddressingMode.ISY);
} else {
throw new RuntimeException("Unknown addressing mode " + ctx.getText());
}
@ -288,21 +312,39 @@ public class AsmFragmentInstance {
@Override
public Object visitAsmModeInd(KickCParser.AsmModeIndContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), AsmAddressingMode.IND);
return createAsmInstruction(ctx, ctx.asmExpr(), null, AsmAddressingMode.IND);
}
@Override
public Object visitAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx) {
return createAsmInstruction(ctx, ctx.asmExpr(), null, AsmAddressingMode.LIN);
}
private AsmInstruction createAsmInstruction(
KickCParser.AsmParamModeContext ctx,
KickCParser.AsmExprContext exprCtx,
KickCParser.AsmParamModeContext paramModeCtx,
KickCParser.AsmExprContext operand1Ctx,
KickCParser.AsmExprContext operand2Ctx,
AsmAddressingMode addressingMode) {
return createAsmInstruction((KickCParser.AsmInstructionContext) paramModeCtx.getParent(), operand1Ctx, operand2Ctx, addressingMode);
}
private AsmInstruction createAsmInstruction(
KickCParser.AsmInstructionContext instructionCtx,
KickCParser.AsmExprContext operand1Ctx,
KickCParser.AsmExprContext operand2Ctx,
AsmAddressingMode addressingMode) {
KickCParser.AsmInstructionContext instructionCtx = (KickCParser.AsmInstructionContext) ctx.getParent();
AsmParameter parameter = (AsmParameter) this.visit(exprCtx);
String mnemonic = instructionCtx.ASM_MNEMONIC().getSymbol().getText();
AsmOpcode asmOpcode = AsmInstructionSet.getOpcode(mnemonic, addressingMode, parameter.isZp());
AsmParameter param1 = operand1Ctx == null ? null : (AsmParameter) this.visit(operand1Ctx);
AsmParameter param2 = operand2Ctx == null ? null : (AsmParameter) this.visit(operand2Ctx);
// Convert to ZP-addressing mode if possible
boolean isZp = param1 != null && param1.isZp();
AsmOpcode asmOpcode = AsmInstructionSet.getOpcode(mnemonic, addressingMode, isZp);
String operand1 = param1 == null ? null : param1.getParam();
String operand2 = param2 == null ? null : param2.getParam();
if(asmOpcode == null) {
throw new InternalError("Error in " + name + ".asm line " + instructionCtx.getStart().getLine() + " - Instruction type unknown " + mnemonic + " " + addressingMode + " " + parameter);
throw new InternalError("Error in " + name + ".asm line " + instructionCtx.getStart().getLine() + " - Instruction type not supported " + addressingMode.getAsm(mnemonic, operand1, operand2));
}
return new AsmInstruction(asmOpcode, parameter.getParam());
return new AsmInstruction(asmOpcode, operand1, operand2);
}
@Override

View File

@ -301,10 +301,13 @@ asmBytes
asmParamMode
: asmExpr #asmModeAbs
| ASM_IMM asmExpr #asmModeImm
| asmExpr ASM_COMMA ASM_NAME #asmModeAbsXY
| asmExpr ASM_COMMA asmExpr #asmModeAbsXY
| ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_COMMA ASM_NAME #asmModeIndIdxXY
| ASM_PAR_BEGIN ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_PAR_END ASM_COMMA ASM_NAME #asmModeIndLongIdxXY
| ASM_PAR_BEGIN asmExpr ASM_COMMA ASM_NAME ASM_PAR_END ASM_COMMA ASM_NAME #asmModeSPIndIdx
| ASM_PAR_BEGIN asmExpr ASM_COMMA ASM_NAME ASM_PAR_END #asmModeIdxIndXY
| ASM_PAR_BEGIN asmExpr ASM_PAR_END #asmModeInd
| ASM_PAR_BEGIN ASM_PAR_BEGIN asmExpr ASM_PAR_END ASM_PAR_END #asmModeIndLong
;
asmExpr

File diff suppressed because one or more lines are too long

View File

@ -6719,12 +6719,70 @@ public class KickCParser extends Parser {
else return visitor.visitChildren(this);
}
}
public static class AsmModeAbsXYContext extends AsmParamModeContext {
public static class AsmModeSPIndIdxContext extends AsmParamModeContext {
public TerminalNode ASM_PAR_BEGIN() { return getToken(KickCParser.ASM_PAR_BEGIN, 0); }
public AsmExprContext asmExpr() {
return getRuleContext(AsmExprContext.class,0);
}
public List<TerminalNode> ASM_COMMA() { return getTokens(KickCParser.ASM_COMMA); }
public TerminalNode ASM_COMMA(int i) {
return getToken(KickCParser.ASM_COMMA, i);
}
public List<TerminalNode> ASM_NAME() { return getTokens(KickCParser.ASM_NAME); }
public TerminalNode ASM_NAME(int i) {
return getToken(KickCParser.ASM_NAME, i);
}
public TerminalNode ASM_PAR_END() { return getToken(KickCParser.ASM_PAR_END, 0); }
public AsmModeSPIndIdxContext(AsmParamModeContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).enterAsmModeSPIndIdx(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).exitAsmModeSPIndIdx(this);
}
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof KickCParserVisitor ) return ((KickCParserVisitor<? extends T>)visitor).visitAsmModeSPIndIdx(this);
else return visitor.visitChildren(this);
}
}
public static class AsmModeIndLongContext extends AsmParamModeContext {
public List<TerminalNode> ASM_PAR_BEGIN() { return getTokens(KickCParser.ASM_PAR_BEGIN); }
public TerminalNode ASM_PAR_BEGIN(int i) {
return getToken(KickCParser.ASM_PAR_BEGIN, i);
}
public AsmExprContext asmExpr() {
return getRuleContext(AsmExprContext.class,0);
}
public List<TerminalNode> ASM_PAR_END() { return getTokens(KickCParser.ASM_PAR_END); }
public TerminalNode ASM_PAR_END(int i) {
return getToken(KickCParser.ASM_PAR_END, i);
}
public AsmModeIndLongContext(AsmParamModeContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).enterAsmModeIndLong(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).exitAsmModeIndLong(this);
}
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof KickCParserVisitor ) return ((KickCParserVisitor<? extends T>)visitor).visitAsmModeIndLong(this);
else return visitor.visitChildren(this);
}
}
public static class AsmModeAbsXYContext extends AsmParamModeContext {
public List<AsmExprContext> asmExpr() {
return getRuleContexts(AsmExprContext.class);
}
public AsmExprContext asmExpr(int i) {
return getRuleContext(AsmExprContext.class,i);
}
public TerminalNode ASM_COMMA() { return getToken(KickCParser.ASM_COMMA, 0); }
public TerminalNode ASM_NAME() { return getToken(KickCParser.ASM_NAME, 0); }
public AsmModeAbsXYContext(AsmParamModeContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
@ -6740,6 +6798,35 @@ public class KickCParser extends Parser {
else return visitor.visitChildren(this);
}
}
public static class AsmModeIndLongIdxXYContext extends AsmParamModeContext {
public List<TerminalNode> ASM_PAR_BEGIN() { return getTokens(KickCParser.ASM_PAR_BEGIN); }
public TerminalNode ASM_PAR_BEGIN(int i) {
return getToken(KickCParser.ASM_PAR_BEGIN, i);
}
public AsmExprContext asmExpr() {
return getRuleContext(AsmExprContext.class,0);
}
public List<TerminalNode> ASM_PAR_END() { return getTokens(KickCParser.ASM_PAR_END); }
public TerminalNode ASM_PAR_END(int i) {
return getToken(KickCParser.ASM_PAR_END, i);
}
public TerminalNode ASM_COMMA() { return getToken(KickCParser.ASM_COMMA, 0); }
public TerminalNode ASM_NAME() { return getToken(KickCParser.ASM_NAME, 0); }
public AsmModeIndLongIdxXYContext(AsmParamModeContext ctx) { copyFrom(ctx); }
@Override
public void enterRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).enterAsmModeIndLongIdxXY(this);
}
@Override
public void exitRule(ParseTreeListener listener) {
if ( listener instanceof KickCParserListener ) ((KickCParserListener)listener).exitAsmModeIndLongIdxXY(this);
}
@Override
public <T> T accept(ParseTreeVisitor<? extends T> visitor) {
if ( visitor instanceof KickCParserVisitor ) return ((KickCParserVisitor<? extends T>)visitor).visitAsmModeIndLongIdxXY(this);
else return visitor.visitChildren(this);
}
}
public static class AsmModeIdxIndXYContext extends AsmParamModeContext {
public TerminalNode ASM_PAR_BEGIN() { return getToken(KickCParser.ASM_PAR_BEGIN, 0); }
public AsmExprContext asmExpr() {
@ -6831,7 +6918,7 @@ public class KickCParser extends Parser {
AsmParamModeContext _localctx = new AsmParamModeContext(_ctx, getState());
enterRule(_localctx, 90, RULE_asmParamMode);
try {
setState(864);
setState(886);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,84,_ctx) ) {
case 1:
@ -6861,7 +6948,7 @@ public class KickCParser extends Parser {
setState(845);
match(ASM_COMMA);
setState(846);
match(ASM_NAME);
asmExpr(0);
}
break;
case 4:
@ -6881,30 +6968,86 @@ public class KickCParser extends Parser {
}
break;
case 5:
_localctx = new AsmModeIdxIndXYContext(_localctx);
_localctx = new AsmModeIndLongIdxXYContext(_localctx);
enterOuterAlt(_localctx, 5);
{
setState(854);
match(ASM_PAR_BEGIN);
setState(855);
asmExpr(0);
match(ASM_PAR_BEGIN);
setState(856);
match(ASM_COMMA);
asmExpr(0);
setState(857);
match(ASM_NAME);
match(ASM_PAR_END);
setState(858);
match(ASM_PAR_END);
setState(859);
match(ASM_COMMA);
setState(860);
match(ASM_NAME);
}
break;
case 6:
_localctx = new AsmModeIndContext(_localctx);
_localctx = new AsmModeSPIndIdxContext(_localctx);
enterOuterAlt(_localctx, 6);
{
setState(860);
match(ASM_PAR_BEGIN);
setState(861);
asmExpr(0);
setState(862);
match(ASM_PAR_BEGIN);
setState(863);
asmExpr(0);
setState(864);
match(ASM_COMMA);
setState(865);
match(ASM_NAME);
setState(866);
match(ASM_PAR_END);
setState(867);
match(ASM_COMMA);
setState(868);
match(ASM_NAME);
}
break;
case 7:
_localctx = new AsmModeIdxIndXYContext(_localctx);
enterOuterAlt(_localctx, 7);
{
setState(870);
match(ASM_PAR_BEGIN);
setState(871);
asmExpr(0);
setState(872);
match(ASM_COMMA);
setState(873);
match(ASM_NAME);
setState(874);
match(ASM_PAR_END);
}
break;
case 8:
_localctx = new AsmModeIndContext(_localctx);
enterOuterAlt(_localctx, 8);
{
setState(876);
match(ASM_PAR_BEGIN);
setState(877);
asmExpr(0);
setState(878);
match(ASM_PAR_END);
}
break;
case 9:
_localctx = new AsmModeIndLongContext(_localctx);
enterOuterAlt(_localctx, 9);
{
setState(880);
match(ASM_PAR_BEGIN);
setState(881);
match(ASM_PAR_BEGIN);
setState(882);
asmExpr(0);
setState(883);
match(ASM_PAR_END);
setState(884);
match(ASM_PAR_END);
}
break;
@ -7109,7 +7252,7 @@ public class KickCParser extends Parser {
int _alt;
enterOuterAlt(_localctx, 1);
{
setState(880);
setState(902);
_errHandler.sync(this);
switch (_input.LA(1)) {
case ASM_BRACKET_BEGIN:
@ -7118,11 +7261,11 @@ public class KickCParser extends Parser {
_ctx = _localctx;
_prevctx = _localctx;
setState(867);
setState(889);
match(ASM_BRACKET_BEGIN);
setState(868);
setState(890);
asmExpr(0);
setState(869);
setState(891);
match(ASM_BRACKET_END);
}
break;
@ -7134,7 +7277,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprUnaryContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(871);
setState(893);
_la = _input.LA(1);
if ( !(((((_la - 137)) & ~0x3f) == 0 && ((1L << (_la - 137)) & ((1L << (ASM_PLUS - 137)) | (1L << (ASM_MINUS - 137)) | (1L << (ASM_LESS_THAN - 137)) | (1L << (ASM_GREATER_THAN - 137)))) != 0)) ) {
_errHandler.recoverInline(this);
@ -7144,7 +7287,7 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
setState(872);
setState(894);
asmExpr(8);
}
break;
@ -7153,7 +7296,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprLabelContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(873);
setState(895);
match(ASM_NAME);
}
break;
@ -7162,7 +7305,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprLabelRelContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(874);
setState(896);
match(ASM_MULTI_REL);
}
break;
@ -7171,11 +7314,11 @@ public class KickCParser extends Parser {
_localctx = new AsmExprReplaceContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(875);
setState(897);
match(ASM_CURLY_BEGIN);
setState(876);
setState(898);
match(ASM_NAME);
setState(877);
setState(899);
match(ASM_CURLY_END);
}
break;
@ -7184,7 +7327,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprIntContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(878);
setState(900);
match(ASM_NUMBER);
}
break;
@ -7193,7 +7336,7 @@ public class KickCParser extends Parser {
_localctx = new AsmExprCharContext(_localctx);
_ctx = _localctx;
_prevctx = _localctx;
setState(879);
setState(901);
match(ASM_CHAR);
}
break;
@ -7201,7 +7344,7 @@ public class KickCParser extends Parser {
throw new NoViableAltException(this);
}
_ctx.stop = _input.LT(-1);
setState(896);
setState(918);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,87,_ctx);
while ( _alt!=2 && _alt!=org.antlr.v4.runtime.atn.ATN.INVALID_ALT_NUMBER ) {
@ -7209,20 +7352,20 @@ public class KickCParser extends Parser {
if ( _parseListeners!=null ) triggerExitRuleEvent();
_prevctx = _localctx;
{
setState(894);
setState(916);
_errHandler.sync(this);
switch ( getInterpreter().adaptivePredict(_input,86,_ctx) ) {
case 1:
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
setState(882);
setState(904);
if (!(precpred(_ctx, 10))) throw new FailedPredicateException(this, "precpred(_ctx, 10)");
{
setState(883);
setState(905);
match(ASM_DOT);
}
setState(884);
setState(906);
asmExpr(11);
}
break;
@ -7230,9 +7373,9 @@ public class KickCParser extends Parser {
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
setState(885);
setState(907);
if (!(precpred(_ctx, 9))) throw new FailedPredicateException(this, "precpred(_ctx, 9)");
setState(886);
setState(908);
_la = _input.LA(1);
if ( !(_la==ASM_SHIFT_LEFT || _la==ASM_SHIFT_RIGHT) ) {
_errHandler.recoverInline(this);
@ -7242,7 +7385,7 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
setState(887);
setState(909);
asmExpr(10);
}
break;
@ -7250,9 +7393,9 @@ public class KickCParser extends Parser {
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
setState(888);
setState(910);
if (!(precpred(_ctx, 7))) throw new FailedPredicateException(this, "precpred(_ctx, 7)");
setState(889);
setState(911);
_la = _input.LA(1);
if ( !(_la==ASM_MULTIPLY || _la==ASM_DIVIDE) ) {
_errHandler.recoverInline(this);
@ -7262,7 +7405,7 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
setState(890);
setState(912);
asmExpr(8);
}
break;
@ -7270,9 +7413,9 @@ public class KickCParser extends Parser {
{
_localctx = new AsmExprBinaryContext(new AsmExprContext(_parentctx, _parentState));
pushNewRecursionContext(_localctx, _startState, RULE_asmExpr);
setState(891);
setState(913);
if (!(precpred(_ctx, 6))) throw new FailedPredicateException(this, "precpred(_ctx, 6)");
setState(892);
setState(914);
_la = _input.LA(1);
if ( !(_la==ASM_PLUS || _la==ASM_MINUS) ) {
_errHandler.recoverInline(this);
@ -7282,14 +7425,14 @@ public class KickCParser extends Parser {
_errHandler.reportMatch(this);
consume();
}
setState(893);
setState(915);
asmExpr(7);
}
break;
}
}
}
setState(898);
setState(920);
_errHandler.sync(this);
_alt = getInterpreter().adaptivePredict(_input,87,_ctx);
}
@ -7418,7 +7561,7 @@ public class KickCParser extends Parser {
}
public static final String _serializedATN =
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\u00a7\u0386\4\2\t"+
"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3\u00a7\u039c\4\2\t"+
"\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13"+
"\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22"+
"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31\t\31"+
@ -7480,24 +7623,25 @@ public class KickCParser extends Parser {
"\n(\f(\16(\u031e\13(\3(\3(\3)\3)\3)\3)\3)\3)\3)\3)\3)\3)\5)\u032c\n)\3"+
"*\7*\u032f\n*\f*\16*\u0332\13*\3+\3+\3+\5+\u0337\n+\3,\3,\3,\3,\5,\u033d"+
"\n,\3-\3-\5-\u0341\n-\3.\3.\3.\3.\7.\u0347\n.\f.\16.\u034a\13.\3/\3/\3"+
"/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\5/\u0363"+
"\n/\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3"+
"\60\5\60\u0373\n\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60"+
"\3\60\3\60\7\60\u0381\n\60\f\60\16\60\u0384\13\60\3\60\2\t\f\30\32&FH"+
"^\61\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@"+
"BDFHJLNPRTVXZ\\^\2\r\3\2\27\30\5\2\22\23\31\32^^\4\2!!$$\3\2\35\36\3\2"+
"\24\26\3\2\22\23\3\2\37$\3\2\u008b\u008e\3\2\u0089\u008a\3\2\u008f\u0090"+
"\3\2\u008b\u008c\2\u0409\2`\3\2\2\2\4c\3\2\2\2\6i\3\2\2\2\bz\3\2\2\2\n"+
"|\3\2\2\2\f\177\3\2\2\2\16\u0096\3\2\2\2\20\u00bb\3\2\2\2\22\u00c0\3\2"+
"\2\2\24\u00ca\3\2\2\2\26\u00d1\3\2\2\2\30\u00d7\3\2\2\2\32\u00f6\3\2\2"+
"\2\34\u0106\3\2\2\2\36\u0109\3\2\2\2 \u0115\3\2\2\2\"\u0118\3\2\2\2$\u011b"+
"/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3"+
"/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\3/\5/\u0379\n"+
"/\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60"+
"\5\60\u0389\n\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60"+
"\3\60\7\60\u0397\n\60\f\60\16\60\u039a\13\60\3\60\2\t\f\30\32&FH^\61\2"+
"\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668:<>@BDFHJL"+
"NPRTVXZ\\^\2\r\3\2\27\30\5\2\22\23\31\32^^\4\2!!$$\3\2\35\36\3\2\24\26"+
"\3\2\22\23\3\2\37$\3\2\u008b\u008e\3\2\u0089\u008a\3\2\u008f\u0090\3\2"+
"\u008b\u008c\2\u0422\2`\3\2\2\2\4c\3\2\2\2\6i\3\2\2\2\bz\3\2\2\2\n|\3"+
"\2\2\2\f\177\3\2\2\2\16\u0096\3\2\2\2\20\u00bb\3\2\2\2\22\u00c0\3\2\2"+
"\2\24\u00ca\3\2\2\2\26\u00d1\3\2\2\2\30\u00d7\3\2\2\2\32\u00f6\3\2\2\2"+
"\34\u0106\3\2\2\2\36\u0109\3\2\2\2 \u0115\3\2\2\2\"\u0118\3\2\2\2$\u011b"+
"\3\2\2\2&\u0123\3\2\2\2(\u012e\3\2\2\2*\u0133\3\2\2\2,\u0144\3\2\2\2."+
"\u014a\3\2\2\2\60\u015d\3\2\2\2\62\u01b6\3\2\2\2\64\u01b8\3\2\2\2\66\u01e9"+
"\3\2\2\28\u01ec\3\2\2\2:\u0245\3\2\2\2<\u0248\3\2\2\2>\u0253\3\2\2\2@"+
"\u0271\3\2\2\2B\u0277\3\2\2\2D\u0279\3\2\2\2F\u027b\3\2\2\2H\u02c7\3\2"+
"\2\2J\u0308\3\2\2\2L\u0310\3\2\2\2N\u0316\3\2\2\2P\u032b\3\2\2\2R\u0330"+
"\3\2\2\2T\u0336\3\2\2\2V\u033c\3\2\2\2X\u033e\3\2\2\2Z\u0342\3\2\2\2\\"+
"\u0362\3\2\2\2^\u0372\3\2\2\2`a\5\6\4\2ab\7\2\2\3b\3\3\2\2\2cd\5R*\2d"+
"\u0378\3\2\2\2^\u0388\3\2\2\2`a\5\6\4\2ab\7\2\2\3b\3\3\2\2\2cd\5R*\2d"+
"e\7\2\2\3e\5\3\2\2\2fh\5\b\5\2gf\3\2\2\2hk\3\2\2\2ig\3\2\2\2ij\3\2\2\2"+
"j\7\3\2\2\2ki\3\2\2\2lm\5\n\6\2mn\7\n\2\2n{\3\2\2\2op\5\36\20\2pq\7\n"+
"\2\2q{\3\2\2\2rs\5$\23\2st\7\n\2\2t{\3\2\2\2u{\5*\26\2v{\5\62\32\2wx\5"+
@ -7745,36 +7889,44 @@ public class KickCParser extends Parser {
"\u033f\3\2\2\2\u0340\u0341\3\2\2\2\u0341Y\3\2\2\2\u0342\u0343\7\177\2"+
"\2\u0343\u0348\5^\60\2\u0344\u0345\7\u0083\2\2\u0345\u0347\5^\60\2\u0346"+
"\u0344\3\2\2\2\u0347\u034a\3\2\2\2\u0348\u0346\3\2\2\2\u0348\u0349\3\2"+
"\2\2\u0349[\3\2\2\2\u034a\u0348\3\2\2\2\u034b\u0363\5^\60\2\u034c\u034d"+
"\7\u0081\2\2\u034d\u0363\5^\60\2\u034e\u034f\5^\60\2\u034f\u0350\7\u0083"+
"\2\2\u0350\u0351\7\u009f\2\2\u0351\u0363\3\2\2\2\u0352\u0353\7\u0084\2"+
"\2\u0353\u0354\5^\60\2\u0354\u0355\7\u0085\2\2\u0355\u0356\7\u0083\2\2"+
"\u0356\u0357\7\u009f\2\2\u0357\u0363\3\2\2\2\u0358\u0359\7\u0084\2\2\u0359"+
"\u035a\5^\60\2\u035a\u035b\7\u0083\2\2\u035b\u035c\7\u009f\2\2\u035c\u035d"+
"\7\u0085\2\2\u035d\u0363\3\2\2\2\u035e\u035f\7\u0084\2\2\u035f\u0360\5"+
"^\60\2\u0360\u0361\7\u0085\2\2\u0361\u0363\3\2\2\2\u0362\u034b\3\2\2\2"+
"\u0362\u034c\3\2\2\2\u0362\u034e\3\2\2\2\u0362\u0352\3\2\2\2\u0362\u0358"+
"\3\2\2\2\u0362\u035e\3\2\2\2\u0363]\3\2\2\2\u0364\u0365\b\60\1\2\u0365"+
"\u0366\7\u0086\2\2\u0366\u0367\5^\60\2\u0367\u0368\7\u0087\2\2\u0368\u0373"+
"\3\2\2\2\u0369\u036a\t\t\2\2\u036a\u0373\5^\60\n\u036b\u0373\7\u009f\2"+
"\2\u036c\u0373\7\u009d\2\2\u036d\u036e\7\u0091\2\2\u036e\u036f\7\u009f"+
"\2\2\u036f\u0373\7\u0092\2\2\u0370\u0373\7\u0093\2\2\u0371\u0373\7\u009c"+
"\2\2\u0372\u0364\3\2\2\2\u0372\u0369\3\2\2\2\u0372\u036b\3\2\2\2\u0372"+
"\u036c\3\2\2\2\u0372\u036d\3\2\2\2\u0372\u0370\3\2\2\2\u0372\u0371\3\2"+
"\2\2\u0373\u0382\3\2\2\2\u0374\u0375\f\f\2\2\u0375\u0376\7\u0088\2\2\u0376"+
"\u0381\5^\60\r\u0377\u0378\f\13\2\2\u0378\u0379\t\n\2\2\u0379\u0381\5"+
"^\60\f\u037a\u037b\f\t\2\2\u037b\u037c\t\13\2\2\u037c\u0381\5^\60\n\u037d"+
"\u037e\f\b\2\2\u037e\u037f\t\f\2\2\u037f\u0381\5^\60\t\u0380\u0374\3\2"+
"\2\2\u0380\u0377\3\2\2\2\u0380\u037a\3\2\2\2\u0380\u037d\3\2\2\2\u0381"+
"\u0384\3\2\2\2\u0382\u0380\3\2\2\2\u0382\u0383\3\2\2\2\u0383_\3\2\2\2"+
"\u0384\u0382\3\2\2\2Ziz\u0083\u008d\u0093\u009b\u00a2\u00ab\u00b0\u00b6"+
"\u00bb\u00c0\u00c7\u00ce\u00d3\u00df\u00e2\u00e4\u00ef\u00f6\u00fb\u0101"+
"\u0103\u010b\u0111\u011d\u012b\u0131\u0137\u013d\u0142\u0146\u014f\u0156"+
"\u015d\u0186\u01b2\u01b6\u01bb\u01c6\u01da\u01e3\u01e9\u01ee\u01f5\u0202"+
"\u0207\u0213\u0221\u0234\u023d\u0245\u024a\u024f\u0251\u0257\u025c\u0260"+
"\u0266\u0269\u0271\u0274\u0277\u0283\u028f\u0297\u029d\u02a1\u02b6\u02ba"+
"\u02c3\u02c7\u02f9\u0303\u0305\u030d\u0312\u031c\u032b\u0330\u0336\u033c"+
"\u0340\u0348\u0362\u0372\u0380\u0382";
"\2\2\u0349[\3\2\2\2\u034a\u0348\3\2\2\2\u034b\u0379\5^\60\2\u034c\u034d"+
"\7\u0081\2\2\u034d\u0379\5^\60\2\u034e\u034f\5^\60\2\u034f\u0350\7\u0083"+
"\2\2\u0350\u0351\5^\60\2\u0351\u0379\3\2\2\2\u0352\u0353\7\u0084\2\2\u0353"+
"\u0354\5^\60\2\u0354\u0355\7\u0085\2\2\u0355\u0356\7\u0083\2\2\u0356\u0357"+
"\7\u009f\2\2\u0357\u0379\3\2\2\2\u0358\u0359\7\u0084\2\2\u0359\u035a\7"+
"\u0084\2\2\u035a\u035b\5^\60\2\u035b\u035c\7\u0085\2\2\u035c\u035d\7\u0085"+
"\2\2\u035d\u035e\7\u0083\2\2\u035e\u035f\7\u009f\2\2\u035f\u0379\3\2\2"+
"\2\u0360\u0361\7\u0084\2\2\u0361\u0362\5^\60\2\u0362\u0363\7\u0083\2\2"+
"\u0363\u0364\7\u009f\2\2\u0364\u0365\7\u0085\2\2\u0365\u0366\7\u0083\2"+
"\2\u0366\u0367\7\u009f\2\2\u0367\u0379\3\2\2\2\u0368\u0369\7\u0084\2\2"+
"\u0369\u036a\5^\60\2\u036a\u036b\7\u0083\2\2\u036b\u036c\7\u009f\2\2\u036c"+
"\u036d\7\u0085\2\2\u036d\u0379\3\2\2\2\u036e\u036f\7\u0084\2\2\u036f\u0370"+
"\5^\60\2\u0370\u0371\7\u0085\2\2\u0371\u0379\3\2\2\2\u0372\u0373\7\u0084"+
"\2\2\u0373\u0374\7\u0084\2\2\u0374\u0375\5^\60\2\u0375\u0376\7\u0085\2"+
"\2\u0376\u0377\7\u0085\2\2\u0377\u0379\3\2\2\2\u0378\u034b\3\2\2\2\u0378"+
"\u034c\3\2\2\2\u0378\u034e\3\2\2\2\u0378\u0352\3\2\2\2\u0378\u0358\3\2"+
"\2\2\u0378\u0360\3\2\2\2\u0378\u0368\3\2\2\2\u0378\u036e\3\2\2\2\u0378"+
"\u0372\3\2\2\2\u0379]\3\2\2\2\u037a\u037b\b\60\1\2\u037b\u037c\7\u0086"+
"\2\2\u037c\u037d\5^\60\2\u037d\u037e\7\u0087\2\2\u037e\u0389\3\2\2\2\u037f"+
"\u0380\t\t\2\2\u0380\u0389\5^\60\n\u0381\u0389\7\u009f\2\2\u0382\u0389"+
"\7\u009d\2\2\u0383\u0384\7\u0091\2\2\u0384\u0385\7\u009f\2\2\u0385\u0389"+
"\7\u0092\2\2\u0386\u0389\7\u0093\2\2\u0387\u0389\7\u009c\2\2\u0388\u037a"+
"\3\2\2\2\u0388\u037f\3\2\2\2\u0388\u0381\3\2\2\2\u0388\u0382\3\2\2\2\u0388"+
"\u0383\3\2\2\2\u0388\u0386\3\2\2\2\u0388\u0387\3\2\2\2\u0389\u0398\3\2"+
"\2\2\u038a\u038b\f\f\2\2\u038b\u038c\7\u0088\2\2\u038c\u0397\5^\60\r\u038d"+
"\u038e\f\13\2\2\u038e\u038f\t\n\2\2\u038f\u0397\5^\60\f\u0390\u0391\f"+
"\t\2\2\u0391\u0392\t\13\2\2\u0392\u0397\5^\60\n\u0393\u0394\f\b\2\2\u0394"+
"\u0395\t\f\2\2\u0395\u0397\5^\60\t\u0396\u038a\3\2\2\2\u0396\u038d\3\2"+
"\2\2\u0396\u0390\3\2\2\2\u0396\u0393\3\2\2\2\u0397\u039a\3\2\2\2\u0398"+
"\u0396\3\2\2\2\u0398\u0399\3\2\2\2\u0399_\3\2\2\2\u039a\u0398\3\2\2\2"+
"Ziz\u0083\u008d\u0093\u009b\u00a2\u00ab\u00b0\u00b6\u00bb\u00c0\u00c7"+
"\u00ce\u00d3\u00df\u00e2\u00e4\u00ef\u00f6\u00fb\u0101\u0103\u010b\u0111"+
"\u011d\u012b\u0131\u0137\u013d\u0142\u0146\u014f\u0156\u015d\u0186\u01b2"+
"\u01b6\u01bb\u01c6\u01da\u01e3\u01e9\u01ee\u01f5\u0202\u0207\u0213\u0221"+
"\u0234\u023d\u0245\u024a\u024f\u0251\u0257\u025c\u0260\u0266\u0269\u0271"+
"\u0274\u0277\u0283\u028f\u0297\u029d\u02a1\u02b6\u02ba\u02c3\u02c7\u02f9"+
"\u0303\u0305\u030d\u0312\u031c\u032b\u0330\u0336\u033c\u0340\u0348\u0378"+
"\u0388\u0396\u0398";
public static final ATN _ATN =
new ATNDeserializer().deserialize(_serializedATN.toCharArray());
static {

View File

@ -1609,6 +1609,30 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx) { }
/**
* {@inheritDoc}
*
@ -1633,6 +1657,18 @@ public class KickCParserBaseListener implements KickCParserListener {
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAsmModeInd(KickCParser.AsmModeIndContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void enterAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx) { }
/**
* {@inheritDoc}
*
* <p>The default implementation does nothing.</p>
*/
@Override public void exitAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx) { }
/**
* {@inheritDoc}
*

View File

@ -944,6 +944,20 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
@ -958,6 +972,13 @@ public class KickCParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> imple
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAsmModeInd(KickCParser.AsmModeIndContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*
* <p>The default implementation returns the result of calling
* {@link #visitChildren} on {@code ctx}.</p>
*/
@Override public T visitAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx) { return visitChildren(ctx); }
/**
* {@inheritDoc}
*

View File

@ -1541,6 +1541,30 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx);
/**
* Enter a parse tree produced by the {@code asmModeIndLongIdxXY}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void enterAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx);
/**
* Exit a parse tree produced by the {@code asmModeIndLongIdxXY}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void exitAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx);
/**
* Enter a parse tree produced by the {@code asmModeSPIndIdx}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void enterAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx);
/**
* Exit a parse tree produced by the {@code asmModeSPIndIdx}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void exitAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx);
/**
* Enter a parse tree produced by the {@code asmModeIdxIndXY}
* labeled alternative in {@link KickCParser#asmParamMode}.
@ -1565,6 +1589,18 @@ public interface KickCParserListener extends ParseTreeListener {
* @param ctx the parse tree
*/
void exitAsmModeInd(KickCParser.AsmModeIndContext ctx);
/**
* Enter a parse tree produced by the {@code asmModeIndLong}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void enterAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx);
/**
* Exit a parse tree produced by the {@code asmModeIndLong}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
*/
void exitAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx);
/**
* Enter a parse tree produced by the {@code asmExprReplace}
* labeled alternative in {@link KickCParser#asmExpr}.

View File

@ -911,6 +911,20 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitAsmModeIndIdxXY(KickCParser.AsmModeIndIdxXYContext ctx);
/**
* Visit a parse tree produced by the {@code asmModeIndLongIdxXY}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAsmModeIndLongIdxXY(KickCParser.AsmModeIndLongIdxXYContext ctx);
/**
* Visit a parse tree produced by the {@code asmModeSPIndIdx}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAsmModeSPIndIdx(KickCParser.AsmModeSPIndIdxContext ctx);
/**
* Visit a parse tree produced by the {@code asmModeIdxIndXY}
* labeled alternative in {@link KickCParser#asmParamMode}.
@ -925,6 +939,13 @@ public interface KickCParserVisitor<T> extends ParseTreeVisitor<T> {
* @return the visitor result
*/
T visitAsmModeInd(KickCParser.AsmModeIndContext ctx);
/**
* Visit a parse tree produced by the {@code asmModeIndLong}
* labeled alternative in {@link KickCParser#asmParamMode}.
* @param ctx the parse tree
* @return the visitor result
*/
T visitAsmModeIndLong(KickCParser.AsmModeIndLongContext ctx);
/**
* Visit a parse tree produced by the {@code asmExprReplace}
* labeled alternative in {@link KickCParser#asmExpr}.

View File

@ -1743,6 +1743,9 @@ public class Pass0GenerateStatementSequence extends KickCParserBaseVisitor<Objec
@Override
public Void visitAsmExprLabel(KickCParser.AsmExprLabelContext ctxLabel) {
String label = ctxLabel.ASM_NAME().toString();
if(label.equalsIgnoreCase("x") || label.equalsIgnoreCase("y") || label.equalsIgnoreCase("z")|| label.equalsIgnoreCase("sp"))
// Skip registers
return super.visitAsmExprLabel(ctxLabel);
if(!definedLabels.contains(label)) {
// Look for the symbol
Symbol symbol = getCurrentScope().findSymbol(ctxLabel.ASM_NAME().getText());

View File

@ -28,7 +28,7 @@ public class Pass5AddMainRts extends Pass5AsmOptimization {
if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getAsmOpcode().getMnemonic().equals("jsr")) {
if(instruction.getParameter().equals(SymbolRef.MAIN_PROC_NAME)) {
if(instruction.getOperand1().equals(SymbolRef.MAIN_PROC_NAME)) {
// Add RTS if it is missing
if(!lineIterator.hasNext()) {
addRts(lineIterator);

View File

@ -45,7 +45,7 @@ public class Pass5DoubleJumpElimination extends Pass5AsmOptimization {
AsmOpcode jmpOpcode = AsmInstructionSet.getOpcode("jmp", AsmAddressingMode.ABS, false);
AsmOpcode rtsOpcode = AsmInstructionSet.getOpcode("rts", AsmAddressingMode.NON, false);
if(asmInstruction.getAsmOpcode().equals(jmpOpcode)) {
immediateJumps.put(currentScope + "::" + currentLabel, asmInstruction.getParameter());
immediateJumps.put(currentScope + "::" + currentLabel, asmInstruction.getOperand1());
}
if(asmInstruction.getAsmOpcode().equals(rtsOpcode)) {
immediateJumps.put(currentScope + "::" + currentLabel, "rts");
@ -68,16 +68,17 @@ public class Pass5DoubleJumpElimination extends Pass5AsmOptimization {
} else if(line instanceof AsmInstruction) {
AsmInstruction asmInstruction = (AsmInstruction) line;
if(asmInstruction.getAsmOpcode().isJump()) {
String immediateJmpTarget = immediateJumps.get(currentScope + "::" + asmInstruction.getParameter());
if(immediateJmpTarget == "rts" && asmInstruction.getAsmOpcode().getMnemonic() == "jmp") {
String jumpTarget = immediateJumps.get(currentScope + "::" + asmInstruction.getOperandJumpTarget());
if(jumpTarget == "rts" && asmInstruction.getAsmOpcode().getMnemonic() == "jmp") {
getLog().append("Replacing jump to rts with rts in " + asmInstruction.toString());
AsmOpcode rtsOpcode = AsmInstructionSet.getOpcode("rts", AsmAddressingMode.NON, false);
asmInstruction.setAsmOpcode(rtsOpcode);
asmInstruction.setParameter(null);
asmInstruction.setOperand1(null);
asmInstruction.setOperand2(null);
optimized = true;
} else if(immediateJmpTarget != null && immediateJmpTarget != "rts" && !immediateJmpTarget.equals(asmInstruction.getParameter())) {
getLog().append("Skipping double jump to " + immediateJmpTarget + " in " + asmInstruction.toString());
asmInstruction.setParameter(immediateJmpTarget);
} else if(jumpTarget != null && jumpTarget != "rts" && !jumpTarget.equals(asmInstruction.getOperandJumpTarget())) {
getLog().append("Skipping double jump to " + jumpTarget + " in " + asmInstruction.toString());
asmInstruction.setOperandJumpTarget(jumpTarget);
optimized = true;
}
}

View File

@ -157,7 +157,7 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
if(asmChunk != null) {
//getLog().append("Found ASM chunk "+asmChunk);
AsmLine asmLine = asmChunk.getAsmLine(idx);
if(asmLine != null && asmLine instanceof AsmInstruction) {
if(asmLine instanceof AsmInstruction) {
//getLog().append("Found ASM line "+asmLine);
AsmInstruction asmInstruction = (AsmInstruction) asmLine;
AsmOpcode asmOpcode = asmInstruction.getAsmOpcode();
@ -165,10 +165,10 @@ public class Pass5FixLongBranches extends Pass5AsmOptimization {
if(inverseAsmOpcode != null) {
//getLog().append("Inversed branch instruction "+asmInstructionType.getMnemnonic()+" -> "+inverseType.getMnemnonic());
getLog().append("Fixing long branch [" + idx + "] " + asmLine.toString() + " to " + inverseAsmOpcode.getMnemonic());
String branchDest = asmInstruction.getParameter();
String branchDest = asmInstruction.getOperandJumpTarget();
asmInstruction.setAsmOpcode(inverseAsmOpcode);
String newLabel = AsmFormat.asmFix("!" + branchDest);
asmInstruction.setParameter(newLabel+"+");
asmInstruction.setOperandJumpTarget(newLabel+"+");
AsmOpcode jmpOpcode = AsmInstructionSet.getOpcode("jmp", AsmAddressingMode.ABS, false);
AsmInstruction jmpInstruction = new AsmInstruction(jmpOpcode, branchDest);
asmChunk.addLineAfter(asmInstruction, jmpInstruction);

View File

@ -25,7 +25,7 @@ public class Pass5NextJumpElimination extends Pass5AsmOptimization {
}
if(candidate != null) {
if(line instanceof AsmLabel) {
if(((AsmLabel) line).getLabel().equals(candidate.getParameter())) {
if(((AsmLabel) line).getLabel().equals(candidate.getOperandJumpTarget())) {
removeLines.add(candidate);
}
}

View File

@ -38,12 +38,12 @@ public class Pass5RedundantLabelElimination extends Pass5AsmOptimization {
}
} else if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getAsmOpcode().isJump() && instruction.getParameter()!=null) {
String labelStr = instruction.getParameter();
if(instruction.getAsmOpcode().isJump() && instruction.getOperandJumpTarget()!=null) {
String labelStr = instruction.getOperandJumpTarget();
String labelReplacementStr = getLabelReplacement(redundantLabelSet, currentScope, labelStr);
if(labelReplacementStr!=null) {
getLog().append("Replacing label " + labelStr + " with " + labelReplacementStr);
instruction.setParameter(labelReplacementStr);
instruction.setOperandJumpTarget(labelReplacementStr);
}
}

View File

@ -96,12 +96,12 @@ public class Pass5RelabelLongLabels extends Pass5AsmOptimization {
} else if(asmLine instanceof AsmInstruction) {
AsmInstruction asmInstruction = (AsmInstruction) asmLine;
if(asmInstruction.getAsmOpcode().isJump()) {
String parameter = asmInstruction.getParameter();
String parameter = asmInstruction.getOperandJumpTarget();
Map<String, String> scopeRelabels = relabels.get(currentScope);
if(scopeRelabels != null) {
String newLabel = scopeRelabels.get(parameter);
if(newLabel != null) {
asmInstruction.setParameter(newLabel);
asmInstruction.setOperandJumpTarget(newLabel);
}
}
}

View File

@ -42,7 +42,7 @@ public class Pass5SkipBegin extends Pass5AsmOptimization {
} else if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getAsmOpcode().getMnemonic().equals("jsr")) {
if(instruction.getParameter().equals(SymbolRef.MAIN_PROC_NAME)) {
if(instruction.getOperandJumpTarget().equals(SymbolRef.MAIN_PROC_NAME)) {
lineIterator.remove();
optimized = true;
getLog().append("Removing instruction " + line.getAsm());

View File

@ -36,77 +36,77 @@ public class Pass5UnnecesaryLoadElimination extends Pass5AsmOptimization {
AsmOpcode asmOpcode = instruction.getAsmOpcode();
if(asmOpcode.getMnemonic().equals("lda") && asmOpcode.getAddressingMode().equals(AsmAddressingMode.IMM)) {
String immValue = instruction.getParameter();
String immValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getA(), immValue)) {
modified = remove(lineIt);
} else if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getX(), immValue)) {
getLog().append("Replacing instruction " + instruction + " with TXA");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("txa", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
} else if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getY(), immValue)) {
getLog().append("Replacing instruction " + instruction + " with TYA");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tya", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("lda") && (asmOpcode.getAddressingMode().equals(AsmAddressingMode.ZP) || asmOpcode.getAddressingMode().equals(AsmAddressingMode.ABS))) {
String memValue = instruction.getParameter();
String memValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(instructionValues.getaMem() != null && instructionValues.getaMem().equals(memValue)) {
modified = remove(lineIt);
} else if(instructionValues.getxMem() != null && instructionValues.getxMem().equals(memValue)) {
getLog().append("Replacing instruction " + instruction + " with TXA");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("txa", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
} else if(instructionValues.getyMem() != null && instructionValues.getyMem().equals(memValue)) {
getLog().append("Replacing instruction " + instruction + " with TYA");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tya", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("ldx") && asmOpcode.getAddressingMode().equals(AsmAddressingMode.IMM)) {
String immValue = instruction.getParameter();
String immValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getX(), immValue)) {
modified = remove(lineIt);
} else if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getA(), immValue)) {
getLog().append("Replacing instruction " + instruction + " with TAX");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tax", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("ldx") && (asmOpcode.getAddressingMode().equals(AsmAddressingMode.ZP) || asmOpcode.getAddressingMode().equals(AsmAddressingMode.ABS))) {
String memValue = instruction.getParameter();
String memValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(instructionValues.getxMem() != null && instructionValues.getxMem().equals(memValue)) {
modified = remove(lineIt);
} else if(instructionValues.getaMem() != null && instructionValues.getaMem().equals(memValue)) {
getLog().append("Replacing instruction " + instruction + " with TAX");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tax", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("ldy") && asmOpcode.getAddressingMode().equals(AsmAddressingMode.IMM)) {
String immValue = instruction.getParameter();
String immValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getY(), immValue)) {
modified = remove(lineIt);
} else if(AsmProgramStaticRegisterValues.matchImm(instructionValues.getA(), immValue)) {
getLog().append("Replacing instruction " + instruction + " with TAY");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tay", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("ldy") && (asmOpcode.getAddressingMode().equals(AsmAddressingMode.ZP) || asmOpcode.getAddressingMode().equals(AsmAddressingMode.ABS))) {
String memValue = instruction.getParameter();
String memValue = instruction.getOperand1();
AsmProgramStaticRegisterValues.AsmRegisterValues instructionValues = staticValues.getValues(instruction);
if(instructionValues.getyMem() != null && instructionValues.getyMem().equals(memValue)) {
modified = remove(lineIt);
} else if(instructionValues.getaMem() != null && instructionValues.getaMem().equals(memValue)) {
getLog().append("Replacing instruction " + instruction + " with TAY");
instruction.setAsmOpcode(AsmInstructionSet.getOpcode("tay", AsmAddressingMode.NON, false));
instruction.setParameter(null);
instruction.setOperand1(null);
}
}
if(asmOpcode.getMnemonic().equals("clc")) {

View File

@ -41,8 +41,8 @@ public class Pass5UnusedLabelElimination extends Pass5AsmOptimization {
usedLabels.add(labelStr);
} else if(line instanceof AsmInstruction) {
AsmInstruction instruction = (AsmInstruction) line;
if(instruction.getAsmOpcode().isJump() && instruction.getParameter()!=null) {
String labelStr = currentScope + "::" + instruction.getParameter();
if(instruction.getAsmOpcode().isJump() && instruction.getOperandJumpTarget()!=null) {
String labelStr = currentScope + "::" + instruction.getOperandJumpTarget();
usedLabels.add(labelStr);
}
}

View File

@ -42,6 +42,11 @@ public class TestPrograms {
public TestPrograms() {
}
@Test
public void testAsmAddressingModes() throws IOException, URISyntaxException {
compileAndCompare("asm-addressing-modes.c");
}
@Test
public void testCastingNegative() throws IOException, URISyntaxException {
compileAndCompare("casting-negative.c");

View File

@ -0,0 +1,33 @@
// Tests the different ASM addressing modes
void main() {
asm {
// absolute indexed
lda $12,x
// Indirect
jmp ($1234)
// TODO: Indirect ABS,x
// jmp ($1234,x)
// TODO Indirect Zeropage
//jmp ($12)
// TODO test relative
// lda $12, $1234
// TODO Stack Pointer Indirect Indexed
//lda ($12,sp),y
// TODO Indirect,Z
//lda ($12),z
// TODO Indirect Long,Z
//lda (($12)),z
// TODO Indirect Long
//lda (($12))
}
}

View File

@ -0,0 +1,10 @@
// Tests the different ASM addressing modes
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
main: {
// asm
lda.z $12,x
jmp ($1234)
// }
}

View File

@ -0,0 +1,8 @@
(void()) main()
main: scope:[main] from
asm { lda$12,x jmp($1234) }
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return

View File

@ -0,0 +1,144 @@
CONTROL FLOW GRAPH SSA
(void()) main()
main: scope:[main] from __start
asm { lda$12,x jmp($1234) }
to:main::@return
main::@return: scope:[main] from main
return
to:@return
(void()) __start()
__start: scope:[__start] from
call main
to:__start::@1
__start::@1: scope:[__start] from __start
to:__start::@return
__start::@return: scope:[__start] from __start::@1
return
to:@return
SYMBOL TABLE SSA
(void()) __start()
(label) __start::@1
(label) __start::@return
(void()) main()
(label) main::@return
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
CALL GRAPH
Created 0 initial phi equivalence classes
Coalesced down to 0 phi equivalence classes
FINAL CONTROL FLOW GRAPH
(void()) main()
main: scope:[main] from
asm { lda$12,x jmp($1234) }
to:main::@return
main::@return: scope:[main] from main
[1] return
to:@return
VARIABLE REGISTER WEIGHTS
(void()) main()
Initial phi equivalence classes
Complete equivalence classes
INITIAL ASM
Target platform is c64basic / MOS6502X
// File Comments
// Tests the different ASM addressing modes
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// asm { lda$12,x jmp($1234) }
lda.z $12,x
jmp ($1234)
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
REGISTER UPLIFT POTENTIAL REGISTERS
Statement asm { lda$12,x jmp($1234) } always clobbers reg byte a
REGISTER UPLIFT SCOPES
Uplift Scope [main]
Uplift Scope []
Uplifting [main] best 18 combination
Uplifting [] best 18 combination
ASSEMBLER BEFORE OPTIMIZATION
// File Comments
// Tests the different ASM addressing modes
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// asm { lda$12,x jmp($1234) }
lda.z $12,x
jmp ($1234)
jmp __breturn
// main::@return
__breturn:
// [1] return
rts
}
// File Data
ASSEMBLER OPTIMIZATIONS
Removing instruction jmp __breturn
Succesful ASM optimization Pass5NextJumpElimination
Removing instruction __breturn:
Succesful ASM optimization Pass5UnusedLabelElimination
Removing unreachable instruction rts
Succesful ASM optimization Pass5UnreachableCodeElimination
FINAL SYMBOL TABLE
(void()) main()
(label) main::@return
FINAL ASSEMBLER
Score: 9
// File Comments
// Tests the different ASM addressing modes
// Upstart
.pc = $801 "Basic"
:BasicUpstart(main)
.pc = $80d "Program"
// Global Constants & labels
// main
main: {
// asm
// asm { lda$12,x jmp($1234) }
lda.z $12,x
jmp ($1234)
// main::@return
// }
// [1] return
}
// File Data

View File

@ -0,0 +1,3 @@
(void()) main()
(label) main::@return