static uae_u32 addressing_mask;
static int opcodecnt;
static int cpu_stopped;
+static int cpu_halted;
static int cpu_lvl = 0;
static int test_count;
static int testing_active;
+static uae_u16 testing_active_opcode;
static time_t starttime;
static int filecount;
static uae_u16 sr_undefined_mask;
static struct accesshistory ahist[MAX_ACCESSHIST];
static struct accesshistory ahist2[MAX_ACCESSHIST];
+static int is_superstack_use_required(void)
+{
+ switch (testing_active_opcode)
+ {
+ case 0x4e73: // RTE
+ return 1;
+ }
+ return 0;
+}
+
#define OPCODE_AREA 32
static bool valid_address(uaecptr addr, int size, int w)
test_memory_accessed = w ? -1 : 1;
return 1;
}
+ if (addr >= test_memory_end - RESERVED_SUPERSTACK && addr + size < test_memory_end) {
+ // allow only instructions that have to access super stack, for example RTE
+ // read-only
+ if (w)
+ goto oob;
+ if (testing_active) {
+ if (is_superstack_use_required()) {
+ test_memory_accessed = 1;
+ return 1;
+ }
+ }
+ }
oob:
return 0;
}
put_long_test(addr, v);
}
-uae_u16 get_wordi_test(uaecptr addr)
+uae_u16 get_wordi_test(int o)
{
- return get_word_test(addr);
+ uae_u32 v = get_word_test_prefetch(o);
+ regs.pc += 2;
+ return v;
}
uae_u32 memory_get_byte(uaecptr addr)
MakeFromSR_x(0);
}
+void cpu_halt(int halt)
+{
+ cpu_halted = halt;
+}
+
static void exception_check_trace(int nr)
{
SPCFLAG_TRACE = 0;
void cpureset(void)
{
- test_exception = 1;
+ cpu_halted = -1;
}
static void doexcstack(void)
if (opcodecnt == 1) {
// STOP #xxxx: test all combinations
// (also includes RTD)
- put_word_test(pc, imm16_cnt++);
+ if (dp->mnemo == i_LPSTOP) {
+ uae_u16 lp = 0x01c0;
+ if (imm16_cnt & (0x40 | 0x80)) {
+ for (;;) {
+ lp = rand16();
+ if (lp != 0x01c0)
+ break;
+ }
+ }
+ put_word_test(pc, lp);
+ put_word_test(pc + 2, imm16_cnt++);
+ pc += 2;
+ } else {
+ put_word_test(pc, imm16_cnt++);
+ }
if (imm16_cnt == 0)
*isconstant = 0;
else
}
}
+static uae_u32 generate_stack_return(int cnt)
+{
+ uae_u32 v = rand32();
+ switch (cnt & 3)
+ {
+ case 0:
+ case 3:
+ v = opcode_memory_start + 128;
+ break;
+ case 1:
+ v &= 0xffff;
+ if (test_low_memory_start == 0xffffffff)
+ v |= 0x8000;
+ if (test_high_memory_start == 0xffffffff)
+ v &= 0x7fff;
+ break;
+ case 2:
+ v = opcode_memory_start + (uae_s16)v;
+ break;
+ }
+ if (!feature_exception3_instruction)
+ v &= ~1;
+ return v;
+}
+
+static int handle_rte(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant, uaecptr addr)
+{
+ // skip bus error/address error frames because internal fields can't be simply randomized
+ int offset = 2;
+ int frame, v;
+
+ imm_special++;
+ for (;;) {
+ frame = (imm_special >> 2) & 15;
+ // 68010 bus/address error
+ if (cpu_lvl == 1 && (frame == 8)) {
+ imm_special += 4;
+ continue;
+ }
+ if ((cpu_lvl == 2 || cpu_lvl == 3) && (frame == 9 || frame == 10 || frame == 11)) {
+ imm_special += 4;
+ continue;
+ }
+ // 68040 FP post-instruction, FP unimplemented, Address error
+ if (cpu_lvl == 4 && (frame == 3 || frame == 4 || frame == 7)) {
+ imm_special += 4;
+ continue;
+ }
+ // 68060 access fault/FP disabled, FP post-instruction
+ if (cpu_lvl == 5 && (frame == 3 || frame == 4)) {
+ imm_special += 4;
+ continue;
+ }
+ // throwaway frame
+ if (frame == 1) {
+ imm_special += 4;
+ continue;
+ }
+ break;
+ }
+ v = imm_special >> 6;
+ uae_u16 sr = v & 31;
+ sr |= (v >> 5) << 12;
+ put_word_test(addr, sr);
+ addr += 2 + 4;
+ // frame + vector offset
+ put_word_test(addr, (frame << 12) | (rand16() & 0x0fff));
+ addr += 2;
+#if 0
+ if (frame == 1) {
+ int imm_special_tmp = imm_special;
+ imm_special &= ~(15 << 2);
+ if (rand8() & 1)
+ imm_special |= 2 << 2;
+ handle_rte(opcode, addr, dp, isconstant, addr);
+ imm_special = imm_special_tmp;
+ v = generate_stack_return(imm_special);
+ put_long_test(addr + 2, v);
+ offset += 8 + 2;
+#endif
+ if (frame == 2) {
+ put_long_test(addr, rand32());
+ }
+ return offset;
+}
+
static int handle_specials_stack(uae_u16 opcode, uaecptr pc, struct instr *dp, int *isconstant)
{
int offset = 0;
if (dp->mnemo == i_RTE || dp->mnemo == i_RTD || dp->mnemo == i_RTS || dp->mnemo == i_RTR || dp->mnemo == i_UNLK) {
uae_u32 v;
uaecptr addr = regs.regs[8 + 7];
- imm_special++;
// RTE, RTD, RTS and RTR
if (dp->mnemo == i_RTR) {
// RTR
- v = imm_special;
+ v = imm_special++;
uae_u16 ccr = v & 31;
ccr |= rand16() & ~31;
put_word_test(addr, ccr);
} else if (dp->mnemo == i_RTE) {
// RTE
if (currprefs.cpu_model == 68000) {
+ imm_special++;
v = imm_special >> 2;
uae_u16 sr = v & 31;
sr |= (v >> 5) << 12;
addr += 2;
offset += 2;
} else {
- // TODO 68010+ RTE
+ offset += handle_rte(opcode, pc, dp, isconstant, addr);
+ addr += 2;
}
*isconstant = imm_special >= (1 << (4 + 5)) * 4 ? 0 : -1;
} else if (dp->mnemo == i_RTS) {
// RTS
*isconstant = imm_special >= 256 ? 0 : -1;
}
- v = rand32();
- switch (imm_special & 3)
- {
- case 0:
- case 3:
- v = opcode_memory_start + 128;
- break;
- case 1:
- v &= 0xffff;
- break;
- case 2:
- v = opcode_memory_start + (uae_s16)v;
- break;
- }
+ v = generate_stack_return(imm_special);
put_long_test(addr, v);
if (out_of_test_space) {
wprintf(_T("handle_specials out of bounds access!?"));
{
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0x4c42
- && opw1 == 0xcf19
+ if (opc == 0x89c2
+ //&& opw1 == 0xcf19
//&& opw2 == 0x504e
)
printf("");
high_memory_accessed = 0;
test_memory_accessed = 0;
testing_active = 1;
+ testing_active_opcode = opc;
int cnt = feature_loop_mode * 2;
(*cpufunctbl[opc])(opc);
- // supervisor mode and A7 was modified: skip this test round.
+ // Supervisor mode and A7 was modified: skip this test round.
if (s && regs.regs[15] != a7) {
- test_exception = -1;
+ // but not if RTE
+ if (!is_superstack_use_required())
+ test_exception = -1;
}
if (!test_exception) {
switch (dp->mnemo)
{
case i_MOVE2C:
- case i_MOVEC2:
case i_FSAVE:
case i_FRESTORE:
case i_PFLUSH:
case i_CINVA:
case i_CINVL:
case i_CINVP:
+ case i_PLPAR:
+ case i_PLPAW:
return 1;
- case i_RTE:
- if (cpu_lvl > 0)
- return 1;
- break;
}
return 0;
+}
+static int noregistercheck(struct instr *dp)
+{
+ switch (dp->mnemo)
+ {
+ case i_MOVEC2:
+ return 1;
+ }
+ return 0;
}
static uae_u8 last_exception[256];
return p;
}
-static uae_u16 get_ccr_ignore(struct instr *dp)
+static uae_u16 get_ccr_ignore(struct instr *dp, uae_u16 extra)
{
uae_u16 ccrignoremask = 0;
- if ((cpu_lvl == 2 || cpu_lvl == 3) && test_exception == 5 && (dp->mnemo == i_DIVS || dp->mnemo == i_DIVL)) {
- // 68020/030 DIVS.W/.L + Divide by Zero: V state is not stable.
- ccrignoremask |= 2; // mask CCR=V
+ if ((cpu_lvl == 2 || cpu_lvl == 3) && test_exception == 5) {
+ if ((dp->mnemo == i_DIVS) || (dp->mnemo == i_DIVL && (extra & 0x0800) && !(extra & 0x0400))) {
+ // 68020/030 DIVS.W/.L + Divide by Zero: V state is not stable.
+ ccrignoremask |= 2; // mask CCR=V
+ }
}
return ccrignoremask;
}
}
}
+ xorshiftstate ^= 0x12;
+
int pathlen = _tcslen(path);
_stprintf(dir, _T("%s%s"), path, mns);
if (fpuopcode < 0) {
if (opc == 0x0156)
printf("");
- if (subtest_count == 1537)
+ if (subtest_count == 416)
printf("");
out_of_test_space = 0;
test_exception = 0;
cpu_stopped = 0;
+ cpu_halted = 0;
ahcnt = 0;
memset(®s, 0, sizeof(regs));
regs.sr = ccr | sr_mask;
regs.usp = regs.regs[8 + 7];
regs.isp = test_memory_end - 0x80;
+ // copy user stack to super stack, for RTE etc support
+ memcpy(regs.isp - test_memory_start + test_memory, regs.usp - test_memory_start + test_memory, 0x20);
regs.msp = test_memory_end;
// data size optimization, only store data
cnt_stopped++;
// CPU stopped, skip test
skipped = 1;
+ } else if (cpu_halted) {
+ // CPU halted or reset, skip test
+ skipped = 1;
} else if (out_of_test_space) {
exception_array[0]++;
// instruction accessed memory out of test address space bounds
exception_array[test_exception]++;
if (test_exception == 8 && !(sr_mask & 0x2000)) {
// Privilege violation exception? Switch to super mode in next round.
- // Except if reset..
- if (lookup->mnemo != i_RESET) {
- sr_mask_request |= 0x2000;
- sr_allowed_mask |= 0x2000;
- }
+ sr_mask_request |= 0x2000;
+ sr_allowed_mask |= 0x2000;
}
if (test_exception == 3) {
if (!feature_exception3_data && !(test_exception_3_fc & 2)) {
// validate branch instructions
if (isbranchinst(dp)) {
if ((regs.pc != srcaddr && regs.pc != pc - 2) || pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) {
- printf("Branch instruction target fault\n");
- exit(0);
+ wprintf(_T("Branch instruction target fault\n"));
+ abort();
}
}
}
MakeSR();
if (!skipped) {
+ bool storeregs = true;
+ if (noregistercheck(dp)) {
+ *dst++ = CT_SKIP_REGS;
+ storeregs = false;
+ }
// save modified registers
for (int i = 0; i < MAX_REGISTERS; i++) {
uae_u32 s = last_registers[i];
uae_u32 d = regs.regs[i];
if (s != d) {
- dst = store_reg(dst, CT_DREG + i, s, d, -1);
+ if (storeregs) {
+ dst = store_reg(dst, CT_DREG + i, s, d, -1);
+ }
last_registers[i] = d;
}
}
- uae_u32 ccrignoremask = get_ccr_ignore(dp) << 16;
+ uae_u32 ccrignoremask = get_ccr_ignore(dp, ((pcaddr[2] << 8) | pcaddr[3])) << 16;
if ((regs.sr | ccrignoremask) != last_sr) {
dst = store_reg(dst, CT_SR, last_sr, regs.sr | ccrignoremask, -1);
last_sr = regs.sr | ccrignoremask;
_tcscpy(modetxt, _T("MULL"));
extra_and = 0x0800;
ovrname = _T("MULU");
+ } else if (!_tcsicmp(modetxt, _T("MOVEC"))) {
+ _tcscpy(modetxt, _T("MOVEC2"));
+ ovrname = _T("MOVEC");
}
for (int j = 0; lookuptab[j].name; j++) {
movem.l a5/a6,-(sp)
move.l a0,a6
lea scpucheck(pc),a5
- jsr -0x1e(a6)
+ jsr -0x1e(a6) | Supervisor
movem.l (sp)+,a5/a6
bra.s .cpudone2
.cpucheck2:
bne.s .cpudone
dbf d0,.cpucheck
.cpudone:
- addq.l #1,d0
+ addq.w #1,d0
.cpudone2:
rts
#define CT_END_FINISH 0xff
#define CT_END_INIT (0x80 | 0x40)
#define CT_END_SKIP (0x80 | 0x40 | 0x01)
+#define CT_SKIP_REGS (0x80 | 0x40 | 0x02)
#define CT_EMPTY CT_END_INIT
[cputest]
-; CPU model (68000, 68020, 68040 or 68060).
+; CPU model (68000, 68020, 68030, 68040 or 68060).
; Always select 68020 when testing FPU instructions, even if test hardware CPU is 68040 or 68060.
-cpu=68020
+cpu=68000
; CPU address space. 24-bit or 32-bit. If 24-bit, tester will assume upper 8-bits of addresses gets ignored.
-cpu_address_space=32
+cpu_address_space=24
; FPU model (empty string or 0, 68881, 68882, 68040, 68060)
; Enable only when testing FPU. Enabled FPU mode will slow down native test execution even when not testing FPU instructions.
test_low_memory_end=0x8000
; High address space limits (0x00ff8000 to 0x01000000 is complete space if 24-bit). Comment out to disable.
-;test_high_memory_start=0x00ff8000
-;test_high_memory_end=0x01000000
+test_high_memory_start=0x00ff8000
+test_high_memory_end=0x01000000
; ROM high address space. High memory is only used for read tests, uses last 32k of ROM image file.
high_rom=D:\amiga\roms\Kickstart v3.1 rev 40.63 (1993)(Commodore)(A500-A600-A2000)[!].rom
; main test memory start and size (real hardware must have RAM in this address space)
-;test_memory_start=0x780000
-test_memory_start=0x68800000
+test_memory_start=0x780000
+;test_memory_start=0x68800000
+;test_memory_start=0x07800000
+;test_memory_start=0x08800000
test_memory_size=0x080000
; number of test rounds (registers are re-randomized after each round)
; test branches to odd addresses
; same options as above
-feature_exception3_instruction=1
+feature_exception3_instruction=0
; SR extra mask.
; 0x8000 = T1
-; 0x4000 = T0 (68020)
+; 0x4000 = T0 (68020-68040)
; 0x2000 = S
-; 0x1000 = M (68020)
+; 0x1000 = M (68020-68060)
; Other bits are ignored.
; For example 0xa000 adds 3 extra test rounds: S=1/T1=0, S=0/T1=1 and S=1/T1=1
; Note: instructions that generate privilege violation exception will automatically add extra S=1 round.
return p;
}
-static uae_u16 test_sr, test_ccrignoremask;
+static uae_u16 test_ccrignoremask;
static uae_u32 test_fpsr, test_fpcr;
static void addinfo(void)
}
strcat(outbp, "\n");
outbp += strlen(outbp);
- sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx MSP: %08lx\n", test_regs.sr != test_sr ? '*' : ' ', before ? test_sr : r->sr, r->pc, r->ssp, r->msp);
+ sprintf(outbp, "SR:%c%04x PC: %08lx ISP: %08lx MSP: %08lx\n",
+ test_regs.sr != last_registers.sr ? '*' : ' ', before ? regs.sr : test_regs.sr,
+ r->pc, r->ssp, r->msp);
outbp += strlen(outbp);
if (before >= 0) {
- uae_u16 s = before ? test_sr : r->sr;
- uae_u16 s1 = test_regs.sr;
- uae_u16 s2 = test_sr;
- uae_u16 s3 = before ? s1 : last_registers.sr;
+ uae_u16 s = before ? regs.sr : test_regs.sr; // current value
+ uae_u16 s1 = regs.sr; // original value
+ uae_u16 s2 = test_regs.sr; // test result value
+ uae_u16 s3 = last_registers.sr; // expected result value
for (int i = 0; srbits[i].name; i++) {
if (i > 0)
*outbp++ = ' ';
uae_u16 mask = 1 << srbits[i].bit;
- sprintf(outbp, "%s%c%d", srbits[i].name, (s3 & mask) != (s1 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0);
+ sprintf(outbp, "%s%c%d", srbits[i].name,
+ (s2 & mask) != (s3 & mask) ? '!' : ((s1 & mask) != (s2 & mask) ? '*' : '='), (s & mask) != 0);
outbp += strlen(outbp);
}
}
static uae_u8 last_exception[256];
static int last_exception_len;
-static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc)
+static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc, int *experr)
{
int exclen = 0;
uae_u8 *exc;
outbp += strlen(outbp);
hexdump(sp, exclen);
errors = 1;
+ *experr = 1;
}
return p;
}
+// regs: registers before execution of test code
+// test_reg: registers used during execution of test code, also modified by test code.
+// last_registers: registers after modifications from data files. Test ok if test_reg == last_registers.
+
static uae_u8 *validate_test(uae_u8 *p, int ignore_errors, int ignore_sr)
{
uae_u8 regs_changed[16] = { 0 };
if (*p == CT_END_SKIP)
return p + 1;
+ int experr = 0;
for (;;) {
uae_u8 v = *p;
if (v & CT_END) {
}
if (ignore_errors) {
if (exc) {
- p = validate_exception(&test_regs, p, exc, exc == cpuexc);
+ p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr);
}
break;
}
break;
}
if (exc) {
- p = validate_exception(&test_regs, p, exc, exc == cpuexc);
+ p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr);
}
if (exc != cpuexc) {
addinfo();
} else {
sprintf(outbp, "Exception ID: expected %d but got %d\n", exc, cpuexc);
}
+ experr = 1;
}
outbp += strlen(outbp);
errors++;
if ((val & (sr_undefined_mask & test_ccrignoremask)) != (test_regs.sr & (sr_undefined_mask & test_ccrignoremask)) && !ignore_errors && !ignore_sr) {
addinfo();
if (dooutput) {
- sprintf(outbp, "SR: expected %04x -> %04x but got %04x (%04x)\n", test_sr, val & 0xffff, test_regs.sr & 0xffff, test_ccrignoremask);
+ sprintf(outbp, "SR: expected %04x -> %04x but got %04x (%04x)\n", regs.sr & 0xffff, val & 0xffff, test_regs.sr & 0xffff, test_ccrignoremask);
outbp += strlen(outbp);
}
errors++;
}
out_regs(&test_regs, 0);
if (exc > 1) {
- sprintf(outbp, "OK: Generated exception %d\n", exc);
- outbp += strlen(outbp);
+ if (!experr) {
+ sprintf(outbp, "OK: Generated exception %d\n", exc);
+ outbp += strlen(outbp);
+ }
if (exc == 3 && cpu_lvl == 0) {
sprintf(outbp, "RW=%d IN=%d FC=%d\n",
((test_regs.exc >> (16 + 4)) & 1),
regs.pc = opcode_memory_addr;
regs.fpiar = opcode_memory_addr;
+ memcpy((void*)regs.ssp, (void*)regs.regs[15], 0x20);
xmemcpy(&test_regs, ®s, sizeof(struct registers));
test_regs.sr = ccr | sr_mask;
- test_sr = test_regs.sr;
+ uae_u32 test_sr = test_regs.sr;
if (fpumode) {
test_regs.fpsr = (ccr & 15) << 24;
test_regs.fpcr = (ccr >> 4) << 4;
last_registers.pc = last_pc;
last_registers.fpiar = last_fpiar;
+ if ((*p) == CT_SKIP_REGS) {
+ p++;
+ for (int i = 0; i < 16; i++) {
+ test_regs.regs[i] = regs.regs[i];
+ }
+ }
+
p = validate_test(p, ignore_errors, ignore_sr);
last_pc = last_registers.pc;
exit(0);
}
- printf("CPUlvl=%d, Mask=%08lx\n", cpu_lvl, addressing_mask);
+ printf("CPUlvl=%d, Mask=%08lx Code=%08lx\n", cpu_lvl, addressing_mask, opcode_memory);
printf("%s:\n", inst_name);
testcnt = 0;
--- /dev/null
+
+UAE CPU Tester
+
+I finally wrote utility (this was my "Summer 2019" project) that can be used to verify operation of for example software emulated or FPGA 680x0 CPUs.
+It is based on UAE CPU core (gencpu generated special test core). All the CPU logic comes from UAE CPU core.
+
+Verifies:
+
+- All CPU registers (D0-D7/A0-A7, PC and SR/CCR)
+- All FPU registers (FP0-FP7, FPIAR, FPCR, FPSR)
+- Generated exception and stack frame contents (if any)
+- Memory writes, including stack modifications (if any)
+- Loop mode for JIT testing. (generates <test instruction>, dbf dn,loop)
+- Supports 68000, 68020, 68030 (only difference between 020 and 030 seems to be data cache and MMU), 68040 and 68060. (I don't currently have real 68010)
+
+Tests executed for each tested instruction:
+
+- Every CCR combination (32 tests)
+- Every FPU condition combination (4 bits) + 2 precision bits + 2 rounding bits (256 tests)
+- Every addressing mode, including optionally 68020+ addressing modes.
+- If instruction generated privilege violation exception, extra test round is run in supervisor mode (Total 64 tests).
+- Optionally can do any combination of T0, T1, S and M -bit SR register extra test rounds.
+- Every opcode value is tested. Total number of tests per opcode depends on available addressing modes etc. It can be hundreds of thousands or even millions..
+
+Test generation details:
+
+Instruction's effective address is randomized. It is accepted if it points to any of 3 test memory regions. If it points outside of test memory, it will be re-randomized few times. Test will be skipped if current EA makes it impossible to point to any of 3 test regions.
+If 68000/68010 and address error testing is enabled: 2 extra test rounds are generated, one with even and another with odd EAs to test and verify address errors.
+
+Notes and limitations:
+
+- Test generator is very brute force based, it should be more intelligent..
+- Address error testing is optional, if disabled, generated tests never cause address errors.
+- RTE test only tests stack frame types 0 and 2 (if 68020+)
+- All tests that would halt or reset the CPU are skipped (RESET in supervisor mode, STOP parameter that would stop the CPU etc)
+- Single instruction test set will take long time to run on real 68000. Few minutes to much longer...
+- Undefined flags (for example DIV and CHK) are also verified. It probably would be good idea to optionally filter them out.
+- Instruction cycle order or timing is ignored. It is not possible without extra hardware.
+- 68000 bus errors are not tested but there are some plans for future version with custom hardware. (Hatari also uses UAE CPU core)
+- FPU testing is not yet fully implemented.
+- Sometimes reported old and new condition code state does not match error report..
+
+Tester compatibility (integer instructions only):
+
+68000: Complete.
+68010: Not supported yet (Don't have real 68010, at least not yet).
+68020: Almost complete (DIVS.W/DIVS.L V-flag weirdness).
+68030: Same as 68020.
+68040: Almost complete (Weird unaligned MOVE16 behavior which may be board specific).
+68060: Same as 68040.
+
+More CPU details in WinUAE changelog.
+
+Not implemented or only partially implemented:
+
+68010+:
+
+- MOVEC: Only MOVEC to An/Dn is tested and read value is ignored. Basically only verifies if correct and only correct CPU model specific control registers exist.
+- RTE: long frames with undefined fields are skipped. Basic frame types 0 and 2 are verified, also unsupported frame types are tested, error is reported if CPU does not generate frame exception.
+- 68020+ undefined addressing mode bit combinations are not tested.
+
+All models:
+
+- Interrupts (stack frames and STOP)
+- MMU instructions (Not going to happen)
+- 68020+ cache related instructions.
+- FPU FSAVE/FRESTORE, FPU support also isn't fully implemented yet.
+
+Build instructions:
+
+- buildm68k first (already built if UAE core was previously compiled)
+- gencpu with CPU_TEST=1 define. This creates cpuemu_x_test.cpp files (x=90-94), cpustbl_test.cpp and cputbl_test.h
+- build cputestgen project.
+- build native Amiga project (cputest directory). Assembly files probably only compiles with Bebbo's GCC.
+
+
+Test generator quick instructions:
+
+Update cputestgen.ini to match your CPU model, memory settings etc...
+
+"Low memory" = memory accessible using absolute word addressing mode, positive value (0x0000 to 0x7fff). Can be larger.
+"High memory" = memory accessible using absolute word addressing mode, negative value (0xFFF8000 to 0xFFFFFFFF)
+
+If high memory is ROM space (like on 24-bit address space Amigas), memory region is used for read only tests, use "high_rom=<path to rom image>" to select ROM image. Last 32k of image is loaded.
+
+Use "test_low_memory_start"/"test_high_memory_start" and "test_low_memory_end"/"test_high_memory_end" to restrict range of memory region used for tests, for example if part of region is normally inaccessible.
+
+"test_memory_start"/"test_memory_size" is the main test memory, tested instruction and stack is located here. Must be at least 128k but larger the size, the easier it is for the generator to find effective addresses that hit test memory. This memory space must be free on target m68k hardware.
+
+All 3 memory regions (if RAM) are filled with pseudo-random pattern and saved as "lmem.dat", "hmem.dat" and "tmem.dat"
+
+Usage of Amiga m68k native test program:
+
+Copy all three dat files, test executable compiled for target platform (currently only Amiga is supported) and data file directories to target system.
+
+cputest all = run all tests, in alphabetical order. Stops when mismatch is detected.
+cputest tst.b = run tst.b tests only
+cputest all tst.b = run tst.b, then tst.w and so on in alphabetical order until end or mismatch is detected.
+
+If mismatch is detected, opcode word(s), instruction disassembly, registers before and after and reason message is shown on screen. If difference is in exception stack frame, both expected and returned stack frame is shown in hexadecimal.
extra = get_word_debug(pc);
_stprintf(instrname + _tcslen(instrname), _T(",#$%04x"), extra);
pc += 2;
+ } else if (lookup->mnemo == i_LPSTOP) {
+ if (extra == 0x01c0) {
+ uae_u16 extra2 = get_word_debug(pc + 2);
+ _stprintf(instrname, _T("LPSTOP #$%04x"), extra2);
+ pc += 4;
+ } else {
+ _stprintf(instrname, _T("ILLG #$%04x"), extra);
+ pc += 2;
+ }
} else if (lookup->mnemo == i_FDBcc) {
pc = ShowEA(NULL, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode);
pc += 2;
// if new SR S-bit is not set:
// 68000 (68010?): Update SR, increase PC and then cause privilege violation exception (handled in newcpu)
// 68000 (68010?): Traced STOP runs 4 cycles faster.
- // 68020 68030: STOP works normally
- // 68040 68060: Immediate privilege violation exception
+ // 68020 68030 68040: STOP works normally
+ // 68060: Immediate privilege violation exception
if ((cpu_level == 0 || cpu_level == 1) && using_ce) {
printf("\t%s(regs.t1 ? 4 : 8);\n", do_cycles);
}
- if (cpu_level >= 4) {
+ if (cpu_level >= 5) {
printf("\tif (!(sr & 0x2000)) {\n");
incpc("%d", m68k_pc_offset);
printf("\t\tException(8); goto %s;\n", endlabelstr);
next_cpu_level = cpu_level - 1;
break;
case i_LPSTOP: /* 68060 */
- printf ("\tuae_u16 sw = %s (2);\n", srcwi);
- printf ("\tif (sw != (0x100|0x80|0x40)) { Exception (4); goto %s; }\n", endlabelstr);
+ printf ("\tuae_u16 sw = %s(2);\n", srcwi);
+ printf ("\tif (sw != 0x01c0) { Exception (11); goto %s; }\n", endlabelstr);
printf("\tif (!(regs.sr & 0x2000)) {\n");
printf("\t\tException(8); goto %s;\n", endlabelstr);
printf("\t}\n");
- printf("\tregs.sr = %s (4);\n", srcwi);
+ printf("\tuae_u16 newsr = %s(4);\n", srcwi);
+ printf("\tif (!(newsr & 0x2000)) {\n");
+ printf("\t\tException(8); goto %s;\n", endlabelstr);
+ printf("\t}\n");
+ printf("\tregs.sr = newsr;\n");
makefromsr();
printf ("\tm68k_setstopped();\n");
m68k_pc_offset += 4;
sync_m68k_pc ();
fill_prefetch_full_ntx();
+ need_endlabel = 1;
+ break;
+ case i_HALT: /* 68060 debug */
+ printf("\tcpu_halt(CPU_HALT_68060_HALT);\n");
+ break;
+ case i_PULSE: /* 68060 debug */
break;
case i_RTE:
addop_ce020 (curi, 0);
printf ("\t\tint frame = format >> 12;\n");
printf ("\t\tint offset = 8;\n");
printf ("\t\tnewsr = sr; newpc = pc;\n");
- printf ("\t\tif (frame == 0x0) { m68k_areg (regs, 7) += offset; break; }\n");
- printf ("\t\telse if (frame == 0x8) { m68k_areg (regs, 7) += offset + 50; break; }\n");
- printf ("\t\telse { Exception_cpu(14); goto %s; }\n", endlabelstr);
+ printf ("\t\tif (frame == 0x0) {\n\t\t\tm68k_areg (regs, 7) += offset; break; }\n");
+ printf ("\t\telse if (frame == 0x8) {\n\t\t\tm68k_areg (regs, 7) += offset + 50; break; }\n");
+ printf ("\t\telse {\n\t\t\tException_cpu(14); goto %s; }\n", endlabelstr);
printf ("\t\tregs.sr = newsr; MakeFromSR ();\n}\n");
pop_braces (old_brace_level);
printf ("\tregs.sr = newsr;\n");
printf ("\t\tint offset = 8;\n");
printf ("\t\tnewsr = sr; newpc = pc;\n");
addcycles_ce020 (6);
- printf ("\t\tif (frame == 0x0) { m68k_areg (regs, 7) += offset; break; }\n");
+ printf ("\t\tif (frame == 0x0) {\n\t\t\tm68k_areg (regs, 7) += offset; break; }\n");
if (cpu_level >= 2) {
// 68020+
- printf ("\t\telse if (frame == 0x1) { m68k_areg (regs, 7) += offset; }\n");
- printf ("\t\telse if (frame == 0x2) { m68k_areg (regs, 7) += offset + 4; break; }\n");
+ printf ("\t\telse if (frame == 0x1) {\n\t\t\tm68k_areg (regs, 7) += offset; }\n");
+ printf ("\t\telse if (frame == 0x2) {\n\t\t\tm68k_areg (regs, 7) += offset + 4; break; }\n");
}
if (cpu_level >= 4) {
// 68040+
- printf ("\t\telse if (frame == 0x3) { m68k_areg (regs, 7) += offset + 4; break; }\n");
+ printf ("\t\telse if (frame == 0x3) {\n\t\t\tm68k_areg (regs, 7) += offset + 4; break; }\n");
}
if (using_mmu == 68060) {
- printf ("\t\telse if (frame == 0x4) { m68k_do_rte_mmu060 (a); m68k_areg (regs, 7) += offset + 8; break; }\n");
+ printf ("\t\telse if (frame == 0x4) {\n\t\t\tm68k_do_rte_mmu060 (a); m68k_areg (regs, 7) += offset + 8; break; }\n");
} else if (cpu_level >= 4) {
// 68040+
- printf ("\t\telse if (frame == 0x4) { m68k_areg (regs, 7) += offset + 8; break; }\n");
+ printf ("\t\telse if (frame == 0x4) {\n\t\t\tm68k_areg (regs, 7) += offset + 8; break; }\n");
}
if (cpu_level == 1) {
// 68010 only
- printf("\t\telse if (frame == 0x8) { m68k_areg (regs, 7) += offset + 50; break; }\n");
+ printf("\t\telse if (frame == 0x8) {\n\t\t\tm68k_areg (regs, 7) += offset + 50; break; }\n");
}
if (using_mmu == 68040) {
- printf ("\t\telse if (frame == 0x7) { m68k_do_rte_mmu040 (a); m68k_areg (regs, 7) += offset + 52; break; }\n");
- } else if (cpu_level >= 4) {
- // 68040+
- printf ("\t\telse if (frame == 0x7) { m68k_areg (regs, 7) += offset + 52; break; }\n");
+ printf ("\t\telse if (frame == 0x7) {\n\t\t\tm68k_do_rte_mmu040 (a); m68k_areg (regs, 7) += offset + 52; break; }\n");
+ } else if (cpu_level == 4) {
+ // 68040 only
+ printf ("\t\telse if (frame == 0x7) {\n\t\t\tm68k_areg (regs, 7) += offset + 52; break; }\n");
}
if (cpu_level == 2 || cpu_level == 3) {
// 68020/68030 only
- printf ("\t\telse if (frame == 0x9) { m68k_areg (regs, 7) += offset + 12; break; }\n");
+ printf ("\t\telse if (frame == 0x9) {\n\t\t\tm68k_areg (regs, 7) += offset + 12; break; }\n");
if (using_mmu == 68030) {
if (using_prefetch_020) {
- printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr);
- printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr);
+ printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr);
+ printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_do_rte_mmu030c (a); goto %s; }\n", endlabelstr);
} else {
- printf ("\t\telse if (frame == 0xa) { m68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr);
- printf ("\t\telse if (frame == 0xb) { m68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr);
+ printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr);
+ printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_do_rte_mmu030 (a); goto %s; }\n", endlabelstr);
}
} else {
- printf ("\t\telse if (frame == 0xa) { m68k_areg (regs, 7) += offset + 24; break; }\n");
- printf ("\t\telse if (frame == 0xb) { m68k_areg (regs, 7) += offset + 84; break; }\n");
+ printf ("\t\telse if (frame == 0xa) {\n\t\t\tm68k_areg (regs, 7) += offset + 24; break; }\n");
+ printf ("\t\telse if (frame == 0xb) {\n\t\t\tm68k_areg (regs, 7) += offset + 84; break; }\n");
}
}
- printf ("\t\telse { Exception_cpu(14); goto %s; }\n", endlabelstr);
+ printf ("\t\telse {\n\t\t\tException_cpu(14); goto %s; }\n", endlabelstr);
printf ("\t\tregs.sr = newsr;\n");
makefromsr_t0();
printf ("}\n");
printf("\t\tException_cpu(5);\n");
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
- printf("\tsetdivuflags(false, (uae_u32)dst, (uae_u16)src);\n");
printf("\tuae_u32 newv = (uae_u32)dst / (uae_u32)(uae_u16)src;\n");
printf("\tuae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n");
if (using_ce) {
addcycles000_nonces("\t\t", "(getDivu68kCycles((uae_u32)dst, (uae_u16)src)) - 4");
fill_prefetch_next();
printf("\t\tif (newv > 0xffff) {\n");
- printf("\t\t\tsetdivuflags(true, (uae_u32)dst, (uae_u16)src);\n");
+ printf("\t\t\tsetdivuflags((uae_u32)dst, (uae_u16)src);\n");
printf("\t\t} else {\n");
printf("\t\t");
genflags (flag_logical, sz_word, "newv", "", "");
printf("\t\tException_cpu(5);\n");
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
- printf("\tsetdivsflags(false, (uae_s32)dst, (uae_s16)src);\n");
if (using_ce) {
start_brace();
printf("\t\tint cycles = (getDivs68kCycles((uae_s32)dst, (uae_s16)src)) - 4;\n");
addcycles000_nonces("\t\t", "(getDivs68kCycles((uae_s32)dst, (uae_s16)src)) - 4");
fill_prefetch_next ();
printf("\tif (dst == 0x80000000 && src == -1) {\n");
- printf("\t\tsetdivsflags(true, (uae_s32)dst, (uae_s16)src);\n");
+ printf("\t\tsetdivsflags((uae_s32)dst, (uae_s16)src);\n");
printf("\t} else {\n");
printf("\t\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n");
printf("\t\tuae_u16 rem = (uae_s32)dst %% (uae_s32)(uae_s16)src;\n");
printf("\t\tif ((newv & 0xffff8000) != 0 && (newv & 0xffff8000) != 0xffff8000) {\n");
- printf("\t\t\tsetdivsflags(true, (uae_s32)dst, (uae_s16)src);\n");
+ printf("\t\t\tsetdivsflags((uae_s32)dst, (uae_s16)src);\n");
printf("\t\t} else {\n");
printf("\t\t\tif (((uae_s16)rem < 0) != ((uae_s32)dst < 0)) rem = -rem;\n");
genflags(flag_logical, sz_word, "newv", "", "");
printf ("\tuae_u32 *regp = regs.regs + regno;\n");
printf ("\tif (! m68k_movec2(src & 0xFFF, regp)) goto %s;\n", endlabelstr);
trace_t0_68040_only();
+ need_endlabel = 1;
break;
case i_MOVE2C:
genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
printf ("\tuae_u32 *regp = regs.regs + regno;\n");
printf ("\tif (! m68k_move2c(src & 0xFFF, regp)) goto %s;\n", endlabelstr);
trace_t0_68040_only();
+ need_endlabel = 1;
break;
case i_CAS:
{
extern int movem_next[256];
uae_u16 get_word_test_prefetch(int);
-uae_u16 get_wordi_test(uaecptr);
+uae_u16 get_wordi_test(int);
void put_byte_test(uaecptr, uae_u32);
void put_word_test(uaecptr, uae_u32);
extern int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor);
extern int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor);
extern void divbyzero_special(bool issigned, uae_s32 dst);
-extern void setdivuflags(bool overflow, uae_u32 dividend, uae_u16 divisor);
-extern void setdivsflags(bool overflow, uae_s32 dividend, uae_s16 divisor);
+extern void setdivuflags(uae_u32 dividend, uae_u16 divisor);
+extern void setdivsflags(uae_s32 dividend, uae_s16 divisor);
extern void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size);
extern void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size);
extern void protect_roms (bool);
#define CPU_HALT_CPU_STUCK 9
#define CPU_HALT_SSP_IN_NON_EXISTING_ADDRESS 10
#define CPU_HALT_INVALID_START_ADDRESS 11
+#define CPU_HALT_68060_HALT 12
uae_u32 process_cpu_indirect_memory_read(uae_u32 addr, int size);
void process_cpu_indirect_memory_write(uae_u32 addr, uae_u32 data, int size);
i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16,
i_MMUOP030, i_PFLUSHN, i_PFLUSH, i_PFLUSHAN, i_PFLUSHA,
i_PLPAR, i_PLPAW, i_PTESTR, i_PTESTW,
- i_LPSTOP,
+ i_LPSTOP, i_HALT, i_PULSE,
MAX_OPCODE_FAMILY
} ENUMNAME (instrmnem);
#if MOVEC_DEBUG > 0
write_log (_T("move2c %04X <- %08X PC=%x\n"), regno, *regp, M68K_GETPC);
#endif
- if (movec_illg (regno)) {
- op_illg (0x4E7B);
+ if (movec_illg(regno)) {
+ if (currprefs.cpu_model < 68060 && !regs.s) {
+ Exception(8);
+ return 0;
+ }
+ op_illg(0x4E7B);
return 0;
} else {
+ if (!regs.s) {
+ Exception(8);
+ return 0;
+ }
switch (regno) {
case 0: regs.sfc = *regp & 7; break;
case 1: regs.dfc = *regp & 7; break;
#if MOVEC_DEBUG > 0
write_log (_T("movec2 %04X PC=%x\n"), regno, M68K_GETPC);
#endif
- if (movec_illg (regno)) {
- op_illg (0x4E7A);
+ if (movec_illg(regno)) {
+ if (currprefs.cpu_model < 68060 && !regs.s) {
+ Exception(8);
+ return 0;
+ }
+ op_illg(0x4E7A);
return 0;
} else {
+ if (!regs.s) {
+ Exception(8);
+ return 0;
+ }
switch (regno) {
case 0: *regp = regs.sfc; break;
case 1: *regp = regs.dfc; break;
* 68000: V=1, C=0, Z=0, N=1
* 68020: V=1, C=0, Z=0, N=X
* 68040: V=1, C=0, NZ not modified.
- * 68060: V=1, C=0, N=0, Z=0
+ * 68060: V=1, C=0, NZ not modified.
*
* X) N is set if original 32-bit destination value is negative.
*
*/
-void setdivuflags(bool overflow, uae_u32 dividend, uae_u16 divisor)
+void setdivuflags(uae_u32 dividend, uae_u16 divisor)
{
- if (!overflow) {
- if (currprefs.cpu_model != 68040)
- CLEAR_CZNV();
- } else {
- if (currprefs.cpu_model == 68060) {
- SET_VFLG(1);
- } else if (currprefs.cpu_model == 68040) {
- SET_VFLG(1);
- SET_CFLG(0);
- } else if (currprefs.cpu_model >= 68020) {
- SET_VFLG(1);
- if ((uae_s32)dividend < 0)
- SET_NFLG(1);
- } else {
- SET_VFLG(1);
+ if (currprefs.cpu_model == 68060) {
+ SET_VFLG(1);
+ SET_CFLG(0);
+ } else if (currprefs.cpu_model == 68040) {
+ SET_VFLG(1);
+ SET_CFLG(0);
+ } else if (currprefs.cpu_model >= 68020) {
+ SET_VFLG(1);
+ if ((uae_s32)dividend < 0)
SET_NFLG(1);
- }
+ } else {
+ SET_VFLG(1);
+ SET_NFLG(1);
}
}
* 68000: V=1, C=0, N=1, Z=0
* 68020: V=1, C=0, ZN = X
* 68040: V=1, C=0. NZ not modified.
- * 68060: V=1, C=0, N=0, Z=0
+ * 68060: V=1, C=0, NZ not modified.
*
* X) if absolute overflow(Check getDivs68kCycles for details) : Z = 0, N = 0
* if not absolute overflow : N is set if internal result BYTE is negative, Z is set if it is zero!
*
*/
-void setdivsflags(bool overflow, uae_s32 dividend, uae_s16 divisor)
+void setdivsflags(uae_s32 dividend, uae_s16 divisor)
{
- if (!overflow) {
- if (currprefs.cpu_model != 68040)
- CLEAR_CZNV();
- } else {
- if (currprefs.cpu_model == 68060) {
- SET_VFLG(1);
- } else if (currprefs.cpu_model == 68040) {
- SET_VFLG(1);
- SET_CFLG(0);
- } else if (currprefs.cpu_model >= 68020) {
- SET_VFLG(1);
- // absolute overflow?
- if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor))
- return;
- uae_u32 aquot = (uae_u32)abs(dividend) / (uae_u16)abs(divisor);
- if ((uae_s8)aquot == 0)
- SET_ZFLG(1);
- if ((uae_s8)aquot < 0)
- SET_NFLG(1);
- } else {
- SET_VFLG(1);
+ if (currprefs.cpu_model == 68060) {
+ SET_VFLG(1);
+ SET_CFLG(0);
+ } else if (currprefs.cpu_model == 68040) {
+ SET_VFLG(1);
+ SET_CFLG(0);
+ } else if (currprefs.cpu_model >= 68020) {
+ CLEAR_CZNV();
+ SET_VFLG(1);
+ // absolute overflow?
+ if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor))
+ return;
+ uae_u32 aquot = (uae_u32)abs(dividend) / (uae_u16)abs(divisor);
+ if ((uae_s8)aquot == 0)
+ SET_ZFLG(1);
+ if ((uae_s8)aquot < 0)
SET_NFLG(1);
- }
+ } else {
+ CLEAR_CZNV();
+ SET_VFLG(1);
+ SET_NFLG(1);
}
}
/*
- * CHK.W undefined flags
+ * CHK undefined flags
*
* 68000: CV=0. Z: dst==0. N: dst < 0. !N: dst > src.
* 68020: Z: dst==0. N: dst < 0. V: src-dst overflow. C: if dst < 0: (dst > src || src >= 0), if dst > src: (src >= 0).
- * 68040: N=0. If exception: N=dst < 0
+ * 68040: C=0. C=1 if exception and (dst < 0 && src >= 0) || (src >= 0 && dst >= src) || (dst < 0 && src < dst)
+ * 68060: N=0. If exception: N=dst < 0
*
*/
void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size)
if (dst < 0 || dst > src) {
if (size == sz_word) {
int flgs = ((uae_s16)(dst)) < 0;
- int flgo = ((uae_s16)(src)) < 0;
- uae_s16 val = (uae_s16)src - (uae_s16)dst;
- int flgn = val < 0;
- SET_VFLG((flgs ^ flgo) & (flgn ^ flgo));
+ int flgo = ((uae_s16)(src)) < 0;
+ uae_s16 val = (uae_s16)src - (uae_s16)dst;
+ int flgn = val < 0;
+ SET_VFLG((flgs ^ flgo) & (flgn ^ flgo));
} else {
int flgs = dst < 0;
- int flgo = src < 0;
- uae_s32 val = src - dst;
+ int flgo = src < 0;
+ uae_s32 val = src - dst;
int flgn = val < 0;
SET_VFLG((flgs ^ flgo) & (flgn ^ flgo));
}
SET_CFLG(src >= 0);
}
}
- } else {
+ } else if (currprefs.cpu_model == 68040) {
+ SET_CFLG(0);
+ if (dst < 0 || dst > src) {
+ if (dst < 0 && src >= 0) {
+ SET_CFLG(1);
+ } else if (src >= 0 && dst >= src) {
+ SET_CFLG(1);
+ } else if (dst < 0 && src < dst) {
+ SET_CFLG(1);
+ }
+ }
+ SET_NFLG(dst < 0);
+ } else if (currprefs.cpu_model == 68060) {
SET_NFLG(0);
if (dst < 0 || dst > src) {
SET_NFLG(dst < 0);
* CHK2/CMP2 undefined flags
*
* 68020-68030: See below..
- * 68040: N: val<0 V=0
+ * 68040: NV not modified.
+ * 68060: N: val<0 V=0
*
*/
// Someone else can attempt to simplify this..
void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size)
{
- SET_NFLG(0);
- SET_VFLG(0);
-
- if (currprefs.cpu_model >= 68040) {
+ if (currprefs.cpu_model == 68060) {
+ SET_VFLG(0);
SET_NFLG(val < 0);
return;
+ } else if (currprefs.cpu_model == 68040) {
+ return;
}
+ SET_NFLG(0);
+ SET_VFLG(0);
+
if (val == lower || val == upper)
return;
static void divsl_divbyzero(uae_u16 extra, uae_s64 a)
{
- if (currprefs.cpu_model == 68060) {
+ if (currprefs.cpu_model >= 68040) {
SET_CFLG(0);
} else {
SET_NFLG(0);
static void divul_divbyzero(uae_u16 extra, uae_s64 a)
{
- if (currprefs.cpu_model == 68060) {
+ if (currprefs.cpu_model >= 68040) {
SET_CFLG(0);
} else {
uae_s32 a32 = (uae_s32)a;
{ i_PTESTW, _T("PTESTW"), NULL, 0 },
{ i_LPSTOP, _T("LPSTOP"), NULL, 0 },
+ { i_HALT, _T("HALT"), NULL, 0 },
+ { i_PULSE, _T("PULSE"), NULL, 0 },
{ i_ILLG, _T(""), NULL, 0 },
};
0100 1110 0111 0111:000:XNZVC:-----:00: RTR
- 1 0 12
-0100 1110 0111 1010:102:?????:?????:10: MOVEC2 #1
+0100 1110 0111 1010:100:?????:?????:10: MOVEC2 #1
- 6 0 6
-0100 1110 0111 1011:102:?????:?????:10: MOVE2C #1
+0100 1110 0111 1011:100:?????:?????:10: MOVE2C #1
- 6 0 6
0100 1110 10ss sSSS:000://///://///:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd]
- 0 0 4 jea
1111 0110 00dd dDDD:400:-----:-----:12: MOVE16 L,d[Aipi-Aind]
% 68060
-1111 1000 0000 0000:502:?????:?????:10: LPSTOP #1
+1111 1000 0000 0000:500:?????:?????:10: LPSTOP #1
1111 0101 1000 1rrr:502:-----:-----:00: PLPAW Ara
1111 0101 1100 1rrr:502:-----:-----:00: PLPAR Ara
-
+% "Debug Pipe Control Mode Commands"
+0100 1010 1100 1000:502:?????:?????:00: HALT
+0100 1010 1100 1100:500:?????:?????:00: PULSE