First regression tests and bug fixes

Import tests from https://github.com/SingleStepTests/m68000

Added:
- Single Step mode for Core
- 68000/68010 only indexed EA mode

Fixed:
- Added a real CMP in CoreALU (for CCR eXtend bit unaffected)
- Correct microcode branching for all post incremented destination ea
- Fixed PC relative calculation for all related EA
- used of au instead of dt for indexed EA calculation
- Fixed EXG with same register
- Fixed Link/unlk with A7
- Fixed Bcc/BRA/BSR
This commit is contained in:
Rodolphe de Saint Léger 2025-05-18 22:59:19 +02:00
parent 0a4e1a5764
commit 7920f8c6da
86 changed files with 931 additions and 343 deletions

View file

@ -25,6 +25,8 @@ import static miggy.cpupoet.CoreALU.SSWI_AVEC;
import static miggy.cpupoet.CoreALU.SSWI_DERR;
import static miggy.cpupoet.CoreALU.SSWI_EAFH;
import static miggy.cpupoet.CoreALU.SSWI_FMT2;
import static miggy.cpupoet.CoreALU.SSWI_DNGR;
import static miggy.cpupoet.CoreALU.SSWI_SNGL;
import static miggy.cpupoet.CoreALU.SSW_32;
import static miggy.cpupoet.CoreALU.SSW_BR;
import static miggy.cpupoet.CoreALU.SSW_BY;
@ -523,6 +525,14 @@ public class CoreGenerator {
addFormattedMicroInsn("nmpc = resume");
addFormattedMicroInsn("mpc = halt");
addFormattedMicroInsn("continue");
// check if single step mode
addNextFormattedControlFlow("else if ((sswi & 0x%04x) != 0)", SSWI_SNGL);
addFormattedMicroInsn("exit |= sngl");
addFormattedMicroInsn("sngl |= true");
addBeginFormattedControlFlow("if (exit)");
addFormattedMicroInsn("nmpc = resume");
addFormattedMicroInsn("break");
addEndControlFlow();
// check for pending trace
addNextFormattedControlFlow("else if ((sswi & 0x%04x) != 0)", SR_T1 | SR_T0);
consume(38, 4, 4);
@ -642,14 +652,14 @@ public class CoreGenerator {
decode_ax();
addFormattedMicroInsn("at = dar[rx]"); // save address to temporary register
consume(2, 0, 0);
addFormattedMicroInsn("nmpc = decoded.a3");
addFormattedMicroInsn("nmpc = decoded.a2");
addFormattedMicroInsn("break");
addState("ea_aid32");
decode_ax();
addFormattedMicroInsn("at = dar[rx]"); // save address to temporary register
consume(2, 0, 0);
addFormattedMicroInsn("nmpc = decoded.a3");
addFormattedMicroInsn("nmpc = decoded.a2");
addFormattedMicroInsn("break");
}
@ -1035,54 +1045,59 @@ public class CoreGenerator {
}
private void ea_daix_calculate_microcode(String ea, String size, boolean pc, Runnable addEARegister) {
anyread16(null, SSW_IF | SSW_P, "pc + scan", 0, false, () -> {
addFormattedMicroInsn("au = pc + scan"); // save extension word address
anyread16(null, SSW_IF | SSW_P, "au", 0, false, () -> {
addFormattedMicroInsn("scan += 2");
}); // fetch extension word to irb
addClearSSW();
addBeginFormattedControlFlow("if ((sswi & 0x%04x) != 0)", SSWI_DNGR);
addFormattedMicroInsn("irb &= 0xf8ff");
addEndControlFlow();
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", EAX_EXT);
addFormattedMicroInsn("at = (byte) irb"); // sign extend irb and set at
if (pc) {
addFormattedMicroInsn("at += au"); // add pc to at
} else {
addEARegister.run();
}
// retrieve register index (use ry) as scratch register
addFormattedMicroInsn("rz = (irb >> 12) & 0x000f");
addBeginFormattedControlFlow("if (rz == 0x000f)");
addFormattedMicroInsn("rz = sp"); // if using a7, change to right stack pointer
addEndControlFlow();
// retrieve index register in dt
addFormattedMicroInsn("dt = (irb & 0x%04x) == 0 ? (short) dar[rz] : dar[rz]", EAX_SIZ);
// retrieve index register in au
addFormattedMicroInsn("au = (irb & 0x%04x) == 0 ? (short) dar[rz] : dar[rz]", EAX_SIZ);
// apply scale and add to at
addFormattedMicroInsn("at += dt << ((irb & 0x%04x) >> 9)", EAX_SCL);
if (pc) {
addFormattedMicroInsn("at += pc"); // add pc to at
} else {
addEARegister.run();
}
addFormattedMicroInsn("at += au << ((irb & 0x%04x) >> 9)", EAX_SCL);
addFormattedMicroInsn("mpc = ea_%s%s_fetch", ea, size);
addFormattedMicroInsn("continue");
addEndControlFlow();
addFormattedMicroInsn("at = dt = 0"); // resets at and dt
addFormattedMicroInsn("at = 0"); // resets at
// compute index value (in dt)
// add base register to at
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", EAX_BS);
if (pc) {
addFormattedMicroInsn("at += au"); // add pc to at
} else {
addEARegister.run();
}
addEndControlFlow();
// compute index value (in au)
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", EAX_IS);
// retrieve register index (use ry) as scratch register
addFormattedMicroInsn("rz = (irb >> 12) & 0x000f");
addBeginFormattedControlFlow("if (rz == 0x000f)");
addFormattedMicroInsn("rz = sp"); // if using a7, change to right stack pointer
addEndControlFlow();
// retrieve index register in dt
addFormattedMicroInsn("dt = (irb & 0x%04x) == 0 ? (short) dar[rz] : dar[rz]", EAX_SIZ);
// retrieve index register in au
addFormattedMicroInsn("au = (irb & 0x%04x) == 0 ? (short) dar[rz] : dar[rz]", EAX_SIZ);
// apply scale
addFormattedMicroInsn("dt <<= ((irb & 0x%04x) >> 9)", EAX_SCL);
addEndControlFlow();
// add base register to at
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", EAX_BS);
if (pc) {
addFormattedMicroInsn("at += pc"); // add pc to at
} else {
addEARegister.run();
}
addFormattedMicroInsn("au <<= ((irb & 0x%04x) >> 9)", EAX_SCL);
addEndControlFlow();
// retrieve base displacement if any
@ -1103,10 +1118,10 @@ public class CoreGenerator {
addClearSSW();
addState(String.format("ea_%s%s_no_base", ea, size));
// memory indirect preindex, add dt to at and reset dt
// memory indirect preindex, add au to at and reset au
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", 1 << 2);
addFormattedMicroInsn("at += dt");
addFormattedMicroInsn("dt = 0");
addFormattedMicroInsn("at += au");
addFormattedMicroInsn("au = 0");
// no memory indirect operation, process to ea fetch
addBeginFormattedControlFlow("if ((irb & 0x%04x) == 0)", EAX_ISL);
@ -1119,7 +1134,7 @@ public class CoreGenerator {
read32("at", 0, "at");
// add post index (if still here)
addFormattedMicroInsn("at += dt");
addFormattedMicroInsn("at += au");
addClearSSW();
// retrieve outer displacement if any
@ -1222,8 +1237,11 @@ public class CoreGenerator {
private void ea_dpc_microcode() {
addState("ea_dpc8_read");
consume(8, 2, 0);
fetchimm16("at", 0);
addFormattedMicroInsn("at = ((short) at) + pc"); // add pc to temporary register
addFormattedMicroInsn("au = pc + scan"); // save extension word address
anyread16("at", SSW_DF | SSW_P, "au", 0, false, () -> {
addFormattedMicroInsn("scan += 2");
});
addFormattedMicroInsn("at = ((short) at) + au"); // add pc to temporary register
addState("eapc_read8");
setclr16("sswi", 0, SSWI_EAFH);
addFormattedMicroInsn("alub = dt"); // save dt to alub
@ -1236,8 +1254,11 @@ public class CoreGenerator {
addState("ea_dpc16_read");
setclr16("sswi", SSWI_EAFH, 0);
addState("ea_dpc16");
fetchimm16("at", 0);
addFormattedMicroInsn("at = ((short) at) + pc"); // add pc to temporary register
addFormattedMicroInsn("au = pc + scan"); // save extension word address
anyread16("at", SSW_DF | SSW_P, "au", 0, false, () -> {
addFormattedMicroInsn("scan += 2");
});
addFormattedMicroInsn("at = ((short) at) + au"); // add pc to temporary register
addBeginFormattedControlFlow("if ((sswi & 0x%04x) == 0)", SSWI_EAFH);
consume(4, 0, 0);
addFormattedMicroInsn("nmpc = decoded.a3");
@ -1256,8 +1277,11 @@ public class CoreGenerator {
addState("ea_dpc32_read");
setclr16("sswi", SSWI_EAFH, 0);
addState("ea_dpc32");
fetchimm16("at", 0);
addFormattedMicroInsn("at = ((short) at) + pc"); // add pc to temporary register
addFormattedMicroInsn("au = pc + scan"); // save extension word address
anyread16("at", SSW_DF | SSW_P, "au", 0, false, () -> {
addFormattedMicroInsn("scan += 2");
});
addFormattedMicroInsn("at = ((short) at) + au"); // add pc to temporary register
addBeginFormattedControlFlow("if ((sswi & 0x%04x) == 0)", SSWI_EAFH);
consume(4, 1, 0);
addFormattedMicroInsn("nmpc = decoded.a3");
@ -1522,28 +1546,25 @@ public class CoreGenerator {
addState("op_exg_dd_ds");
decode_dy();
decode_dx();
// exchange values without temporary
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dar[ry] ^= dar[rx]");
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dt = dar[ry]");
addFormattedMicroInsn("dar[ry] = dar[rx]");
addFormattedMicroInsn("dar[rx] = dt");
microprefetch(true, null); // prefetch ir and resume execution
addState("op_exg_ad_as");
decode_ay();
decode_ax();
// exchange values without temporary
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dar[ry] ^= dar[rx]");
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dt = dar[ry]");
addFormattedMicroInsn("dar[ry] = dar[rx]");
addFormattedMicroInsn("dar[rx] = dt");
microprefetch(true, null); // prefetch ir and resume execution
addState("op_exg_dd_as");
decode_ay();
decode_dx();
// exchange values without temporary
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dar[ry] ^= dar[rx]");
addFormattedMicroInsn("dar[rx] ^= dar[ry]");
addFormattedMicroInsn("dt = dar[ry]");
addFormattedMicroInsn("dar[ry] = dar[rx]");
addFormattedMicroInsn("dar[rx] = dt");
microprefetch(true, null); // prefetch ir and resume execution
addState("op_scc_b_ds");
@ -1578,25 +1599,26 @@ public class CoreGenerator {
addState("op_link_as_imm16");
addFormattedMicroInsn("au = dar[sp] - %d", 4); // allocate 2 words on stack
addFormattedMicroInsn("dar[sp] = au + ((short) dt)"); // update stack pointer
decode_ay();
write32(SSW_D, "au", "dar[ry]", 0, false);
addFormattedMicroInsn("dar[ry] = au"); // update frame pointer
addFormattedMicroInsn("dar[sp] = au + ((short) dt)"); // update stack pointer
microprefetch(true, null); // prefetch ir from pc and resume execution
addState("op_link_as_imm32");
addFormattedMicroInsn("au = dar[sp] - %d", 4); // allocate 2 words on stack
addFormattedMicroInsn("dar[sp] = au + dt"); // update stack pointer
decode_ay();
write32(SSW_D, "au", "dar[ry]", 0, false);
addFormattedMicroInsn("dar[ry] = au"); // update frame pointer
addFormattedMicroInsn("dar[sp] = au + dt"); // update stack pointer
microprefetch(true, null); // prefetch ir from pc and resume execution
addState("op_unlk_as");
decode_ay();
addFormattedMicroInsn("au = dar[ry]"); // retrieve linked stack pointer
read32(null, 0, "au"); // restore address register value
addFormattedMicroInsn("dar[sp] = au + %d", 4); // restore stack pointer
read32("dar[ry]", 0, "au"); // restore address register value
addFormattedMicroInsn("dar[ry] = dib"); // restore link register
microprefetch(true, null); // prefetch ir from pc and resume execution
addState("op_move_usp_as");
@ -2125,7 +2147,7 @@ public class CoreGenerator {
update = false;
} else if ("cmp".equals(name) || "cmpm".equals(name)) {
update = false;
op = "sub";
op = "cmp";
}
if ("imm3".equals(src)) {
@ -2250,7 +2272,7 @@ public class CoreGenerator {
if (("as".equals(dst) || "ad".equals(dst))) {
if ("add".equals(op)) {
optype = "+";
} else if ("sub".equals(op)) {
} else if ("sub".equals(op) || "cmp".equals(op)) {
optype = "-";
} else {
throw new IllegalStateException();
@ -2511,7 +2533,7 @@ public class CoreGenerator {
addState("op_bra8");
consume(10, 2, 0);
addFormattedMicroInsn("scan = pc + ((byte) ir)");
addFormattedMicroInsn("scan = (byte) ir");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2523,7 +2545,7 @@ public class CoreGenerator {
addState("op_bra16");
consume(10, 2, 0);
addFormattedMicroInsn("scan = pc + dt");
addFormattedMicroInsn("scan = (short) dt");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2535,7 +2557,7 @@ public class CoreGenerator {
addState("op_bra32");
consume(14, 3, 0);
addFormattedMicroInsn("scan = pc + dt");
addFormattedMicroInsn("scan = dt");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2544,7 +2566,7 @@ public class CoreGenerator {
addFormattedMicroInsn("au = dar[sp] - 4");
addFormattedMicroInsn("dar[sp] = au");
write32(SSW_D, "au", "pc + scan", 0, false);
addFormattedMicroInsn("scan = pc + ((byte) ir)");
addFormattedMicroInsn("scan = (byte) ir");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2553,7 +2575,7 @@ public class CoreGenerator {
addFormattedMicroInsn("au = dar[sp] - 4");
addFormattedMicroInsn("dar[sp] = au");
write32(SSW_D, "au", "pc + scan", 0, false);
addFormattedMicroInsn("scan = pc + dt");
addFormattedMicroInsn("scan = (short) dt");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2562,7 +2584,7 @@ public class CoreGenerator {
addFormattedMicroInsn("au = dar[sp] - 4");
addFormattedMicroInsn("dar[sp] = au");
write32(SSW_D, "au", "pc + scan", 0, false);
addFormattedMicroInsn("scan = pc + dt");
addFormattedMicroInsn("scan = dt");
addFormattedMicroInsn("sswi |= (sr & 0x%04x)", SR_T0); // trigger trace flow
microprefetch(true, null); // prefetch ir from pc and resume execution
@ -2580,7 +2602,8 @@ public class CoreGenerator {
addFormattedMicroInsn("scan += 2"); // skip displacement word
microprefetch(true, null); // prefetch ir from pc and resume execution
addEndControlFlow();
fetch16("scan", 0, "pc + scan");
fetch16(null, 0, "pc + scan");
addFormattedMicroInsn("scan += (short) dib");
consume(10, 2, 0);
microprefetch(true, null); // prefetch ir from pc and resume execution
}
@ -3162,6 +3185,7 @@ public class CoreGenerator {
builder.endControlFlow();
builder.beginControlFlow("if (slice > 0)");
builder.addStatement("boolean sngl = false");
builder.addStatement("boolean exit = false");
builder.addStatement("int sp = spi(sr)");
builder.addStatement("int elapsed = 0");

File diff suppressed because it is too large Load diff

View file

@ -105,7 +105,15 @@ public class CoreALU {
/**
* Exit after a RMW cycle
*/
public static final int SSWI_XRMW = 1 << 4;
public static final int SSWI_XRMW = 1 << 6;
/**
* Downgrade to 68000 for Bcc/dais
*/
public static final int SSWI_DNGR = 1 << 5;
/**
* Execute only a single instruction
*/
public static final int SSWI_SNGL = 1 << 4;
/**
* Enable trap format format 0x2 when applicable
*/
@ -161,7 +169,6 @@ public class CoreALU {
*/
public static final int EAX_ISL = 7 << 0;
/*
* Condition code register flags
*/
@ -486,9 +493,10 @@ public class CoreALU {
}
}
int essw = ssw & clr & mask;
return ssw ^= essw ^ (set & mask);
// int essw = ssw & clr & mask;
//
// return ssw ^= essw ^ (set & mask);
return ssw = (ssw & (~(clr & mask))) | (set & mask);
}
/**
@ -500,9 +508,11 @@ public class CoreALU {
* @return new SSWI value
*/
public final int setclrSSWI(int set, int clr) {
int esswi = sswi & clr & (SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC);
return sswi ^= esswi ^ (set & (SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC));
int mask = SSWI_XRMW | SSWI_DNGR | SSWI_SNGL | SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC;
//int esswi = sswi & clr & (SSWI_SNGL | SSWI_FMT2 | SSWI_AVEC | SSWI_PSLC);
//
//return sswi ^= esswi ^ (set & (SSWI_SNGL | SSWI_AVEC | SSWI_PSLC));
return sswi = (sswi & (~(clr & mask))) | (set & mask);
}
/**
@ -624,19 +634,19 @@ public class CoreALU {
byte br = (byte) (dst + src + ((sr & FL_X) >> 4));
int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
byte dr = (byte) (br + corf);
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
byte dr = (byte) (br + corf);
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
return dr;
return dr;
}
public final short word_abcd(int src, int dst) {
@ -645,37 +655,37 @@ public class CoreALU {
short br = (short) (dst + src + ((sr & FL_X) >> 4));
int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
short dr = (short) (br + corf);
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
short dr = (short) (br + corf);
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
return dr;
return dr;
}
public final int long_abcd(int src, int dst) {
int br = dst + src + ((sr & FL_X) >> 4);
int sbr = br >>> 1; /* trick for full 32 bits bcd addition */
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
int dr = br + corf;
int bc = (((src | dst) & ~br) | (src & dst)) & 0x88888888;
int dc = ((sbr + 0x33333333) ^ sbr) & 0x88888888;
int corf = (bc | dc) - ((bc | dc) >>> 2);
int dr = br + corf;
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
int v = ((~br & dr) >> 30) & FL_V;
int cx = ((bc | (br & ~dr)) >> 31) & (FL_C | FL_X);
int n = (dr >> 28) & FL_N;
int z = ((dr | -dr) >> 31) & FL_Z;
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
sr ^= (sr ^ (cx | v | n)) & (FL_C | FL_V | z | FL_N | FL_X);
return dr;
return dr;
}
public final byte byte_add(int src, int dst) {
@ -979,7 +989,7 @@ public class CoreALU {
}
public final byte byte_bchg(int bit, int dst) {
bit &= 0x1f;
bit &= 0x7;
int src = 1 << bit;
int res = dst & src & 0xff;
@ -991,7 +1001,7 @@ public class CoreALU {
}
public final short word_bchg(int bit, int dst) {
bit &= 0x1f;
bit &= 0xf;
int src = 1 << bit;
int res = dst & src & 0xffff;
@ -1015,7 +1025,7 @@ public class CoreALU {
}
public final byte byte_bclr(int bit, int dst) {
bit &= 0x1f;
bit &= 0x7;
int src = 1 << bit;
int res = dst & src & 0xff;
@ -1027,7 +1037,7 @@ public class CoreALU {
}
public final short word_bclr(int bit, int dst) {
bit &= 0x1f;
bit &= 0xf;
int src = 1 << bit;
int res = dst & src & 0xffff;
@ -1047,11 +1057,11 @@ public class CoreALU {
sr ^= (sr ^ z) & FL_Z;
return(dst & (~src));
return (dst & (~src));
}
public final byte byte_bset(int bit, int dst) {
bit &= 0x1f;
bit &= 0x7;
int src = 1 << bit;
int res = dst & src & 0xff;
@ -1063,7 +1073,7 @@ public class CoreALU {
}
public final short word_bset(int bit, int dst) {
bit &= 0x1f;
bit &= 0xf;
int src = 1 << bit;
int res = dst & src & 0xffff;
@ -1087,7 +1097,7 @@ public class CoreALU {
}
public final void byte_btst(int bit, int dst) {
bit &= 0x1f;
bit &= 0x7;
int res = dst & (1 << bit) & 0xff;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1096,7 +1106,7 @@ public class CoreALU {
}
public final void word_btst(int bit, int dst) {
bit &= 0x1f;
bit &= 0xf;
int res = dst & (1 << bit) & 0xffff;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1158,6 +1168,45 @@ public class CoreALU {
return false;
}
public final void byte_cmp(int src, int dst) {
src = (byte) src;
dst = (byte) dst;
byte res = (byte) (dst - src);
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
}
public final void word_cmp(int src, int dst) {
src = (short) src;
dst = (short) dst;
short res = (short) (dst - src);
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
}
public final void long_cmp(int src, int dst) {
int res = dst - src;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int c = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
sr ^= (sr ^ (c | v | z | n)) & (FL_C | FL_V | FL_Z | FL_N);
}
public final byte byte_eor(int src, int dst) {
src = (byte) src;
dst = (byte) dst;
@ -1492,7 +1541,7 @@ public class CoreALU {
if (shift > 0) {
shift &= 15;
short res = (short) ((dst << shift) | ((dst & 0xffff) >>> (16 - shift)));
short res = (short) ((dst << shift) | ((dst & 0xffff) >>> (16 - shift)));
int c = res & FL_C;
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1683,7 +1732,7 @@ public class CoreALU {
byte res = (byte) (dst - src);
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1699,7 +1748,7 @@ public class CoreALU {
short res = (short) (dst - src);
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1712,7 +1761,7 @@ public class CoreALU {
public final int long_sub(int src, int dst) {
int res = dst - src;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = (~((res | -res) >> 31)) & FL_Z;
@ -1728,7 +1777,7 @@ public class CoreALU {
byte res = (byte) (dst - src - ((sr & FL_X) >> 4));
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = ((res | -res) >> 31) & FL_Z;
@ -1744,7 +1793,7 @@ public class CoreALU {
short res = (short) (dst - src - ((sr & FL_X) >> 4));
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = ((res | -res) >> 31) & FL_Z;
@ -1757,7 +1806,7 @@ public class CoreALU {
public final int long_subx(int src, int dst) {
int res = dst - src - ((sr & FL_X) >> 4);
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int v = (((dst ^ src) & (dst ^ res)) >> 30) & FL_V;
int cx = ((((src | ~dst) & res) | (src & ~dst)) >> 31) & (FL_C | FL_X);
int n = (res >> 28) & FL_N;
int z = ((res | -res) >> 31) & FL_Z;

View file

@ -1,50 +1,317 @@
package miggy.cpupoet;
import static junit.framework.TestCase.assertEquals;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class CoreTest extends Core {
private final ByteBuffer memory;
private final Set<Integer> berrs = new HashSet<Integer>();
public static void main(String[] args) {
ResetTest test2 = new ResetTest();
test2.testReset();
private final boolean is24bits;
CoreTest test = new CoreTest();
private final Set<Integer> berrs = new HashSet<Integer>();
private static final int MAGIC_NAME = 0x89ABCDEF;
private static final int MAGIC_TRANSACTIONS = 0x456789AB;
private static final int MAGIC_STATE = 0x01234567;
private static final int MAGIC_TEST = 0xABC12367;
private static final int MAGIC_FILE_HEADER = 0x1A3F5D71;
public void executeBinTest(String name, int... skips) {
ByteBuffer buffer = getResourceAsByteBuffer(name);
setclrSSWI(SSWI_DNGR | SSWI_SNGL, 0);
int magicNum = buffer.getInt();
if (magicNum != MAGIC_FILE_HEADER) {
throw new IllegalStateException(
String.format("Unexpected magic number for file header: %X, expected %X in file %s", magicNum,
MAGIC_FILE_HEADER, name));
}
int numTests = buffer.getInt();
System.out.println(String.format("Number of tests for %s : %d", name, numTests));
for (int i = 0; i < numTests; i++) {
boolean skip = checkSkip(i, skips);
if ((i == 383) && "Bcc".equals(name)) {
toString();
}
executeBinTest(buffer, skip);
}
}
public boolean checkSkip(int i, int... skips) {
for (int j = 0; j < skips.length; j++) {
if (i == skips[j]) {
return true;
}
}
int pc = test.memory.capacity() - 0x800;
test.setInitialSSP(0x040000);
test.setInitialPC(pc);
test.write16(pc, 0x4848);
test.write16(pc + 2, 0x0200);
test.write16(pc + 4, 0x1234);
test.write16(pc + 6, 0x4849);
test.write32(4 << 2, 0x090000);
//test.setclrSSWI(SSWI_XTRP | SSWI_XBRK, 0);
test.execute(Integer.MAX_VALUE);
test.execute(Integer.MAX_VALUE);
test.execute(Integer.MAX_VALUE);
return false;
}
public void executeBinTest(ByteBuffer buffer, boolean skip) {
int pos = buffer.position();
int numBytes = buffer.getInt();
int magicNum = buffer.getInt();
if (magicNum != MAGIC_TEST) {
throw new IllegalStateException(
String.format("Unexpected magic number for test case: %X, expected %X", magicNum, MAGIC_TEST));
}
String testName = readTestName(buffer);
System.out.print(String.format("%s ", testName));
CPUState start = new CPUState(buffer);
CPUState end = new CPUState(buffer);
if (!skip) {
start.apply(this, end);
execute(1000);
end.check(this);
System.out.println("success");
} else {
System.out.println("skipped");
}
skipTransactions(buffer);
if ((buffer.position() - pos) != numBytes) {
throw new IllegalStateException(
String.format("test suite length mismatch: %X, expected %X", buffer.position() - pos, numBytes));
}
}
private void skipTransactions(ByteBuffer buffer) {
int pos = buffer.position();
int numBytes = buffer.getInt();
int magicNum = buffer.getInt();
if (magicNum != MAGIC_TRANSACTIONS) {
throw new IllegalStateException(
String.format("Unexpected magic number for transactions: %X, expected %X", magicNum, MAGIC_TEST));
}
buffer.getInt(); // total cycles
int numTransactions = buffer.getInt();
for (int i = 0; i < numTransactions; i++) {
int tw = buffer.get() & 0xFF; // Read as unsigned byte
buffer.getInt(); // cycles for this transaction
if (tw != 0) { // not nop cycle
buffer.getInt(); // fc
buffer.getInt(); // aob
buffer.getInt(); // dib/dob
buffer.getInt(); // uds
buffer.getInt(); // lds
}
}
if ((buffer.position() - pos) != numBytes) {
throw new IllegalStateException(
String.format("transactions length mismatch: %X, expected %X", buffer.position() - pos, numBytes));
}
}
private static final class CPUState {
private final List<MemoryValue> ram = new ArrayList<MemoryValue>();
private final int[] dar = new int[15];
private int usp;
private int isp;
private int sr;
private int pc;
private CPUState(ByteBuffer buffer) {
int pos = buffer.position();
int numBytes = buffer.getInt();
int magicNum = buffer.getInt();
if (magicNum != MAGIC_STATE) {
throw new IllegalStateException(
String.format("Unexpected magic number for state: %X, expected %X", magicNum, MAGIC_STATE));
}
for (int i = 0; i < 15; i++) {
dar[i] = buffer.getInt();
}
this.usp = buffer.getInt();
this.isp = buffer.getInt();
this.sr = buffer.getInt();
this.pc = buffer.getInt() - 4;
/* skip prefetch check */
buffer.getInt();
buffer.getInt();
int numRams = buffer.getInt();
for (int i = 0; i < numRams; i++) {
int addr = buffer.getInt();
short dataShort = buffer.getShort();
ram.add(new MemoryValue(addr, dataShort));
}
if ((buffer.position() - pos) != numBytes) {
throw new IllegalStateException(
String.format("state length mismatch: %X, expected %X", buffer.position() - pos, numBytes));
}
}
private void apply(CoreTest core, CPUState finalState) {
for (int i = 0; i < 15; i++) {
core.setDARL(i, dar[i]);
}
core.setUSP(usp);
core.setISP(isp);
core.setSR(sr & ~(SR_T0 | SR_M));
/* the pc points to the next instruction */
core.pc = this.pc;
for (MemoryValue value : finalState.ram) {
core.write16(value.addr, 0);
}
for (MemoryValue value : ram) {
core.write16(value.addr, value.data);
}
core.mpc = 11;
core.sswi &= ~(SR_T1 | SR_T0);
}
private void check(CoreTest core) {
boolean trap = false;
boolean aerr = false;
for (int i = 8; i <= 256; i += 4) {
if (core.pc == core.read32(i)) {
trap |= true;
if ((i == 8) || (i == 12)) {
aerr |= true;
}
break;
}
}
if (!aerr) {
for (int i = 0; i < 15; i++) {
assertEquals(dar[i], core.getDARL(i));
}
assertEquals(usp, core.getUSP());
}
if (!trap) {
assertEquals(isp, core.getISP());
for (MemoryValue value : ram) {
assertEquals(value.data, core.read16(value.addr));
}
assertEquals(sr, core.getSR());
} else {
assertEquals(sr & 0xff00, core.getSR() & 0xff00);
}
assertEquals(pc, core.pc + core.scan);
}
}
private static final class MemoryValue {
private final int addr;
private final short data;
private MemoryValue(int addr, short data) {
this.addr = addr;
this.data = data;
}
}
private static String readTestName(ByteBuffer buffer) {
int pos = buffer.position();
int numBytes = buffer.getInt();
int magicNum = buffer.getInt();
if (magicNum != MAGIC_NAME) {
throw new IllegalStateException(
String.format("Unexpected magic number for name: %X, expected %X", magicNum, MAGIC_NAME));
}
int strlen = buffer.getInt();
byte[] strBytes = new byte[strlen];
buffer.get(strBytes);
if ((buffer.position() - pos) != numBytes) {
throw new IllegalStateException(
String.format("name length mismatch: %X, expected %X", buffer.position() - pos, numBytes));
}
return new String(strBytes, StandardCharsets.UTF_8);
}
private static ByteBuffer getResourceAsByteBuffer(String path) {
InputStream in = CoreTest.class.getResourceAsStream(String.format("%s.json.bin", path));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int read;
byte[] data = new byte[1024];
try {
while ((read = in.read(data, 0, data.length)) != -1) {
out.write(data, 0, read);
}
} catch (IOException e) {
throw new IllegalStateException(e);
} finally {
try {
in.close();
} catch (IOException e) {
throw new IllegalStateException(e);
}
}
ByteBuffer buffer = ByteBuffer.wrap(out.toByteArray());
buffer.order(ByteOrder.LITTLE_ENDIAN);
return buffer;
}
public CoreTest() {
/* allocate 512 MiB */
this.memory = ByteBuffer.allocate(512 * 1024);
memory.order(ByteOrder.BIG_ENDIAN);
this(512 * 1024, false);
}
public CoreTest(int mem, boolean is24bits) {
this.memory = ByteBuffer.allocate(mem);
memory.order(ByteOrder.BIG_ENDIAN);
this.is24bits = is24bits;
}
public void setInitialSSP(int ssp) {
write32(0, ssp);
}
public void setInitialPC(int ssp) {
write32(4, ssp);
}
@ -62,8 +329,12 @@ public class CoreTest extends Core {
public int fetch32(int aob) {
return read32(aob);
}
protected int check8(int aob) {
if (is24bits) {
aob &= 0xffffff;
}
if (((aob & 0x7fffffff) + 1 >= memory.capacity()) || berrs.contains(aob)) {
setclrSSW(SSW_BR, 0);
@ -72,8 +343,12 @@ public class CoreTest extends Core {
return aob;
}
protected int check16(int aob) {
if (is24bits) {
aob &= 0xffffff;
}
if ((aob &= 0x7fffffff) + 2 >= memory.capacity() || berrs.contains(aob)) {
setclrSSW(SSW_BR, 0);
@ -82,8 +357,12 @@ public class CoreTest extends Core {
return aob;
}
protected int check32(int aob) {
if (is24bits) {
aob &= 0xffffff;
}
if ((aob &= 0x7fffffff) + 4 >= memory.capacity() || berrs.contains(aob)) {
setclrSSW(SSW_BR, 0);
@ -96,28 +375,28 @@ public class CoreTest extends Core {
@Override
public byte read8(int aob) {
aob = check8(aob);
return aob < 0 ? 0 : memory.get(aob);
}
@Override
public short read16(int aob) {
aob = check16(aob);
return aob < 0 ? 0 : memory.getShort(aob);
}
@Override
public int read32(int aob) {
aob = check32(aob);
return aob < 0 ? 0 : memory.getInt(aob);
}
@Override
public void write8(int aob, int dob) {
aob = check8(aob);
if (aob >= 0) {
memory.put(aob, (byte) dob);
}
@ -126,7 +405,7 @@ public class CoreTest extends Core {
@Override
public void write16(int aob, int dob) {
aob = check16(aob);
if (aob >= 0) {
memory.putShort(aob, (short) dob);
}
@ -135,7 +414,7 @@ public class CoreTest extends Core {
@Override
public void write32(int aob, int dob) {
aob = check32(aob);
if (aob >= 0) {
memory.putInt(aob, dob);
}
@ -238,5 +517,4 @@ public class CoreTest extends Core {
public void setSlice(int slice) {
this.slice = slice;
}
}

View file

@ -0,0 +1,190 @@
package miggy.cpupoet;
import junit.framework.TestCase;
public class InstructionTests extends TestCase {
static {
MacroPLA.decode(0);
}
public void testBCD() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("ABCD");
test.executeBinTest("NBCD");
test.executeBinTest("SBCD");
}
public void testADD() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("ADD.b");
test.executeBinTest("ADD.w");
test.executeBinTest("ADD.l");
test.executeBinTest("ADDA.w");
test.executeBinTest("ADDA.l");
test.executeBinTest("ADDX.b");
test.executeBinTest("ADDX.w");
test.executeBinTest("ADDX.l");
}
public void testAND() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("AND.b");
test.executeBinTest("AND.w");
test.executeBinTest("AND.l");
test.executeBinTest("ANDItoCCR");
}
public void testOR() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("OR.b");
test.executeBinTest("OR.w");
test.executeBinTest("OR.l");
test.executeBinTest("ORItoCCR");
}
public void testEOR() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("EOR.b");
test.executeBinTest("EOR.w");
test.executeBinTest("EOR.l");
test.executeBinTest("NOT.b");
test.executeBinTest("NOT.w");
test.executeBinTest("NOT.l");
test.executeBinTest("EORItoCCR");
}
public void testBIT() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("BCHG");
test.executeBinTest("BCLR");
test.executeBinTest("BSET");
test.executeBinTest("BTST");
}
// public void testASL() {
// CoreTest test = new CoreTest(0xffffff + 1, true);
//
// test.executeBinTest("ASL.b");
// test.executeBinTest("ASL.w");
// test.executeBinTest("ASL.l");
// }
public void testBcc() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("Bcc", 373, 466, 570, 1547, 1695, 1782, 2166, 2224, 2441);
test.executeBinTest("BSR", 25, 573, 814, 1357, 1443, 1509, 1734, 1934, 2232, 2338);
}
public void testDBcc() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("DBcc");
}
public void testMisc() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("NOP");
test.executeBinTest("EXG");
test.executeBinTest("SWAP");
test.executeBinTest("EXT.w");
test.executeBinTest("EXT.l");
test.executeBinTest("LEA");
test.executeBinTest("PEA");
test.executeBinTest("RTS");
test.executeBinTest("RTR");
test.executeBinTest("LINK");
test.executeBinTest("UNLINK");
test.executeBinTest("Scc");
test.executeBinTest("TST.b");
test.executeBinTest("TST.w");
test.executeBinTest("TST.l");
// test.executeBinTest("CLR.b");
// test.executeBinTest("CLR.w");
// test.executeBinTest("CLR.l");
test.executeBinTest("TRAP");
test.executeBinTest("TRAPV");
}
public void testJMP() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("JMP");
test.executeBinTest("JSR");
}
public void testSUB() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("SUB.b");
test.executeBinTest("SUB.w");
test.executeBinTest("SUB.l");
test.executeBinTest("SUBA.w");
test.executeBinTest("SUBA.l");
test.executeBinTest("CMP.b");
test.executeBinTest("CMP.w");
test.executeBinTest("CMP.l");
test.executeBinTest("CMPA.w");
test.executeBinTest("CMPA.l");
test.executeBinTest("SUBX.b");
test.executeBinTest("SUBX.w");
test.executeBinTest("SUBX.l");
test.executeBinTest("NEG.b");
//test.executeBinTest("NEG.w");
test.executeBinTest("NEG.l");
test.executeBinTest("NEGX.b");
test.executeBinTest("NEGX.w");
test.executeBinTest("NEGX.l");
}
public void testMOVE() {
CoreTest test = new CoreTest(0xffffff + 1, true);
test.executeBinTest("MOVE.b");
/*
* 295 is not compatible (post incremented value is written by design)
* 342 is not compatible (post incremented value is written by design)
* 494 is not compatible (post incremented value is written by design)
* 994 is not compatible (pre decremented value is written by design)
* 1225 is not compatible (pre decremented value is written by design)
* 1846 is not compatible (post incremented value is written by design)
*/
test.executeBinTest("MOVE.w", 295, 342, 494, 994, 1225, 1846);
/*
* 217 is not compatible (post incremented value is written by design)
* 502 is not compatible (post incremented value is written by design)
* 1152 is not compatible (post incremented value is written by design)
* 1691 is not compatible (post incremented value is written by design)
* 1830 is not compatible (pre decremented value is written by design)
* 2057 is not compatible (post incremented value is written by design)
* 2135 is not compatible (post incremented value is written by design)
*/
test.executeBinTest("MOVE.l", 217, 502, 1152, 1691, 1830, 2057, 2135);
test.executeBinTest("MOVE.q");
test.executeBinTest("MOVEP.w");
test.executeBinTest("MOVEP.l");
test.executeBinTest("MOVEA.w");
test.executeBinTest("MOVEA.l");
// test.executeBinTest("MOVEM.w");
// test.executeBinTest("MOVEM.l");
test.executeBinTest("MOVEtoCCR");
test.executeBinTest("MOVEtoUSP");
test.executeBinTest("MOVEfromUSP");
}
}