uae_u32 val;
uae_u32 oldval;
int size;
+ bool donotsave;
};
static int ahcnt_current, ahcnt_written;
static int noaccesshistory = 0;
return get_iword_test(m68k_getpci() + o);
}
-// Move from SR does two writes to same address:
-// ignore the first one
static void previoussame(uaecptr addr, int size)
{
if (!ahcnt_current || ahcnt_current == ahcnt_written)
return;
- struct accesshistory *ah = &ahist[ahcnt_current - 1];
- if (ah->addr == addr && ah->size == size) {
- ahcnt_current--;
+ // Move from SR does two writes to same address.
+ // Loop mode can write different values to same address.
+ // Mark old values as do not save.
+ for (int i = ahcnt_written; i < ahcnt_current; i++) {
+ struct accesshistory *ah = &ahist[i];
+ if (ah->size == size && ah->addr == addr) {
+ ah->donotsave = true;
+ }
+ if (size == sz_long) {
+ if (ah->size == sz_word && ah->addr == addr) {
+ ah->donotsave = true;
+ }
+ if (ah->size == sz_word && ah->addr == addr + 2) {
+ ah->donotsave = true;
+ }
+ }
}
}
ah->val = v & 0xff;
ah->oldval = *p;
ah->size = sz_byte;
+ ah->donotsave = false;
}
regs.write_buffer = v;
*p = v;
ah->val = v & 0xffff;
ah->oldval = (p[0] << 8) | p[1];
ah->size = sz_word;
+ ah->donotsave = false;
}
p[0] = v >> 8;
p[1] = v & 0xff;
ah->val = v;
ah->oldval = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
ah->size = sz_long;
+ ah->donotsave = false;
}
p[0] = v >> 24;
p[1] = v >> 16;
struct accesshistory *ah = &ahist[i];
if (ah->oldval == ah->val && !storealways)
continue;
+ if (ah->donotsave)
+ continue;
validate_addr(ah->addr, 1 << ah->size);
uaecptr addr = ah->addr;
addr &= addressing_mask;
uae_u16 opc = regs.ir;
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0x40ef
- && opw1 == 0x64fc
+ if (opc == 0xd196
+ //&& opw1 == 0x64fc
//&& opw2 == 0x4afc
)
printf("");
if (feature_loop_mode_68010) {
if (!opcode_loop_mode(opcode))
continue;
+ if (dp->mnemo == i_DBcc)
+ continue;
}
target_ea[0] = target_ea_bak[0];
enum
{
SR, CCR, USP, SFC, DFC, CACR, VBR, CAAR, MSP, ISP, TC,
- ITT0, ITT1, DTT0, DTT1, MMUSR, URP, SRP, TT0, TT1, CRP
+ ITT0, ITT1, DTT0, DTT1, MMUSR, URP, SRP, TT0, TT1, CRP,
+ BUSCR, PCR
};
#define PC (ushort)16 /* index into reg_names array */
extern BOOL ascending_label_numbers;
extern BOOL disasm_as_lib;
extern BOOL old_style;
-extern BOOL cpu68020,
+extern BOOL cpu68010,
+ cpu68020,
cpu68030,
cpu68040,
cpu68060,
extern short cpu68030_disabled [];
extern short cpu68040_disabled [];
extern short cpu68060_disabled [];
-extern short cpuCF_disabled [];
extern short fpu68881_disabled [];
extern int OPCODE_COL;
BOOL single_file = TRUE;
BOOL print_illegal_instr_offset = FALSE; /* -i */
BOOL old_style = FALSE;
-BOOL cpu68020 = TRUE, /* -m2 */
+BOOL cpu68010 = TRUE,
+ cpu68020 = TRUE, /* -m2 */
cpu68030 = TRUE, /* -m3 */
cpu68040 = TRUE, /* -m4 */
cpu68060 = TRUE, /* -m6 */
- cpuCF = FALSE,
fpu68881 = TRUE; /* -m8 */
BOOL disasm_as_lib = FALSE; /* -l */
BOOL ascending_label_numbers = FALSE; /* -dn */
"tt0", /* 18 */
"tt1", /* 19 */
"crp" /* 20 */
+ "buscr" /* 21 */
+ "pcr" /* 22 */
};
/**********************************************************************/
983, /* PLPAR */
0
};
-
-short cpuCF_disabled [] =
- {
- 452, /* MVS.B */
- 453, /* MVS.W */
- 454, /* MVZ.B */
- 455, /* MVZ.W */
- 460, /* MVS.B */
- 461, /* MVS.W */
- 462, /* MVZ.B */
- 463, /* MVZ.W */
- 468, /* MVS.B */
- 469, /* MVS.W */
- 470, /* MVZ.B */
- 471, /* MVZ.W */
- 476, /* MVS.B */
- 477, /* MVS.W */
- 478, /* MVZ.B */
- 479, /* MVZ.W */
- 484, /* MVS.B */
- 485, /* MVS.W */
- 486, /* MVZ.B */
- 487, /* MVZ.W */
- 492, /* MVS.B */
- 493, /* MVS.W */
- 494, /* MVZ.B */
- 495, /* MVZ.W */
- 500, /* MVS.B */
- 501, /* MVS.W */
- 502, /* MVZ.B */
- 503, /* MVZ.W */
- 508, /* MVS.B */
- 509, /* MVS.W */
- 510, /* MVZ.B */
- 511, /* MVZ.W */
- 645, /* MOV3Q */
- 653, /* MOV3Q */
- 661, /* MOV3Q */
- 669, /* MOV3Q */
- 677, /* MOV3Q */
- 685, /* MOV3Q */
- 693, /* MOV3Q */
- 701, /* MOV3Q */
- 1056, /* BITREV */
- 1057, /* BYTEREV */
- 1058, /* FF1 */
- 1059, /* SATS */
- 0
- };
case 3: ptr = "rte";
instr_end = TRUE;
break;
- case 4: if (!cpu68020)
+ case 4: if (!cpu68010)
return (TRANSFER);
ptr = "rtd";
instr_end = TRUE;
{
short reg_offset;
- if (!cpu68020)
+ if (!cpu68010)
return (TRANSFER);
switch (*(code + 1) & 0xfff)
{
break;
case 0x002: ptr = special_regs [CACR];
break;
- case 0x003: if (cpu68040)
- ptr = special_regs [TC];
- else
- return (TRANSFER);
+ case 0x003: ptr = special_regs [TC];
+ break;
+ case 0x004: ptr = special_regs [ITT0];
break;
- case 0x004: if (cpu68040)
- ptr = special_regs [ITT0];
- else
- return (TRANSFER);
+ case 0x005: ptr = special_regs [ITT1];
break;
- case 0x005: if (cpu68040)
- ptr = special_regs [ITT1];
- else
- return (TRANSFER);
+ case 0x006: ptr = special_regs [DTT0];
break;
- case 0x006: if (cpu68040)
- ptr = special_regs [DTT0];
- else
- return (TRANSFER);
+ case 0x007: ptr = special_regs [DTT1];
break;
- case 0x007: if (cpu68040)
- ptr = special_regs [DTT1];
- else
- return (TRANSFER);
+ case 0x008: ptr = special_regs [BUSCR];
break;
case 0x800: ptr = special_regs [USP];
break;
break;
case 0x804: ptr = special_regs [ISP];
break;
- case 0x805: if (cpu68040)
- ptr = special_regs [MMUSR];
- else
- return (TRANSFER);
+ case 0x805: ptr = special_regs [MMUSR];
+ break;
+ case 0x806: ptr = special_regs [URP];
break;
- case 0x806: if (cpu68040)
- ptr = special_regs [URP];
- else
- return (TRANSFER);
+ case 0x807: ptr = special_regs [SRP];
break;
- case 0x807: if (cpu68040)
- ptr = special_regs [SRP];
- else
- return (TRANSFER);
+ case 0x808: ptr = special_regs [PCR];
break;
default : return (TRANSFER);
}
reg_offset = (*(code + 1) & 0x8000) ? 8 : 0;
if (pass3)
{
- str_cpy (opcode, "movec.l");
+ str_cpy (opcode, "movec");
if (*code & 0x1)
{
/* from general register to control register */
}
return (1);
}
-
-/**********************************************************************
- ColdFire handlers
-**********************************************************************/
-
-uint mov3q (struct opcode_entry *op)
-
-/* handler for ColdFire mov3q */
-{
-if (pass3)
- {
- char *to;
- to = src;
- *to++ = '#';
- UBYTE data = (UBYTE)op->param;
- if (data)
- *to++ = data + '0';
- else
- {
- *to++ = '-';
- *to++ = '1';
- }
- *to = 0;
- }
-return (decode_ea (dest, MODE_NUM(*code), REG_NUM(*code), ACC_LONG, 1) + 1);
-}
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 0, ACC_LONG }, /* 1010 000 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 000 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 1, ACC_LONG }, /* 1010 001 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 001 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 2, ACC_LONG }, /* 1010 010 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 010 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 3, ACC_LONG }, /* 1010 011 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 011 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 4, ACC_LONG }, /* 1010 100 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 100 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 5, ACC_LONG }, /* 1010 101 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 101 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 6, ACC_LONG }, /* 1010 110 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 110 111 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 000 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 010 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 011 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 100 */
-{ mov3q , 0xff, 0x0f, 1024, "mov3q" , 7, ACC_LONG }, /* 1010 111 101 */
+{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 101 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 110 */
{ invalid , 0xff, 0xff, 1024, 0 , 0, 0 }, /* 1010 111 111 */
{ EA_to_Rn , 0xff, 0x1f, 1024, "cmp.b" , 0, ACC_BYTE }, /* 1011 000 000 */
{ op2_bcdx , 0x03, 0x00, 1024, "subx.b" , NO_ADJ, 0 }, /* 1052 */
{ op2_bcdx , 0x03, 0x00, 1024, "subx.w" , NO_ADJ, 0 }, /* 1053 */
{ op2_bcdx , 0x03, 0x00, 1024, "subx.l" , NO_ADJ, 0 }, /* 1054 */
-{ link_l , 0x02, 0x00, 1024, "link.l" , 0, 0 }, /* 1055 */
-/* ColdFire chains */
-{ op1 , 0x03, 0x00, 1024, "bitrev" , 0, ACC_LONG }, /* 1056 */
-{ op1 , 0x03, 0x00, 1024, "byterev" , 0, ACC_LONG }, /* 1057 */
-{ op1 , 0x03, 0x00, 1024, "ff1" , 0, ACC_LONG }, /* 1058 */
-{ op1 , 0x03, 0x00, 1024, "sats" , 0, ACC_SLONG } /* 1059 */
+{ link_l , 0x02, 0x00, 1024, "link.l" , 0, 0 } /* 1055 */
};
cpu68020 = 0;
fpu68881 = 0;
}
+ if (cpu_lvl < 1) {
+ cpu68010 = 0;
+ }
set_pass3;
; value: 0 = disabled, >0 = number of loops
feature_loop_mode=0
feature_loop_mode_register=7
+; only generate 68010 loop mode compatible instructions
+feature_loop_mode_68010=0
; 68020+ addressing modes (this makes test files much larger if other addressing modes are also enabled)
; currently does not generate any reserved mode bit combinations.
static short disasm;
static short basicexcept;
static short excskipccr;
+static short skipmemwrite;
+static short skipregchange;
+static short skipccrchange;
static short askifmissing;
static short nextall;
static int exitcnt;
uae_u8 *p = mem;
int offset = 0;
int lines = 0;
- while (lines++ < 5) {
+ while (lines++ < 7) {
int v = 0;
if (!is_valid_test_addr_read((uae_u32)p) || !is_valid_test_addr_read((uae_u32)p + 1)) {
sprintf(outbp, "%08x -- INACCESSIBLE --\n", (uae_u32)p);
case 3:
return 126;
case 4:
- case 10:
- case 11:
- return 38;
case 5:
- return 38;
case 6:
- return 44;
- case 7:
- return 40;
case 8:
- return 38;
case 9:
+ case 10:
+ case 11:
+ case 14:
+ return 38;
+ case 7:
return 38;
case 24:
case 25:
{
uae_u8 regs_changed[16] = { 0 };
uae_u8 regs_fpuchanged[8] = { 0 };
- uae_u8 sr_changed = 0, pc_changed = 0;
+ uae_u8 sr_changed = 0, ccr_changed = 0, pc_changed = 0;
uae_u8 fpiar_changed = 0, fpsr_changed = 0, fpcr_changed = 0;
short exc = -1;
regs_changed[i] = 1;
}
}
- if ((last_registers.sr & test_ccrignoremask) != (test_regs.sr & test_ccrignoremask)) {
+ if ((last_registers.sr & test_ccrignoremask & 0xff00) != (test_regs.sr & test_ccrignoremask & 0xff00)) {
sr_changed = 1;
}
+ if ((last_registers.sr & test_ccrignoremask & 0x00ff) != (test_regs.sr & test_ccrignoremask & 0x00ff)) {
+ ccr_changed = 1;
+ }
if (last_registers.pc != test_regs.pc) {
pc_changed = 1;
}
uae_u32 val = last_registers.regs[mode];
int size;
p = restore_value(p, &val, &size);
- if (val != test_regs.regs[mode] && !ignore_errors) {
+ if (val != test_regs.regs[mode] && !ignore_errors && !skipregchange) {
if (dooutput) {
sprintf(outbp, "%c%d: expected %08x but got %08x\n", mode < CT_AREG ? 'D' : 'A', mode & 7, val, test_regs.regs[mode]);
outbp += strlen(outbp);
}
regs_changed[mode] = 0;
last_registers.regs[mode] = val;
- } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU) {
+ } else if (mode < CT_AREG && (v & CT_SIZE_MASK) == CT_SIZE_FPU && !skipregchange) {
struct fpureg val;
p = restore_fpvalue(p, &val);
if (memcmp(&val, &test_regs.fpuregs[mode], sizeof(struct fpureg)) && !ignore_errors) {
}
// CCR check
mask = test_ccrignoremask & 0x00ff;
- if ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask))) {
+ if (skipccrchange || ((val & (sr_undefined_mask & mask)) == (test_regs.sr & (sr_undefined_mask & mask)))) {
errflag &= ~(1 << 7);
}
}
sr_changed = 0;
+ ccr_changed = 0;
last_registers.sr = val;
if (!(test_regs.expsr & 0x2000)) {
sprintf(outbp, "SR S-bit is not set at start of exception handler!\n");
{
case 0:
mval = addr[0];
- if (mval != val && !ignore_errors) {
+ if (mval != val && !ignore_errors && !skipmemwrite) {
if (dooutput) {
sprintf(outbp, "Memory byte write: address %08x, expected %02x but got %02x\n", (uae_u32)addr, val, mval);
outbp += strlen(outbp);
break;
case 1:
mval = (addr[0] << 8) | (addr[1]);
- if (mval != val && !ignore_errors) {
+ if (mval != val && !ignore_errors && !skipmemwrite) {
if (dooutput) {
sprintf(outbp, "Memory word write: address %08x, expected %04x but got %04x\n", (uae_u32)addr, val, mval);
outbp += strlen(outbp);
break;
case 2:
mval = gl(addr);
- if (mval != val && !ignore_errors) {
+ if (mval != val && !ignore_errors && !skipmemwrite) {
if (dooutput) {
sprintf(outbp, "Memory long write: address %08x, expected %08x but got %08x\n", (uae_u32)addr, val, mval);
outbp += strlen(outbp);
}
}
if (!ignore_errors) {
- if (!ignore_sr) {
+ if (!skipregchange) {
for (int i = 0; i < 16; i++) {
if (regs_changed[i]) {
if (dooutput) {
errflag |= 1 << 0;
}
}
+ }
+ if (!ignore_sr) {
if (sr_changed) {
if (dooutput) {
sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
outbp += strlen(outbp);
}
errflag |= 1 << 2;
+ } else if (ccr_changed && !skipccrchange) {
+ if (dooutput) {
+ sprintf(outbp, "SR: modified %04x -> %04x but expected no modifications\n", last_registers.sr & 0xffff, test_regs.sr & 0xffff);
+ outbp += strlen(outbp);
+ }
+ errflag |= 1 << 2;
}
}
for (int i = 0; i < 8; i++) {
printf("-ccrmask = ignore CCR bits that are not set.\n");
printf("-nodisasm = do not disassemble failed test.\n");
printf("-basicexc = do only basic checks when exception is 2 or 3.\n");
- printf("-excskipccr = ignore CCR if DivByZero, CHK, Address/Bus error exception.\n");
+ printf("-skipexcccr = ignore CCR if DivByZero, CHK, Address/Bus error exception.\n");
+ printf("-skipmem = do not validate memory writes.\n");
+ printf("-skipreg = do not validate registers.\n");
printf("-askifmissing = ask for new path if dat file is missing.\n");
printf("-exit n = exit after n tests.\n");
printf("-cycles [range adjust] = check cycle counts.\n");
disasm = 0;
} else if (!_stricmp(s, "-basicexc")) {
basicexcept = 1;
- } else if (!_stricmp(s, "-excskipccr")) {
+ } else if (!_stricmp(s, "-skipexcccr")) {
excskipccr = 1;
+ } else if (!_stricmp(s, "-skipmem")) {
+ skipmemwrite = 1;
+ } else if (!_stricmp(s, "-skipreg")) {
+ skipregchange = 1;
+ } else if (!_stricmp(s, "-skipccr")) {
+ skipccrchange = 1;
} else if (!_stricmp(s, "-askifmissing")) {
askifmissing = 1;
} else if (!_stricmp(s, "-next")) {
- Memory writes, including stack modifications (if any)
- Loop mode for JIT testing. (generates <test instruction>, dbf dn,loop)
- Supports 68000, 68010, 68020, 68030 (only difference between 020 and 030 seems to be data cache and MMU), 68040 and 68060.
-- Cycle counts (68000 Amiga only)
+- Cycle counts (68000/68010, Amiga only)
Tests executed for each tested instruction:
Tester compatibility (integer instructions only):
68000: Complete. Including bus and address error stack frame/register/CCR modification undocumented behavior. Cycle count support.
-68010: Almost complete. Bus errors are only partially supported. DIVS undefined condition codes are not yet supported.
+68010: Almost complete (same as 68000). Loop mode is also fully supported. NOTE: DIVS overflow undocumented N-flag is not fully correct.
68020: Almost complete (DIV undocumented behavior is not yet known)
68030: Same as 68020.
68040: Almost complete (Weird unaligned MOVE16 behavior which may be board specific).
68060: Same as 68040.
-68000 cycle count testing:
+68000/68010 cycle count testing:
Cycle counting requires 100% accurate timing also for following instructions:
- BSR.B
- NOP
- MOVE.W ABS.L,ABS.L
- MOVE SR,-(SP)
+- MOVE.W #x,ABS.L (68010 only)
- RTE
- Illegal instruction exception
- If instruction internally generates exception, internal exception also needs to be cycle-accurate.
0xDFF006 is used for cycle counting = accuracy will be +-2 CPU cycles. 0xDFF006 behavior must be accurate.
-Currently only supported hardware for cycle counting is 7MHz 68000 PAL Amiga with real Fast RAM.
+Currently only supported hardware for cycle counting is 7MHz 68000/68010 PAL Amiga with real Fast RAM.
Bus error cycle counting is not yet supported.
Change log:
+18.01.2020
+
- Cycle count validation (Amiga, 68000 only), including exceptions (except bus errors).
- Interrupt testing (Amiga only, INTREQ bits set one by one, validate correct exception).
- Multiple test sets can be generated and tested in single step.
- Stack usage reduced, gzip decompression works with default 4096 byte stack.
+
+26.01.2020
+
+- 68010 is now almost fully supported, including loop mode and cycle count verification.
+- Removed most ColdFire instructions from disassembler. RTD was not disassembled if 68010. Added missing 68060 PCR and BUSCR control registers.
+- Fixed ahist overflow when generating MOVEM with more than 1 SR flag combination.
+- Some instructions (for example TRAP) had wrong expected cycle count if instruction generated any non-trace exception and also trace exception.
+- added -skipexcccr parameter. Skip CCR check if instruction generates bus, address, divide by zero or CHK exception.
+- added -skipmem (ignore memory write mismatches) -skipreg (ignore register mismatched) -skipccr (ignored CCR mismatch) parameters.
static int optimized_flags;
-#define GF_APDI 1
-#define GF_AD8R 2
-#define GF_PC8R 4
-#define GF_AA 7
-#define GF_NOREFILL 8
-#define GF_PREFETCH 16
-#define GF_FC 32
-#define GF_MOVE 64
-#define GF_IR2IRC 128
-#define GF_LRMW 256
-#define GF_NOFAULTPC 512
-#define GF_RMW 1024
-#define GF_OPCE020 2048
-#define GF_REVERSE 4096
-#define GF_REVERSE2 8192
-#define GF_SECONDWORDSETFLAGS 16384
-#define GF_SECONDEA 32768
+#define GF_APDI 0x00001
+#define GF_AD8R 0x00002
+#define GF_PC8R 0x00004
+#define GF_AA 0x00007
+#define GF_NOREFILL 0x00008
+#define GF_PREFETCH 0x00010
+#define GF_FC 0x00020
+#define GF_MOVE 0x00040
+#define GF_IR2IRC 0x00080
+#define GF_LRMW 0x00100
+#define GF_NOFAULTPC 0x00200
+#define GF_RMW 0x00400
+#define GF_OPCE020 0x00800
+#define GF_REVERSE 0x01000
+#define GF_REVERSE2 0x02000
+#define GF_SECONDWORDSETFLAGS 0x04000
+#define GF_SECONDEA 0x08000
+#define GF_NOFETCH 0x10000 // 68010
+#define GF_CLR68010 0x20000 // 68010
typedef enum
{
static struct instr *g_instr;
static char g_srcname[100];
static int loopmode;
+static int loopmodeextra;
+static int loopmode_set;
#define GENA_GETV_NO_FETCH 0
#define GENA_GETV_FETCH 1
static bool no_prefetch_ce020;
static bool got_ea_ce020;
-// 68020-30 needs different implementation than 68040/060
+// 68010-40 needs different implementation than 68060
+static void next_level_060_to_040(void)
+{
+ if (cpu_level >= 5) {
+ if (next_cpu_level < 5)
+ next_cpu_level = 5 - 1;
+ }
+}
+// 68010-30 needs different implementation than 68040/060
static void next_level_040_to_030(void)
{
if (cpu_level >= 4) {
next_cpu_level = 4 - 1;
}
}
-
// 68000 <> 68010
static void next_level_000(void)
{
printf("%sreturn %d * CYCLE_UNIT / 2;\n", s, cycles);
}
+static void write_return_cycles_none(const char *s)
+{
+ if (using_ce || using_ce020) {
+ printf("%sreturn;\n", s);
+ } else {
+ printf("%sreturn 0;\n", s);
+ }
+}
+
static void write_return_cycles(const char *s, int end)
{
if (end <= 0) {
{
if (using_prefetch) {
printf("\t%s(%d);\n", prefetch_word, o);
- count_read++;
- insn_n_cycles += 4;
+ if (!loopmode || using_ce) {
+ count_read++;
+ insn_n_cycles += 4;
+ } else {
+ addcycles000_nonce("\t", 4);
+ }
check_prefetch_bus_error(o, 0);
did_prefetch = 1;
ir2irc = 0;
ir2irc = 0;
}
+static void loopmode_start(void)
+{
+ loopmode_set = 0;
+ loopmodeextra = 0;
+ if (loopmode) {
+ printf("\tint loop_mode = regs.loop_mode;\n");
+ }
+}
+static void loopmode_stop(void)
+{
+ if (loopmode) {
+ printf("\tregs.loop_mode = loop_mode;\n");
+ }
+}
static void loopmode_begin(void)
{
if (loopmode) {
- printf("\tif(!regs.loop_mode) {\n");
+ printf("\tif(!loop_mode) {\n");
+ }
+}
+static void loopmode_access(void)
+{
+ if (loopmode && loopmode_set) {
+ loopmode_set = 0;
+ printf("\tif(loop_mode & 0xfffe) {\n");
+ if (using_ce) {
+ printf("\t\t%s(loop_mode & 0xfffe);\n", do_cycles);
+ } else {
+ addcycles000_nonces("\t\t", "loop_mode & 0xfffe");
+ }
+ // CLR.L adds 2 extra cycles when loop exits
+ if (g_instr->mnemo == i_CLR && g_instr->size == sz_long) {
+ printf("\t\tloop_mode &= 0xffff0000;\n");
+ printf("\t\tloop_mode |= 1;\n");
+ } else {
+ printf("\t\tloop_mode = 1;\n");
+ }
+ printf("\t}\n");
}
}
+
static void loopmode_end(void)
{
if (loopmode) {
+ int s = g_instr->size;
int m = g_instr->mnemo;
- if (using_ce && (g_instr->dmode == Apdi || (m != i_MOVE && m != i_CLR))) {
- printf("\t} else {\n");
- if (m == i_ASLW || m == i_ASRW || m == i_LSLW || m == i_LSRW || m == i_ROLW || m == i_RORW || m == i_ROXLW || m == i_ROXRW) {
- addcycles000(4);
+ int cycs = 0;
+ int ecycs = 0;
+ if (using_prefetch) {
+ if (m == i_CLR) {
+ cycs += 2;
+ ecycs += 4;
+ } else if (m == i_MOVE) {
+ cycs += 2;
+ if (isreg(g_instr->smode)) {
+ ecycs = 2;
+ }
+ } else if (m == i_ADDX || m == i_SUBX) {
+ if (s == sz_long) {
+ cycs += 2;
+ } else {
+ cycs += 4;
+ }
+ } else if (m == i_CMPM) {
+ if (s == sz_long) {
+ cycs += 4;
+ } else {
+ cycs += 2;
+ }
+ } else if (m == i_NBCD) {
+ cycs += 6;
} else {
- addcycles000(2);
+ cycs += 4;
+ }
+ // destination -(an)?
+ if ((m == i_MOVE || m == i_ABCD || m == i_SBCD) && g_instr->dmode == Apdi) {
+ cycs += 2;
+ }
+
+ if (ecycs == 0) {
+ ecycs = cycs;
}
+
+ if (m == i_TST && s == sz_long) {
+ ecycs = 4;
+ cycs = 6;
+ } else if (m == i_MOVE) {
+ if (isreg(g_instr->smode)) {
+ ecycs += 2;
+ }
+ } else if (m == i_CMP && s == sz_long) {
+ ecycs -= 2;
+ }
+
+ if (cycs > 0 || ecycs > 0) {
+ printf("\t} else {\n");
+ printf("\t\tloop_mode = 0;\n");
+ if (cycs > 0) {
+ printf("\t\tloop_mode |= %d;\n", cycs);
+ }
+ if (ecycs > 0) {
+ printf("\t\tloop_mode |= %d << 16;\n", ecycs);
+ }
+ }
+ printf("\t}\n");
+ loopmode_set = 1;
}
- printf("\t}\n");
}
}
genamode_cnt++;
}
+ loopmode_access();
+
start_brace ();
switch (mode) {
printf("\tuaecptr %sa;\n", name);
add_mmu040_movem (movem);
printf("\t%sa = m68k_areg(regs, %s);\n", name, reg);
+ if ((flags & GF_NOFETCH) && using_prefetch) {
+ addcycles000(2);
+ }
break;
case Aipi: // (An)+
switch (fetchmode)
printf("\tuaecptr %sa;\n", name);
add_mmu040_movem (movem);
printf("\t%sa = m68k_areg(regs, %s);\n", name, reg);
+ if ((flags & GF_NOFETCH) && using_prefetch) {
+ addcycles000(4);
+ }
break;
case Apdi: // -(An)
switch (fetchmode)
default:
term ();
}
- if (!(flags & GF_APDI)) {
+ if (flags & GF_NOFETCH) {
+ if (using_prefetch) {
+ addcycles000(4);
+ }
+ insn_n_cycles += 2;
+ count_cycles_ea += 2;
+ } else if (!(flags & GF_APDI)) {
addcycles000 (2);
insn_n_cycles += 2;
count_cycles_ea += 2;
insn_n_cycles += 4;
printf("\t%sa = %s(m68k_areg(regs, %s), %d);\n", name, disp020, reg, disp020cnt++);
} else {
- if (!(flags & GF_AD8R)) {
+ if (!(flags & GF_AD8R) && !(flags & GF_NOFETCH) && !(flags & GF_CLR68010)) {
addcycles000 (2);
insn_n_cycles += 2;
count_cycles_ea += 2;
}
count_read_ea++;
}
+ if ((flags & GF_NOFETCH) && using_prefetch) {
+ addcycles000(4);
+ insn_n_cycles += 4;
+ count_cycles_ea += 4;
+ }
+ if ((flags & GF_CLR68010) && using_prefetch) {
+ addcycles000(4);
+ insn_n_cycles += 4;
+ count_cycles_ea += 4;
+ }
addr = true;
break;
case PC8r: // (d8,PC,Xn)
printf("\t%sa = %s(tmppc, %s);\n", name, disp000, gen_nextiword (flags));
}
}
+ if ((flags & GF_NOFETCH) && using_prefetch) {
+ addcycles000(4);
+ }
addr = true;
break;
case absw:
switch (size) {
case sz_byte:
{
- insn_n_cycles += 4; printf("\tuae_s8 %s = %s(%sa);\n", name, srcbx, name);
+ insn_n_cycles += 4;
+ printf("\tuae_s8 %s = %s(%sa);\n", name, srcbx, name);
count_read++;
check_bus_error(name, 0, 0, 0, NULL, 1);
break;
}
case sz_word:
{
- insn_n_cycles += 4; printf("\tuae_s16 %s = %s(%sa);\n", name, srcwx, name);
+ insn_n_cycles += 4;
+ printf("\tuae_s16 %s = %s(%sa);\n", name, srcwx, name);
count_read++;
check_bus_error(name, 0, 0, 1, NULL, 1);
break;
printf("\tuae_s32 %s = %s(%sa + 2);\n", name, srcwx, name);
count_read++;
check_bus_error(name, 0, 0, 1, NULL, 1);
- printf("\t%s |= %s(%sa) << 16; \n", name, srcw, name);
+ printf("\t%s |= %s(%sa) << 16; \n", name, srcwx, name);
count_read++;
check_bus_error(name, -2, 0, 1, NULL, 1);
} else {
printf("\tuae_s32 %s = %s(%sa) << 16;\n", name, srcwx, name);
count_read++;
check_bus_error(name, 0, 0, 1, NULL, 1);
- printf("\t%s |= %s(%sa + 2); \n", name, srcw, name);
+ printf("\t%s |= %s(%sa + 2); \n", name, srcwx, name);
count_read++;
check_bus_error(name, 2, 0, 1, NULL, 1);
}
if (strcmp (rmw_varname, to) != 0)
candormw = false;
}
+
+ loopmode_access();
+
genastore_done = true;
if (!(flags & GF_LRMW)) {
returntail(mode != Dreg && mode != Areg);
if (flags & GF_SECONDWORDSETFLAGS) {
genflags(flag_logical, g_instr->size, "src", "", "");
}
- printf("%s(%sa, %s >> 16);\n", dstwx, to, from);
+ printf("\t%s(%sa, %s >> 16);\n", dstwx, to, from);
sprintf(tmp, "%s >> 16", from);
count_write++;
check_bus_error(to, 0, 1, 1, tmp, 1);
if (curi->mnemo == i_DBcc || loopmode) {
next_level_000();
}
+ loopmode_start();
}
// do not unnecessarily create useless mmuop030
if (cpu_level == 0) {
c += 2;
}
+ if (cpu_level == 1 && curi->smode == immi) {
+ c += 2;
+ }
fill_prefetch_next_after(1, "\t\tccr_68000_long_move_ae_LZN(src);\n\t\tdreg_68000_long_replace_low(dstreg, src);\n");
} else {
fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, src);\n");
}
+ loopmodeextra = 4;
} else {
fill_prefetch_next_after(0, "\t\tccr_68000_long_move_ae_LZN(src);\n");
}
fill_prefetch_next_after(1, NULL);
} else {
fill_prefetch_next_t();
+ loopmodeextra = 4;
}
if (c > 0)
addcycles000(c);
if (cpu_level == 0) {
c += 2;
}
+ if (cpu_level == 1 && curi->smode == immi) {
+ c += 2;
+ }
fill_prefetch_next_after(1,
"\t\tuae_s16 bnewv = (uae_s16)dst - (uae_s16)src;\n"
"\t\tint bflgs = ((uae_s16)(src)) < 0;\n"
} else {
fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, newv);\n");
}
+ loopmodeextra = 4;
} else {
fill_prefetch_next_after(0,
"\t\tuae_s16 bnewv = (uae_s16)dst - (uae_s16)src;\n"
fill_prefetch_next_after(1, NULL);
} else {
fill_prefetch_next_t();
+ loopmodeextra = 4;
}
if (c > 0)
addcycles000(c);
c += 4;
} else {
c = curi->size == sz_long ? 2 : 4;
- if (islongimm (curi))
+ if (islongimm(curi)) {
c += 2;
+ }
+ loopmodeextra = curi->size == sz_long ? 4 : 2;
}
fill_prefetch_next_after(0, "\t\tareg_68000_long_replace_low(dstreg, newv);\n");
- if (c > 0)
- addcycles000 (c);
+ if (c > 0) {
+ addcycles000(c);
+ }
genastore ("newv", curi->dmode, "dstreg", sz_long, "dst");
break;
}
if (cpu_level == 0) {
c += 2;
}
+ if (cpu_level == 1 && curi->smode == immi) {
+ // 68010 Immediate long instructions 2 cycles faster, Q variants have same speed.
+ c += 2;
+ }
fill_prefetch_next_after(1,
"\t\tuae_s16 bnewv = (uae_s16)dst + (uae_s16)src;\n"
"\t\tint bflgs = ((uae_s16)(src)) < 0;\n"
} else {
fill_prefetch_next_after(1, "\t\tdreg_68000_long_replace_low(dstreg, newv);\n");
}
+ loopmodeextra = 4;
} else {
fill_prefetch_next_after(0,
"\t\tuae_s16 bnewv = (uae_s16)dst + (uae_s16)src;\n"
fill_prefetch_next_after(1, NULL);
} else {
fill_prefetch_next_t();
+ loopmodeextra = 4;
}
if (c > 0)
addcycles000(c);
c += 4;
} else {
c = curi->size == sz_long ? 2 : 4;
- if (islongimm (curi))
+ if (islongimm(curi)) {
c += 2;
+ }
+ loopmodeextra = curi->size == sz_long ? 4 : 2;
}
fill_prefetch_next_after(1, "\t\tareg_68000_long_replace_low(dstreg, newv);\n");
- if (c > 0)
- addcycles000 (c);
+ if (c > 0) {
+ addcycles000(c);
+ }
genastore("newv", curi->dmode, "dstreg", sz_long, "dst");
break;
}
genastore_rev("0", curi->smode, "srcreg", curi->size, "src");
}
} else if (cpu_level == 1) {
- genamode(curi, curi->smode, "srcreg", curi->size, "src", 3, 0, 0);
- if (isreg(curi->smode) && curi->size == sz_long)
+ genamode(curi, curi->smode, "srcreg", curi->size, "src", 3, 0, GF_CLR68010);
+ if (isreg(curi->smode) && curi->size == sz_long) {
addcycles000(2);
+ }
if (!isreg(curi->smode) && using_exception_3 && curi->size != sz_byte && (using_prefetch || using_ce)) {
printf("\tif(srca & 1) {\n");
if (curi->size == sz_word) {
}
bsetcycles(curi);
// bclr needs 1 extra cycle
- if (curi->mnemo == i_BCLR && curi->dmode == Dreg)
- addcycles000 (2);
+ if (curi->mnemo == i_BCLR && curi->dmode == Dreg) {
+ addcycles000(2);
+ }
+ if (curi->mnemo == i_BCLR && curi->size == sz_byte) {
+ if (cpu_level == 1) {
+ // 68010 BCLR.B is 2 cycles slower
+ addcycles000(2);
+ }
+ next_level_000();
+ }
if (curi->mnemo == i_BCHG) {
printf("\tdst ^= (1 << src);\n");
printf("\tSET_ZFLG(((uae_u32)dst & (1 << src)) >> src);\n");
/* The next two are coded a little unconventional, but they are doing
* weird things... */
case i_MVPRM: // MOVEP R->M
- genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+ genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, cpu_level == 1 ? GF_NOFETCH : 0);
printf("\tuaecptr mempa = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
check_prefetch_buserror(m68k_pc_offset);
if (curi->size == sz_word) {
case i_MVPMR: // MOVEP M->R
printf("\tuaecptr mempa = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword (0));
check_prefetch_buserror(m68k_pc_offset);
- genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0);
+ genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0);
if (curi->size == sz_word) {
printf("\tuae_u16 val = (%s(mempa) & 0xff) << 8;\n", srcb);
count_read++;
}
break;
case i_MVSR2: // MOVE FROM SR
- genamode (curi, curi->smode, "srcreg", sz_word, "src", cpu_level == 0 ? 2 : 3, 0, 0);
+ next_level_000();
+ genamode (curi, curi->smode, "srcreg", sz_word, "src", cpu_level == 0 ? 2 : 3, 0, cpu_level == 1 ? GF_NOFETCH : 0);
printf("\tMakeSR();\n");
if (isreg (curi->smode)) {
if (cpu_level == 0 && curi->size == sz_word) {
} else {
fill_prefetch_next_after(1, NULL);
}
- addcycles000 (2);
+ if (cpu_level == 0) {
+ addcycles000(2);
+ }
} else {
// 68000: read first and ignore result
if (cpu_level == 0 && curi->size == sz_word) {
clear_m68k_offset();
break;
case i_MVR2USP:
+ next_level_000();
genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
printf("\tregs.usp = src;\n");
+ if (cpu_level == 1) {
+ addcycles000(2);
+ }
fill_prefetch_next_t();
trace_t0_68040_only();
break;
case i_MVUSP2R:
+ next_level_000();
genamode(curi, curi->smode, "srcreg", curi->size, "src", 2, 0, 0);
genastore("regs.usp", curi->smode, "srcreg", curi->size, "src");
+ if (cpu_level == 1) {
+ addcycles000(2);
+ }
fill_prefetch_next_t();
break;
case i_RESET:
// 68010
int old_brace_level = n_braces;
printf("\tuaecptr oldpc = %s;\n", getpc);
- printf("\tuae_u16 newsr; uae_u32 newpc;\n");
+ printf("\tuae_u16 newsr;\n");
+ printf("\tuae_u32 newpc;\n");
printf("\tuaecptr a = m68k_areg(regs, 7);\n");
+ printf("\tuae_u16 sr = %s(a);\n", srcw);
+ count_read++;
+ check_bus_error("", 0, 0, 1, NULL, 1);
+ printf("\tuae_u32 pc = %s(a + 2) << 16;\n", srcw);
+ count_read++;
+ check_bus_error("", 2, 0, 1, NULL, 1);
+
printf("\tuae_u16 format = %s(a + 2 + 4);\n", srcw);
count_read++;
check_bus_error("", 6, 0, 1, NULL, 1);
printf("\t\tException_cpu(14);\n");
write_return_cycles("\t\t", 0);
printf("\t}\n");
- printf("\tuae_u16 sr = %s(a);\n", srcw);
- count_read++;
- check_bus_error("", 0, 0, 1, NULL, 1);
- printf("\tuae_u32 pc = %s(a + 2) << 16;\n", srcw);
- count_read++;
- check_bus_error("", 2, 0, 1, NULL, 1);
+
printf("\tpc |= %s(a + 4); \n", srcw);
count_read++;
check_bus_error("", 4, 0, 1, NULL, 1);
printf("\tm68k_areg(regs, 7) += offs;\n");
} else {
genamode (NULL, Aipi, "7", sz_long, "pc", 1, 0, 0);
- genamode (curi, curi->smode, "srcreg", curi->size, "offs", 1, 0, 0);
+ genamode (curi, curi->smode, "srcreg", curi->size, "offs", 1, 0, GF_NOREFILL);
printf("\tm68k_areg(regs, 7) += offs;\n");
}
printf("\tif (pc & 1) {\n");
break;
case i_TRAPV:
sync_m68k_pc();
- // TRAPV is really weird
- // If V is set but prefetch causes bus error: S is set.
- // for some reason T is also cleared!
- if (using_prefetch) {
- printf("\tuae_u16 opcode_v = opcode;\n");
- }
- fill_prefetch_next_after(1,
- "\t\tif (GET_VFLG()) {\n"
- "\t\t\tMakeSR();\n"
- "\t\t\tregs.sr |= 0x2000;\n"
- "\t\t\tregs.sr &= ~0x8000;\n"
- "\t\t\tMakeFromSR();\n"
- "\t\t} else {\n"
- "\t\t\topcode = regs.ir | 0x20000;\n"
- "\t\t\tif(regs.t1) opcode |= 0x10000;\n"
- "\t\t}\n");
- printf("\tif (GET_VFLG()) {\n");
- if (using_prefetch) {
- // If exception vector is odd,
- // stacked opcode is TRAPV
- printf("\t\tregs.ir = opcode_v;\n");
+ next_level_000();
+ if (cpu_level == 0) {
+ // 68000 TRAPV is really weird
+ // If V is set but prefetch causes bus error: S is set.
+ // for some reason T is also cleared!
+ if (using_prefetch) {
+ printf("\tuae_u16 opcode_v = opcode;\n");
+ }
+ fill_prefetch_next_after(1,
+ "\t\tif (GET_VFLG()) {\n"
+ "\t\t\tMakeSR();\n"
+ "\t\t\tregs.sr |= 0x2000;\n"
+ "\t\t\tregs.sr &= ~0x8000;\n"
+ "\t\t\tMakeFromSR();\n"
+ "\t\t} else {\n"
+ "\t\t\topcode = regs.ir | 0x20000;\n"
+ "\t\t\tif(regs.t1) opcode |= 0x10000;\n"
+ "\t\t}\n");
+ printf("\tif (GET_VFLG()) {\n");
+ if (using_prefetch) {
+ // If exception vector is odd,
+ // stacked opcode is TRAPV
+ printf("\t\tregs.ir = opcode_v;\n");
+ }
+ printf("\t\tException_cpu(7);\n");
+ write_return_cycles("\t\t", 0);
+ printf("\t}\n");
+ } else if (cpu_level == 1) {
+ push_ins_cnt();
+ printf("\tif (GET_VFLG()) {\n");
+ addcycles000(2);
+ printf("\t\tException_cpu(7);\n");
+ write_return_cycles("\t\t", 0);
+ printf("\t}\n");
+ pop_ins_cnt();
+ fill_prefetch_next();
+ } else {
+ fill_prefetch_next();
+ printf("\tif (GET_VFLG()) {\n");
+ printf("\t\tException_cpu(7);\n");
+ write_return_cycles("\t\t", 0);
+ printf("\t}\n");
}
- printf("\t\tException_cpu(7);\n");
- write_return_cycles("\t\t", 0);
- printf("\t}\n");
break;
case i_RTR:
printf("\tuaecptr oldpc = %s;\n", getpc);
curi->smode, "srcreg", curi->size, "src", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0),
curi->dmode, "dstreg", curi->size, "offs", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0));
if (cpu_level == 1) {
- printf("\tregs.loop_mode = false;\n");
+ printf("\tint was_loop_mode = regs.loop_mode;\n");
+ printf("\tregs.loop_mode = 0;\n");
}
printf("\tuaecptr oldpc = %s;\n", getpc);
- addcycles000 (2);
+ addcycles000(2);
+ addcycles000_nonce("\t", 2);
if (using_exception_3 && cpu_level >= 4) {
printf("\tif (offs & 1) {\n");
printf("\t\t\texception3i(opcode, oldpc + (uae_s32)offs + 2);\n");
// 68010 loop mode handling
if (cpu_level == 1) {
printf("\t\tif(offs == -4 && !regs.t1 && loop_mode_table[regs.ird]) {\n");
- printf("\t\t\tregs.loop_mode = true;\n");
+ // first loop takes as many cycles as normal DBcc branch
+ // perhaps it also does actual prefetches??
+ printf("\t\t\tif(!was_loop_mode) {\n");
+ addcycles000(6);
+ addcycles000_nonce("\t\t", 6);
+ printf("\t\t\t}\n");
+ printf("\t\t\tregs.loop_mode = 1;\n");
printf("\t\t\tsrc = m68k_dreg(regs, srcreg);\n");
genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src");
addcycles000(2);
+ addcycles000_nonce("\t\t", 2);
printf("\t\t\tif (src) {\n");
if (using_ce) {
printf("\t\t\t\tloop_mode_table[regs.ird](regs.ird);\n");
} else {
printf("\t\t\t\tcount_cycles += loop_mode_table[regs.ird](regs.ird);\n");
}
+
+ printf("\t // quick exit if condition false and count expired\n");
+ printf("\t\t\t\tif (!cctrue(%d) && (m68k_dreg(regs, srcreg) & 0xffff) == 0) {\n", curi->cc);
+ printf("\t\t\t\t\tm68k_dreg(regs, srcreg) |= 0xffff;\n");
+
+ printf("\t // loop exit: add possible extra cycle(s)\n");
+ printf("\t\t\t\t\tif(regs.loop_mode >> 16) {\n");
+ if (using_ce) {
+ printf("\t\t\t\t\t\t%s(regs.loop_mode >> 16);\n", do_cycles);
+ }
+ addcycles000_nonces("\t\t\t\t\t\t", "regs.loop_mode >> 16");
+ printf("\t\t\t\t\t}\n");
+
+ printf("\t\t\t\t\tregs.loop_mode = 0;\n");
+ setpc("oldpc + %d", m68k_pc_offset);
+ int old_m68k_pc_offset = m68k_pc_offset;
+ int old_m68k_pc_total = m68k_pc_total;
+ clear_m68k_offset();
+ get_prefetch_020_continue();
+ fill_prefetch_full_000_special();
+ returncycles("\t\t\t", 8);
+ m68k_pc_offset = old_m68k_pc_offset;
+ m68k_pc_total = old_m68k_pc_total;
+ printf("\t\t\t\t}\n");
+
+ printf("\t // loop continue: add possible extra cycle(s)\n");
+ printf("\t\t\t\tif(regs.loop_mode & 0xfffe) {\n");
+ addcycles000_nonces("\t\t\t\t\t", "regs.loop_mode & 0xfffe");
+ if (using_ce) {
+ printf("\t\t\t\t\t%s(regs.loop_mode & 0xfffe);\n", do_cycles);
+ }
+ printf("\t\t\t\t}\n");
+
setpc("oldpc");
check_ipl();
- addcycles000(2);
- returncycles("\t\t\t\t", 4);
- printf("\t\t\t} else {\n");
- addcycles000(2);
+ returncycles("\t\t\t\t", 0);
printf("\t\t\t}\n");
- printf("\t\t\tregs.loop_mode = false;\n");
+ printf("\t\t\tregs.loop_mode = 0;\n");
setpc("oldpc + %d", m68k_pc_offset);
fill_prefetch_full_000_special();
- returncycles("\t\t\t", 6);
+ returncycles("\t\t\t", 8);
printf("\t\t}\n");
}
printf("\t");
fill_prefetch_1(0);
printf("\t");
- if (cpu_level < 2 || cpu_level >= 4)
- genastore ("(src - 1)", curi->smode, "srcreg", curi->size, "src");
+ if (cpu_level < 2 || cpu_level >= 4) {
+ genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src");
+ }
printf("\t\tif (src) {\n");
irc2ir ();
add_head_cycs (6);
next_level_040_to_030();
break;
case i_Scc:
- // confirmed
next_level_000();
- genamode(curi, curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, 0);
+ genamode(curi, curi->smode, "srcreg", curi->size, "src", cpu_level == 0 ? 1 : 2, 0, cpu_level == 1 ? GF_NOFETCH : 0);
if (isreg(curi->smode)) {
// If mode is Dn and condition true = 2 extra cycles needed.
printf("\tint val = cctrue(%d) ? 0xff : 0x00;\n", curi->cc);
printf("\tSET_CFLG (cflg);\n");
duplicate_carry (0);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_ASLW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
duplicate_carry (0);
printf("\tSET_VFLG (GET_VFLG () | (sign2 != sign));\n");
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_LSRW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
printf("\tSET_CFLG (carry);\n");
duplicate_carry (0);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_LSLW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
duplicate_carry (0);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_ROLW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
genflags (flag_logical, curi->size, "val", "", "");
printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_RORW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
genflags (flag_logical, curi->size, "val", "", "");
printf("\tSET_CFLG (carry);\n");
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_ROXLW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
printf("\tSET_CFLG (carry >> %d);\n", bit_size (curi->size) - 1);
duplicate_carry (0);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_ROXRW:
genamode (curi, curi->smode, "srcreg", curi->size, "data", 1, 0, GF_RMW);
printf("\tSET_CFLG (carry);\n");
duplicate_carry (0);
genastore ("val", curi->smode, "srcreg", curi->size, "data");
+ loopmodeextra = 2;
break;
case i_MOVEC2:
- genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
- fill_prefetch_next ();
- start_brace ();
+ if (cpu_level == 1) {
+ printf("\tif(!regs.s) {\n");
+ printf("\t\tException(8);\n");
+ write_return_cycles_none("\t\t");
+ printf("\t}\n");
+ }
+ genamode(curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
+ fill_prefetch_next();
printf("\tint regno = (src >> 12) & 15;\n");
printf("\tuae_u32 *regp = regs.regs + regno;\n");
printf("\tif (!m68k_movec2(src & 0xFFF, regp)) {\n");
write_return_cycles("\t\t", 0);
printf("\t}\n");
- addcycles000(2);
+ addcycles000(4);
trace_t0_68040_only();
break;
case i_MOVE2C:
+ if (cpu_level == 1) {
+ printf("\tif(!regs.s) {\n");
+ printf("\t\tException(8);\n");
+ write_return_cycles_none("\t\t");
+ printf("\t}\n");
+ }
genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
fill_prefetch_next ();
- start_brace ();
printf("\tint regno = (src >> 12) & 15;\n");
printf("\tuae_u32 *regp = regs.regs + regno;\n");
printf("\tif (!m68k_move2c(src & 0xFFF, regp)) {\n");
write_return_cycles("\t\t", 0);
printf("\t}\n");
- addcycles000(4);
+ addcycles000(2);
trace_t0_68040_only();
break;
case i_CAS:
break;
case i_MOVES: /* ignore DFC and SFC when using_mmu == false */
{
- int old_brace_level;
tail_ce020_done = true;
genamode (curi, curi->smode, "srcreg", curi->size, "extra", 1, 0, 0);
+ strcpy(g_srcname, "src");
+ addcycles000(4);
printf("if (extra & 0x800) {\n");
{
+ int srcdone = 0;
int old_m68k_pc_offset = m68k_pc_offset;
int old_m68k_pc_total = m68k_pc_total;
- old_brace_level = n_braces;
- start_brace ();
- // 68060 stores original value
- if (cpu_level == 5) {
- printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n");
- }
- genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, 0);
+ push_ins_cnt();
+ // 68060 stores original value, 68010 MOVES.L also stores original value.
+ printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n");
+ genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 2, 0, cpu_level == 1 ? GF_NOFETCH : 0);
tail_ce020_done = false;
returntail(false);
did_prefetch = 0;
// Earlier models do -(an)/(an)+ EA calculation first
- if (cpu_level <= 4) {
- printf("\tuae_u32 src = regs.regs[(extra >> 12) & 15];\n");
+ if (!(cpu_level == 5 || (curi->dmode != Aipi && curi->dmode != Apdi) || (cpu_level == 1 && curi->size == sz_long))) {
+ printf("\tsrc = regs.regs[(extra >> 12) & 15];\n");
}
genastore_fc ("src", curi->dmode, "dstreg", curi->size, "dst");
sync_m68k_pc();
- pop_braces(old_brace_level);
+ pop_ins_cnt();
m68k_pc_offset = old_m68k_pc_offset;
m68k_pc_total = old_m68k_pc_total;
}
printf("} else {\n");
{
- start_brace();
- genamode(curi, curi->dmode, "dstreg", curi->size, "src", 1, 0, GF_FC);
+ genamode(curi, curi->dmode, "dstreg", curi->size, "src", 1, 0, GF_FC | (cpu_level == 1 ? GF_NOFETCH : 0));
printf("\tif (extra & 0x8000) {\n");
switch (curi->size) {
case sz_byte: printf("\tm68k_areg(regs, (extra >> 12) & 7) = (uae_s32)(uae_s8)src;\n"); break;
sync_m68k_pc();
tail_ce020_done = false;
returntail(false);
- pop_braces(old_brace_level);
}
printf("}\n");
trace_t0_68040_only();
+ fill_prefetch_next();
+ next_level_060_to_040();
}
break;
case i_BKPT: /* only needed for hardware emulators */
sync_m68k_pc ();
+ addcycles000(4);
printf("\top_illg (opcode);\n");
did_prefetch = -1;
break;
break;
}
end:
+ if (loopmode && loopmodeextra) {
+ printf("\tif (loop_mode) {\n");
+ addcycles000_onlyce(loopmodeextra);
+ addcycles000_nonce("\t\t", loopmodeextra);
+ printf("\t}\n");
+ }
+ loopmode_stop();
if (!genastore_done)
returntail (0);
finish_braces ();
uae_u32 chipset_latch_read;
uae_u32 chipset_latch_write;
uae_u16 db, write_buffer, read_buffer;
- bool loop_mode;
+ int loop_mode;
uaecptr usp, isp, msp;
uae_u16 sr;
start = 0;
else if (nr >= 32 && nr < 32 + 16) // TRAP #x
start = 4;
- else if (nr == 4 || nr == 5 || nr == 6 || nr == 8 || nr == 9 || nr == 10 || nr == 11) // ILLG, DIVBYZERO, PRIV, TRACE, LINEA, LINEF
+ else if (nr == 4 || nr == 5 || nr == 6 || nr == 8 || nr == 9 || nr == 10 || nr == 11 || nr == 14) // ILLG, DIVBYZERO, PRIV, TRACE, LINEA, LINEF, RTE
start = 4;
}
{
int cycles;
- if (currprefs.cpu_model > 68000)
- return;
- if (nr >= 24 && nr <= 31) {
- /* Interrupts */
- cycles = 44 + 4;
- } else if (nr >= 32 && nr <= 47) {
- /* Trap (total is 34, but cpuemux.c already adds 4) */
- cycles = 34 - 4;
- } else {
- switch (nr)
- {
+ if (currprefs.cpu_model == 68000) {
+ if (nr >= 24 && nr <= 31) {
+ /* Interrupts */
+ cycles = 44 + 4;
+ } else if (nr >= 32 && nr <= 47) {
+ /* Trap (total is 34, but cpuemux.c already adds 4) */
+ cycles = 34 - 4;
+ } else {
+ switch (nr)
+ {
case 2: cycles = 50; break; /* Bus error */
case 3: cycles = 50; break; /* Address error */
case 4: cycles = 34; break; /* Illegal instruction */
case 10: cycles = 34; break; /* Line-A */
case 11: cycles = 34; break; /* Line-F */
default:
- cycles = 4;
- break;
+ cycles = 4;
+ break;
+ }
}
+ } else if (currprefs.cpu_model == 68010) {
+ if (nr >= 24 && nr <= 31) {
+ /* Interrupts */
+ cycles = 48 + 4;
+ } else if (nr >= 32 && nr <= 47) {
+ /* Trap */
+ cycles = 38 - 4;
+ } else {
+ switch (nr)
+ {
+ case 2: cycles = 126; break; /* Bus error */
+ case 3: cycles = 126; break; /* Address error */
+ case 4: cycles = 38; break; /* Illegal instruction */
+ case 5: cycles = 38; break; /* Division by zero */
+ case 6: cycles = 38; break; /* CHK */
+ case 7: cycles = 40; break; /* TRAPV */
+ case 8: cycles = 38; break; /* Privilege violation */
+ case 9: cycles = 38; break; /* Trace */
+ case 10: cycles = 38; break; /* Line-A */
+ case 11: cycles = 38; break; /* Line-F */
+ case 14: cycles = 38; break; /* RTE frame error */
+ default:
+ cycles = 4;
+ break;
+ }
+ }
+ } else {
+ return;
}
cycles = adjust_cycles(cycles * CYCLE_UNIT / 2);
x_do_cycles(cycles);
x_put_word (m68k_areg (regs, 7), 0x1000 + vector_nr * 4);
}
} else {
+ add_approximate_exception_cycles(nr);
Exception_build_stack_frame_common(oldpc, currpc, regs.mmu_ssw, nr);
used_exception_build_stack_frame = true;
}
int cycles = 0;
if (currprefs.cpu_model == 68000) {
cycles = 38 - 4;
+ for (int bits = 0; bits < 16 && src; bits++, src >>= 1) {
+ if (src & 1)
+ cycles += 2;
+ }
} else {
- cycles = 8 - 4;
- }
- for (int bits = 0; bits < 16 && src; bits++, src >>= 1) {
- if (src & 1)
- cycles += 2;
+ cycles = 40 - 4;
}
return cycles;
}
int cycles;
if (currprefs.cpu_model == 68000) {
cycles = 38 - 4;
+ uae_u32 usrc = ((uae_u32)src) << 1;
+ for (int bits = 0; bits < 16 && usrc; bits++, usrc >>= 1) {
+ if ((usrc & 3) == 1 || (usrc & 3) == 2) {
+ cycles += 2;
+ }
+ }
} else {
- cycles = 10 - 4;
- }
- uae_u32 usrc = ((uae_u32)src) << 1;
- for (int bits = 0; bits < 16 && usrc; bits++, usrc >>= 1) {
- if ((usrc & 3) == 1 || (usrc & 3) == 2) {
+ cycles = 40 - 4;
+ // 2 extra cycles added if source is negative
+ if (src & 0x8000)
cycles += 2;
- }
}
return cycles;
}
if (divisor == 0)
return 0;
+ if (currprefs.cpu_model == 68010) {
+ // Overflow
+ if ((dividend >> 16) >= divisor)
+ return 4;
+ return 104;
+ }
+
// Overflow
if ((dividend >> 16) >= divisor)
return (mcycles = 5) * 2 - 4;
- if (currprefs.cpu_model == 68000) {
- mcycles = 38;
- } else {
- mcycles = 22;
- }
+ mcycles = 38;
hdivisor = divisor << 16;
if (divisor == 0)
return 0;
+ if (currprefs.cpu_model == 68010) {
+ // Check for absolute overflow
+ if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor))
+ return 12;
+ mcycles = 116;
+ // add 2 extra cycles if negative dividend
+ if (dividend < 0)
+ mcycles += 2;
+ return mcycles;
+ }
+
mcycles = 6;
if (dividend < 0)
// Absolute quotient
aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor);
- if (currprefs.cpu_model == 68000) {
- mcycles += 55;
- } else {
- mcycles += 37;
- }
+ mcycles += 55;
if (divisor >= 0) {
if (dividend >= 0)
(!c->duse || (isreg(c->smode) && !isreg(c->dmode)) || (!isreg(c->smode) && isreg(c->dmode)) || (!isreg(c->smode) && !isreg(c->dmode)))) {
loopmode = true;
}
- if (c->mnemo == i_MOVE) {
- // move x,dn: not supported
+ if (c->mnemo == i_MOVE || c->mnemo == i_MOVEA) {
+ // move x,reg: not supported
if (isreg(c->dmode))
loopmode = false;
// move reg,-(an): not supported
0000 1010 11ss sSSS:200:?????:?????:13: CAS.B #1,s[!Dreg,Areg,Immd,PC8r,PC16]
0000 1100 11ss sSSS:200:?????:?????:13: CAS.W #1,s[!Dreg,Areg,Immd,PC8r,PC16]
0000 1100 1111 1100:250:?????:?????:10: CAS2.W #2
-0000 1110 zzss sSSS:202:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16]
+0000 1110 zzss sSSS:102:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16]
0000 1110 11ss sSSS:200:?????:?????:13: CAS.L #1,s[!Dreg,Areg,Immd,PC8r,PC16]
0000 1110 1111 1100:250:?????:?????:10: CAS2.L #2
0100 1000 00dd dDDD:000:X?Z?C:X-Z--:30: NBCD.B d[!Areg]
- 0 0 6
-0100 1000 0100 1kkk:200:?????:?????:10: BKPT #k
+0100 1000 0100 1kkk:100:?????:?????:10: BKPT #k
0100 1000 01ss sSSS:000:-NZ00:-----:30: SWAP.W s[Dreg]
- 4 0 4