mirror of
https://gitlab.com/camelot/kickc.git
synced 2024-11-25 20:32:25 +00:00
Added byte size to test of compatible CPU opcodes.
This commit is contained in:
parent
0f7061bcf0
commit
b7a6412440
@ -10,14 +10,14 @@ public enum CpuAddressingMode {
|
|||||||
* ACCUMULATOR ADDRESSING — This form of addressing is represented with a one byte instruction, implying an operation
|
* ACCUMULATOR ADDRESSING — This form of addressing is represented with a one byte instruction, implying an operation
|
||||||
* on the accumulator"
|
* on the accumulator"
|
||||||
*/
|
*/
|
||||||
NON("", "%i", 1),
|
NON("", "%i", 0),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #imm Immediate <br>
|
* #imm Immediate <br>
|
||||||
* IMMEDIATE ADDRESSING — In immediate addressing, the operand is contained in the second byte of the instruction,
|
* IMMEDIATE ADDRESSING — In immediate addressing, the operand is contained in the second byte of the instruction,
|
||||||
* with no further memory addressing required.
|
* with no further memory addressing required.
|
||||||
*/
|
*/
|
||||||
IMM("#imm", "%i #%p", 2),
|
IMM("#imm", "%i #%p", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zp Zeropage <br>
|
* zp Zeropage <br>
|
||||||
@ -25,7 +25,7 @@ public enum CpuAddressingMode {
|
|||||||
* second byte of the instruction and assuming a zero high address byte. Careful use of the zero page can result in
|
* 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.
|
* significant increase in code efficiency.
|
||||||
*/
|
*/
|
||||||
ZP("zp", "%i.z %p", 2),
|
ZP("zp", "%i.z %p", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zp,x X Indexed Zeropage <br>
|
* zp,x X Indexed Zeropage <br>
|
||||||
@ -35,7 +35,7 @@ public enum CpuAddressingMode {
|
|||||||
* the second byte references a location in page zero. Additionally, due to the “Zero Page" addressing nature of this
|
* the second byte references a location in page zero. Additionally, due to the “Zero Page" addressing nature of this
|
||||||
* mode, no carry is added to the high order 8 bits of memory and crossing of page boundaries does not occur.
|
* 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),
|
ZPX("zp,x", "%i.z %p,x", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zp,y Y Indexed Zeropage <br>
|
* zp,y Y Indexed Zeropage <br>
|
||||||
@ -45,7 +45,7 @@ public enum CpuAddressingMode {
|
|||||||
* of the second byte references a location in page zero. Additionally, due to the “Zero Page" addressing nature of
|
* of the second byte references a location in page zero. Additionally, due to the “Zero Page" addressing nature of
|
||||||
* this mode, no carry is added to the high order 8 bits of memory and crossing of page boundaries does not occur.
|
* 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),
|
ZPY("zp,y", "%i.z %p,y", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* abs Absolute <br>
|
* abs Absolute <br>
|
||||||
@ -53,7 +53,7 @@ public enum CpuAddressingMode {
|
|||||||
* bits of the effective address while the third byte specifies the eight high order bits. Thus, the absolute
|
* 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.
|
* addressing mode allows access to the entire 65 K bytes of addressable memory.
|
||||||
*/
|
*/
|
||||||
ABS("abs", "%i %p", 3),
|
ABS("abs", "%i %p", 2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* abs,x Absolute X <br>
|
* abs,x Absolute X <br>
|
||||||
@ -64,7 +64,7 @@ public enum CpuAddressingMode {
|
|||||||
* of indexing allows any location referencing and the index to modify multiple fields resulting in reduced coding
|
* of indexing allows any location referencing and the index to modify multiple fields resulting in reduced coding
|
||||||
* and execution time.
|
* and execution time.
|
||||||
*/
|
*/
|
||||||
ABX("abs,x", "%i %p,x", 3),
|
ABX("abs,x", "%i %p,x", 2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* abs,y Absolute Y <br>
|
* abs,y Absolute Y <br>
|
||||||
@ -75,7 +75,7 @@ public enum CpuAddressingMode {
|
|||||||
* indexing allows any location referencing and the index to modify multiple fields resulting in reduced coding and
|
* indexing allows any location referencing and the index to modify multiple fields resulting in reduced coding and
|
||||||
* execution time.
|
* execution time.
|
||||||
*/
|
*/
|
||||||
ABY("abs,y", "%i %p,y", 4),
|
ABY("abs,y", "%i %p,y", 2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (zp,x) Indirect Zeropage X <br>
|
* (zp,x) Indirect Zeropage X <br>
|
||||||
@ -86,7 +86,7 @@ public enum CpuAddressingMode {
|
|||||||
* location in page zero contains the high order eight bits of the effective address. Both memory locations
|
* location in page zero contains the high order eight bits of the effective address. Both memory locations
|
||||||
* specifying the high and low order bytes of the effective address must be in page zero."
|
* specifying the high and low order bytes of the effective address must be in page zero."
|
||||||
*/
|
*/
|
||||||
IZX("(zp,x)", "%i (%p,x)", 2),
|
IZX("(zp,x)", "%i (%p,x)", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (abs,x) Indirect Absolute X <br>
|
* (abs,x) Indirect Absolute X <br>
|
||||||
@ -95,7 +95,7 @@ public enum CpuAddressingMode {
|
|||||||
* the instruction to form an address to a pointer. This address mode is only used with the JMP/JSR instruction and the
|
* 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."
|
* program Counter is loaded with the first and second bytes at this pointer."
|
||||||
*/
|
*/
|
||||||
IAX("(abs,x)", "%i (%p,x)", 3),
|
IAX("(abs,x)", "%i (%p,x)", 2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (zp),y Indirect Zeropage Y
|
* (zp),y Indirect Zeropage Y
|
||||||
@ -105,7 +105,7 @@ public enum CpuAddressingMode {
|
|||||||
* address. The carry from this addition is added to the contents of the next page zero memory location, the result
|
* 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."
|
* being the high order eight bits of the effective address."
|
||||||
*/
|
*/
|
||||||
IZY("(zp),y", "%i (%p),y", 2),
|
IZY("(zp),y", "%i (%p),y", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (zp),z Indirect Zeropage Z <br>
|
* (zp),z Indirect Zeropage Z <br>
|
||||||
@ -115,7 +115,7 @@ public enum CpuAddressingMode {
|
|||||||
* address. The carry from this addition is added to the contents of the next page zero memory location, the result
|
* 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."
|
* being the high order eight bits of the effective address."
|
||||||
*/
|
*/
|
||||||
IZZ("(zp),z", "%i.z (%p),z", 2),
|
IZZ("(zp),z", "%i.z (%p),z", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (abs) Indirect Absolute <br>
|
* (abs) Indirect Absolute <br>
|
||||||
@ -125,14 +125,14 @@ public enum CpuAddressingMode {
|
|||||||
* The next memory location contains the high order byte of the effective address which is loaded into the sixteen
|
* The next memory location contains the high order byte of the effective address which is loaded into the sixteen
|
||||||
* bits of the program counter.
|
* bits of the program counter.
|
||||||
*/
|
*/
|
||||||
IND("(abs)", "%i (%p)", 3),
|
IND("(abs)", "%i (%p)", 2),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (zp) Indirect Zeropage <br>
|
* (zp) Indirect Zeropage <br>
|
||||||
* ZEROPAGE INDIRECT
|
* ZEROPAGE INDIRECT
|
||||||
* The second byte of the instruction contains address of a zeropage memory location.
|
* The second byte of the instruction contains address of a zeropage memory location.
|
||||||
*/
|
*/
|
||||||
INZ("(zp)", "%i.z (%p)", 2),
|
INZ("(zp)", "%i.z (%p)", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ((zp)) 32-bit Indirect Zeropage <br>
|
* ((zp)) 32-bit Indirect Zeropage <br>
|
||||||
@ -140,7 +140,7 @@ public enum CpuAddressingMode {
|
|||||||
* In indirect addressing the second byte of the instruction points to a memory location in page zero. This mode is
|
* 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.
|
* formed by preceding a Base Page Indirect Mode instruction with NEG NEG NOP instructions.
|
||||||
*/
|
*/
|
||||||
LIN("((zp))", "%i.z ((%p))", 2),
|
LIN("((zp))", "%i.z ((%p))", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ((zp)),z 32-bit Indirect Zeropage Z <br>
|
* ((zp)),z 32-bit Indirect Zeropage Z <br>
|
||||||
@ -148,7 +148,7 @@ public enum CpuAddressingMode {
|
|||||||
* In indirect indexed addressing the second byte of the instruction points to a memory location in page zero. This
|
* 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).
|
* 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),
|
LIZ("((zp)),z", "%i.z ((%p)),z", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (zp,sp),y Stack Pointer Indirect Indexed <br>
|
* (zp,sp),y Stack Pointer Indirect Indexed <br>
|
||||||
@ -159,7 +159,7 @@ public enum CpuAddressingMode {
|
|||||||
* addition is added to the contents of the next (D -1) stack location the result being the high order eight bits of
|
* 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
|
* the effective address." STA ($12,SP),Y
|
||||||
*/
|
*/
|
||||||
ISY("(zp,sp),y", "%i.z (%p,sp),y", 2),
|
ISY("(zp,sp),y", "%i.z (%p,sp),y", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Relative <br>
|
* Relative <br>
|
||||||
@ -168,7 +168,7 @@ public enum CpuAddressingMode {
|
|||||||
* contents of the lower eight bits of the program counter when the counter is set at the next instruction. The range
|
* 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."
|
* of the offset is — 128 to + 127 bytes from the next instruction."
|
||||||
*/
|
*/
|
||||||
REL("rel", "%i %p", 2),
|
REL("rel", "%i %p", 1),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zp,rel Zeropage Test Relative
|
* zp,rel Zeropage Test Relative
|
||||||
@ -176,7 +176,7 @@ public enum CpuAddressingMode {
|
|||||||
* test, and one indicating the signed relative PC offset if the branch is taken. This makes BBRi and BBSi the single
|
* 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.
|
* instructions with two explicit operands.
|
||||||
*/
|
*/
|
||||||
REZ("zp,rel", "%i %p,%q", 3);
|
REZ("zp,rel", "%i %p,%q", 2);
|
||||||
|
|
||||||
/** The short name of the addressing mode. */
|
/** The short name of the addressing mode. */
|
||||||
private String name;
|
private String name;
|
||||||
@ -184,7 +184,9 @@ public enum CpuAddressingMode {
|
|||||||
/** The template for an instruction using the addressing mode. */
|
/** The template for an instruction using the addressing mode. */
|
||||||
private String template;
|
private String template;
|
||||||
|
|
||||||
/** The number of bytes that an instruction takes up when using the addressing mode. This includes both opcode and operands. */
|
/**
|
||||||
|
* The number of bytes that the operands of the instruction uses. This does not include the bytes used by the opcode.
|
||||||
|
* TODO: This does not take into account word-relative branches and immediate word*/
|
||||||
private int bytes;
|
private int bytes;
|
||||||
|
|
||||||
CpuAddressingMode(String name, String template, int bytes) {
|
CpuAddressingMode(String name, String template, int bytes) {
|
||||||
@ -193,6 +195,12 @@ public enum CpuAddressingMode {
|
|||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of bytes that the operands of the instruction uses. This does not include the bytes used by the opcode.
|
||||||
|
* NOTE: This misreports number of bytes for instructions that use immediate word or long relative.
|
||||||
|
* TODO: This does not take into account word-relative branches and immediate word
|
||||||
|
* @return The number of bytes.
|
||||||
|
*/
|
||||||
public int getBytes() {
|
public int getBytes() {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package dk.camelot64.cpufamily6502;
|
package dk.camelot64.cpufamily6502;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** A specific opcode in the instruction set of a 6502 family CPU. */
|
/** A specific opcode in the instruction set of a 6502 family CPU. */
|
||||||
public class CpuOpcode {
|
public class CpuOpcode {
|
||||||
@ -65,13 +66,18 @@ public class CpuOpcode {
|
|||||||
return cycles;
|
return cycles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Opcodes that use an extra byte for their operand that the addressing mode reports. This is immediate word and long branches.
|
||||||
|
* The format of the string is <code>mnemonic + " " + addressingMode</code> */
|
||||||
|
public static List<String> LONG_MNEMONICS = Arrays.asList("phw #imm", "lbra rel", "lbne rel", "lbeq rel", "lbcc rel", "lbcs rel", "lbmi rel", "lbpl rel", "lbvs rel", "lbvc rel", "lbsr rel" );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of bytes the instruction with operands takes up in memory
|
* Get the number of bytes the instruction with operands takes up in memory
|
||||||
*
|
*
|
||||||
* @return The number of bytes.
|
* @return The number of bytes.
|
||||||
*/
|
*/
|
||||||
public int getBytes() {
|
public int getBytes() {
|
||||||
return addressingMode.getBytes();
|
final int numBytes = opcode.length + addressingMode.getBytes() + (LONG_MNEMONICS.contains(mnemonic+" "+addressingMode.getName())?1:0);
|
||||||
|
return numBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,16 +91,6 @@ public class CpuOpcode {
|
|||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the printed ASM code for the instruction with an operand value.
|
* Get the printed ASM code for the instruction with an operand value.
|
||||||
* This prints to the syntax that KickAssembler expects.
|
* This prints to the syntax that KickAssembler expects.
|
||||||
|
@ -181,17 +181,17 @@ public class AsmFragmentInstance {
|
|||||||
private static class AsmSequenceGenerator extends KickCParserBaseVisitor {
|
private static class AsmSequenceGenerator extends KickCParserBaseVisitor {
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final AsmProgram program;
|
private final AsmProgram asmProgram;
|
||||||
private final AsmFragmentInstance fragmentInstance;
|
private final AsmFragmentInstance fragmentInstance;
|
||||||
|
|
||||||
public AsmSequenceGenerator(String name, AsmFragmentInstance fragmentInstance, AsmProgram program) {
|
public AsmSequenceGenerator(String name, AsmFragmentInstance fragmentInstance, AsmProgram asmProgram) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.fragmentInstance = fragmentInstance;
|
this.fragmentInstance = fragmentInstance;
|
||||||
this.program = program;
|
this.asmProgram = asmProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsmProgram getProgram() {
|
public AsmProgram getAsmProgram() {
|
||||||
return program;
|
return asmProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(KickCParser.AsmLinesContext context) {
|
public void generate(KickCParser.AsmLinesContext context) {
|
||||||
@ -200,14 +200,14 @@ public class AsmFragmentInstance {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitAsmLabelName(KickCParser.AsmLabelNameContext ctx) {
|
public Object visitAsmLabelName(KickCParser.AsmLabelNameContext ctx) {
|
||||||
program.addLine(new AsmLabel(ctx.ASM_NAME().getText()));
|
asmProgram.addLine(new AsmLabel(ctx.ASM_NAME().getText()));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitAsmLabelMulti(KickCParser.AsmLabelMultiContext ctx) {
|
public Object visitAsmLabelMulti(KickCParser.AsmLabelMultiContext ctx) {
|
||||||
String label = ctx.ASM_MULTI_NAME().getText();
|
String label = ctx.ASM_MULTI_NAME().getText();
|
||||||
program.addLine(new AsmLabel(label));
|
asmProgram.addLine(new AsmLabel(label));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +217,7 @@ public class AsmFragmentInstance {
|
|||||||
for(int i = 1; i < ctx.getChildCount(); i = i + 2) {
|
for(int i = 1; i < ctx.getChildCount(); i = i + 2) {
|
||||||
values.add(ctx.getChild(i).getText());
|
values.add(ctx.getChild(i).getText());
|
||||||
}
|
}
|
||||||
program.addLine(new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values));
|
asmProgram.addLine(new AsmDataNumeric(null, AsmDataNumeric.Type.BYTE, values));
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ public class AsmFragmentInstance {
|
|||||||
instruction = (AsmInstruction) this.visit(paramModeCtx);
|
instruction = (AsmInstruction) this.visit(paramModeCtx);
|
||||||
}
|
}
|
||||||
if(instruction != null) {
|
if(instruction != null) {
|
||||||
program.addLine(instruction);
|
asmProgram.addLine(instruction);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException("Error parsing ASM fragment line " + name + ".asm\n - Line: " + ctx.getText());
|
throw new RuntimeException("Error parsing ASM fragment line " + name + ".asm\n - Line: " + ctx.getText());
|
||||||
}
|
}
|
||||||
@ -334,7 +334,7 @@ public class AsmFragmentInstance {
|
|||||||
AsmParameter param2 = operand2Ctx == null ? null : (AsmParameter) this.visit(operand2Ctx);
|
AsmParameter param2 = operand2Ctx == null ? null : (AsmParameter) this.visit(operand2Ctx);
|
||||||
// Convert to ZP-addressing mode if possible
|
// Convert to ZP-addressing mode if possible
|
||||||
boolean isZp = param1 != null && param1.isZp();
|
boolean isZp = param1 != null && param1.isZp();
|
||||||
CpuOpcode cpuOpcode = this.fragmentInstance.fragmentTemplate.getTargetCpu().getCpu65xx().getOpcode(mnemonic, addressingMode, isZp);
|
CpuOpcode cpuOpcode = this.getAsmProgram().getTargetCpu().getCpu65xx().getOpcode(mnemonic, addressingMode, isZp);
|
||||||
String operand1 = param1 == null ? null : param1.getParam();
|
String operand1 = param1 == null ? null : param1.getParam();
|
||||||
String operand2 = param2 == null ? null : param2.getParam();
|
String operand2 = param2 == null ? null : param2.getParam();
|
||||||
if(cpuOpcode == null) {
|
if(cpuOpcode == null) {
|
||||||
|
@ -8,8 +8,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertNotNull;
|
import static junit.framework.TestCase.*;
|
||||||
import static junit.framework.TestCase.assertTrue;
|
|
||||||
|
|
||||||
public class TestCpuFamilyKickAssCompatibility {
|
public class TestCpuFamilyKickAssCompatibility {
|
||||||
|
|
||||||
@ -49,41 +48,57 @@ public class TestCpuFamilyKickAssCompatibility {
|
|||||||
assertNotNull("KickAss CPU " + kaCpu.name + " does not know the KickC CPU " + kcCpu.getName() + " mnemonic", kcOpcode.getMnemonic());
|
assertNotNull("KickAss CPU " + kaCpu.name + " does not know the KickC CPU " + kcCpu.getName() + " mnemonic", kcOpcode.getMnemonic());
|
||||||
final List<_65xxArgType> kaArgTypes = kaAddressingModeMap.get(kcOpcode.getAddressingMode());
|
final List<_65xxArgType> kaArgTypes = kaAddressingModeMap.get(kcOpcode.getAddressingMode());
|
||||||
assertNotNull("KickAss addressing mode not found " + kcOpcode.getAddressingMode().getName(), kaArgTypes);
|
assertNotNull("KickAss addressing mode not found " + kcOpcode.getAddressingMode().getName(), kaArgTypes);
|
||||||
// Try each argtype
|
// Try each argtype to find the one that works
|
||||||
boolean found = false;
|
boolean found = false;
|
||||||
for(_65xxArgType kaArgType : kaArgTypes) {
|
for(_65xxArgType kaArgType : kaArgTypes) {
|
||||||
final int kaArgTypeIdx = kaArgType.getIdNo();
|
final int kaArgTypeIdx = kaArgType.getIdNo();
|
||||||
if(kaOpcodes!=null && kaOpcodes.length>kaArgTypeIdx) {
|
if(kaOpcodes != null && kaOpcodes.length > kaArgTypeIdx) {
|
||||||
final int kaOpcodeRaw = kaOpcodes[kaArgTypeIdx];
|
final int kaOpcodeRaw = kaOpcodes[kaArgTypeIdx];
|
||||||
if(kaOpcodeRaw >= 0) {
|
if(kaOpcodeRaw >= 0) {
|
||||||
found = true;
|
found = true;
|
||||||
int[] kaOpcode;
|
int[] kaOpcode = getKAOpcode(kaOpcodeRaw, kaArgType, kcOpcode.getMnemonic());
|
||||||
if(kcOpcode.getOpcode().length==1) {
|
|
||||||
kaOpcode = new int[]{kaOpcodeRaw};
|
|
||||||
} else {
|
|
||||||
List<Integer> kaOpcodeList = new ArrayList<>();
|
|
||||||
if(CPU_45GS02.R32_MNEMONICS.contains(kcOpcode.getMnemonic())) {
|
|
||||||
kaOpcodeList.add((int)CPU_45GS02.R32_OPCODE_PREFIX);
|
|
||||||
kaOpcodeList.add((int)CPU_45GS02.R32_OPCODE_PREFIX);
|
|
||||||
}
|
|
||||||
if (kaArgType == _65xxArgType.indirect32ZeropageZ || kaArgType == _65xxArgType.indirect32Zeropage) {
|
|
||||||
// Make sure the prefix is unsigned
|
|
||||||
kaOpcodeList.add(CPU_45GS02.A32_OPCODE_PREFIX&0xff);
|
|
||||||
}
|
|
||||||
kaOpcodeList.add(kaOpcodeRaw);
|
|
||||||
kaOpcode = kaOpcodeList.stream().mapToInt(i->i).toArray();
|
|
||||||
}
|
|
||||||
Assert.assertArrayEquals("KickAss opcode not matching for mnemonic " + kcOpcode.toString(), kcOpcode.getOpcode(), kaOpcode);
|
Assert.assertArrayEquals("KickAss opcode not matching for mnemonic " + kcOpcode.toString(), kcOpcode.getOpcode(), kaOpcode);
|
||||||
|
|
||||||
|
int kaByteSize = kaOpcode.length + kaArgType.getByteSize();
|
||||||
|
assertEquals("KickAss opcode byte size not matching KickC byte size "+kcOpcode.toString(), kcOpcode.getBytes(), kaByteSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assertTrue("KickAss opcode not found for mnemonic " + kcOpcode.toString(), found);
|
assertTrue("KickAss opcode not found for mnemonic " + kcOpcode.toString(), found);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test that each KickAss opcode has a matching KickC opcode
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert KickAssembler opcode to int array, that also contains the prefix opcodes used by 45GS02.
|
||||||
|
*
|
||||||
|
* @param kaOpcodeRaw The "raw" one-byte opcode
|
||||||
|
* @param kaArgType The addressing mode
|
||||||
|
* @param mnemonic The instruction mnemonic
|
||||||
|
* @return The opcode list.
|
||||||
|
*/
|
||||||
|
private int[] getKAOpcode(int kaOpcodeRaw, _65xxArgType kaArgType, String mnemonic) {
|
||||||
|
List<Integer> kaOpcodeList = new ArrayList<>();
|
||||||
|
if(CPU_45GS02.R32_MNEMONICS.contains(mnemonic)) {
|
||||||
|
// Make sure the prefix is unsigned
|
||||||
|
kaOpcodeList.add((int) CPU_45GS02.R32_OPCODE_PREFIX & 0xff);
|
||||||
|
kaOpcodeList.add((int) CPU_45GS02.R32_OPCODE_PREFIX & 0xff);
|
||||||
|
}
|
||||||
|
if(kaArgType == _65xxArgType.indirect32ZeropageZ || kaArgType == _65xxArgType.indirect32Zeropage) {
|
||||||
|
// Make sure the prefix is unsigned
|
||||||
|
kaOpcodeList.add(CPU_45GS02.A32_OPCODE_PREFIX & 0xff);
|
||||||
|
}
|
||||||
|
kaOpcodeList.add(kaOpcodeRaw);
|
||||||
|
int[] kaOpcode = kaOpcodeList.stream().mapToInt(i -> i).toArray();
|
||||||
|
return kaOpcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the KickAss ArgType that matches a KickC addressing mode.
|
* Get the KickAss ArgType that matches a KickC addressing mode.
|
||||||
|
*
|
||||||
* @return The argtype.
|
* @return The argtype.
|
||||||
*/
|
*/
|
||||||
Map<CpuAddressingMode, List<_65xxArgType>> getKAAddressingModeMap() {
|
Map<CpuAddressingMode, List<_65xxArgType>> getKAAddressingModeMap() {
|
||||||
@ -107,7 +122,6 @@ public class TestCpuFamilyKickAssCompatibility {
|
|||||||
map.put(CpuAddressingMode.ISY, Collections.singletonList(_65xxArgType.indirectStackZeropageY));
|
map.put(CpuAddressingMode.ISY, Collections.singletonList(_65xxArgType.indirectStackZeropageY));
|
||||||
map.put(CpuAddressingMode.REL, Arrays.asList(_65xxArgType.relative, _65xxArgType.relativeWord));
|
map.put(CpuAddressingMode.REL, Arrays.asList(_65xxArgType.relative, _65xxArgType.relativeWord));
|
||||||
map.put(CpuAddressingMode.REZ, Collections.singletonList(_65xxArgType.zeropageRelative));
|
map.put(CpuAddressingMode.REZ, Collections.singletonList(_65xxArgType.zeropageRelative));
|
||||||
// TODO: Handle Immediate Word, relative Word
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user