/blitfunc.h
/blittable.cpp
/cpudefs.cpp
-/cpuemu_0.cpp
-/cpuemu_11.cpp
-/cpuemu_13.cpp
-/cpuemu_20.cpp
-/cpuemu_21.cpp
-/cpuemu_22.cpp
-/cpuemu_23.cpp
-/cpuemu_24.cpp
-/cpuemu_31.cpp
-/cpuemu_32.cpp
-/cpuemu_33.cpp
-/cpuemu_40.cpp
-/cpuemu_50.cpp
+/cpuemu_*.cpp
+/cpuemu_*_test.cpp
/cpustbl.cpp
/cpustbl_test.cpp
/cputbl.h
int movem_index2[256];
int movem_next[256];
int bus_error_offset;
-int cpu_bus_error;
+int cpu_bus_error, cpu_bus_error_fake;
struct mmufixup mmufixup[2];
cpuop_func *cpufunctbl[65536];
static uae_u32 feature_addressing_modes[2];
static int ad8r[2], pc8r[2];
static int multi_mode;
-#define MAX_TARGET_EA 8
+#define MAX_TARGET_EA 20
static uae_u32 feature_target_ea[MAX_TARGET_EA][2];
static int target_ea_src_cnt, target_ea_dst_cnt;
static int target_ea_src_max, target_ea_dst_max;
static uaecptr out_of_test_space_addr;
static int forced_immediate_mode;
static int test_exception;
+static int test_exception_extra;
static int exception_stack_frame_size;
static uaecptr test_exception_addr;
static int test_exception_3_w;
static bool is_nowrite_address(uaecptr addr, int size)
{
- return addr + size >= safe_memory_start && addr < safe_memory_end;
+ return addr + size > safe_memory_start && addr < safe_memory_end;
}
static void validate_addr(uaecptr addr, int size)
if (safe_memory_start == 0xffffffff && safe_memory_end == 0xffffffff)
return;
if (addr >= safe_memory_start && addr < safe_memory_end) {
+ cpu_bus_error_fake = 1;
if ((safe_memory_mode & 1) && !write)
cpu_bus_error = 1;
if ((safe_memory_mode & 2) && write)
{
check_bus_error(addr, 1, regs.s ? 5 : 1);
uae_u8 *p = get_addr(addr, 1, 1);
- if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) {
+ if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) {
previoussame(addr, sz_byte);
if (ahcnt >= MAX_ACCESSHIST) {
wprintf(_T("ahist overflow!"));
put_byte_test(addr + 1, v >> 0);
} else {
uae_u8 *p = get_addr(addr, 2, 1);
- if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) {
+ if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) {
previoussame(addr, sz_word);
if (ahcnt >= MAX_ACCESSHIST) {
wprintf(_T("ahist overflow!"));
put_word_test(addr + 2, v >> 0);
} else {
uae_u8 *p = get_addr(addr, 4, 1);
- if (!out_of_test_space && !noaccesshistory && !cpu_bus_error) {
+ if (!out_of_test_space && !noaccesshistory && !cpu_bus_error_fake) {
previoussame(addr, sz_long);
if (ahcnt >= MAX_ACCESSHIST) {
wprintf(_T("ahist overflow!"));
testing_active = -1;
int opcode = (opcode_memory[0] << 8) | (opcode_memory[1]);
- if (test_exception_opcode >= 0)
+ if (test_exception_opcode >= 0) {
opcode = test_exception_opcode;
+ }
+ if (SPCFLAG_DOTRACE && test_exception == 9) {
+ SPCFLAG_DOTRACE = 0;
+ }
int sv = regs.s;
uaecptr tmp = m68k_areg(regs, 7);
uae_u16 mode = (sv ? 4 : 0) | test_exception_3_fc;
mode |= test_exception_3_w ? 0 : 16;
Exception_build_68000_address_error_stack_frame(mode, opcode, test_exception_addr, regs.pc);
+ SPCFLAG_DOTRACE = 0;
}
} else if (cpu_lvl == 1) {
if (test_exception == 2 || test_exception == 3) {
ssw &= 0x00ff;
regs.mmu_fault_addr = test_exception_addr;
Exception_build_stack_frame(regs.instruction_pc, regs.pc, ssw, 3, 0x08);
+ SPCFLAG_DOTRACE = 0;
} else {
Exception_build_stack_frame_common(regs.instruction_pc, regs.pc, 0, test_exception);
}
void exception2_fetch(uae_u32 opcode, uaecptr addr)
{
test_exception = 2;
- test_exception_3_w = 1;
+ test_exception_3_w = 0;
test_exception_addr = addr;
test_exception_opcode = opcode;
test_exception_3_fc = 2;
test_exception_3_size = 1;
test_exception_3_di = 0;
+
+ if (currprefs.cpu_model == 68000) {
+ if (generates_group1_exception(regs.ir)) {
+ test_exception_3_fc |= 8; // set N/I
+ }
+ }
+
doexcstack();
}
test_exception_3_fc = fc;
test_exception_3_size = size;
test_exception_3_di = 1;
+
+ if (currprefs.cpu_model == 68000) {
+ if (generates_group1_exception(regs.ir)) {
+ test_exception_3_fc |= 8; // set N/I
+ }
+ test_exception_opcode = regs.ir;
+ }
+
doexcstack();
}
test_exception_3_size = size;
regs.write_buffer = val;
test_exception_3_di = 1;
+
+ if (currprefs.cpu_model == 68000) {
+ if (generates_group1_exception(regs.ir)) {
+ test_exception_3_fc |= 8; // set N/I
+ }
+ test_exception_opcode = regs.ir;
+ }
+
doexcstack();
}
test_exception_3_fc = fc;
test_exception_3_size = size;
test_exception_3_di = 1;
+
+ if (currprefs.cpu_model == 68000) {
+ if (generates_group1_exception(regs.ir)) {
+ test_exception_3_fc |= 8; // set N/I
+ }
+ if (opcode & 0x10000)
+ test_exception_3_fc |= 8;
+ test_exception_opcode = regs.ir;
+ }
+
doexcstack();
}
void exception3_write(uae_u32 opcode, uae_u32 addr, int size, uae_u32 val, int fc)
test_exception_3_size = size;
regs.write_buffer = val;
test_exception_3_di = 1;
+
+ if (currprefs.cpu_model == 68000) {
+ if (generates_group1_exception(regs.ir)) {
+ test_exception_3_fc |= 8; // set N/I
+ }
+ if (opcode & 0x10000)
+ test_exception_3_fc |= 8;
+ test_exception_opcode = regs.ir;
+ }
+
doexcstack();
}
ea_state_found[2] = 0;
}
+// if other EA is target EA, don't point this EA
+// to same address space.
+static bool other_targetea_same(int srcdst, uae_u32 v)
+{
+ if (target_ea[srcdst ^ 1] == 0xffffffff)
+ return false;
+ if (!is_nowrite_address(target_ea[srcdst ^ 1], 1))
+ return false;
+ if (!is_nowrite_address(v, 1))
+ return false;
+ return true;
+}
+
// attempt to find at least one zero, positive and negative source value
static int analyze_address(struct instr *dp, int srcdst, uae_u32 addr)
{
add <<= (v >> 9) & 3; // SCALE
}
addr += (uae_s8)(v & 0xff); // DISPLACEMENT
+ if (other_targetea_same(srcdst, addr))
+ continue;
if (analyze_address(dp, srcdst, addr))
break;
maxcnt--;
uae_u16 v;
for (;;) {
v = rand16();
+ if (other_targetea_same(srcdst, (uae_s32)(uae_s16)v))
+ continue;
if (analyze_address(dp, srcdst, v))
- break;
+ break;
}
put_word_test(pc, v);
*isconstant = 16;
v = opcode_memory_start + offset;
}
immabsl_cnt++;
+ if (other_targetea_same(srcdst, v))
+ continue;
if (analyze_address(dp, srcdst, v))
break;
}
{
uae_u16 opw1 = (opcode_memory[2] << 8) | (opcode_memory[3] << 0);
uae_u16 opw2 = (opcode_memory[4] << 8) | (opcode_memory[5] << 0);
- if (opc == 0x2191
- && opw1 == 0xdd12
- && opw2 == 0xf78c
+ if (opc == 0x4ea9
+ && opw1 == 0xffff
+ //&& opw2 == 0xf78c
)
printf("");
if (regs.sr & 0x2000)
testing_active = 1;
testing_active_opcode = opc;
cpu_bus_error = 0;
+ cpu_bus_error_fake = 0;
regs.read_buffer = regs.irc;
regs.write_buffer = 0xf00d;
- int cnt = feature_loop_mode * 2;
+ int cnt = (feature_loop_mode + 1) * 2;
if (multi_mode)
cnt = 100;
for (;;) {
+ if (cnt <= 0) {
+ wprintf(_T(" Loop mode didn't end!?\n"));
+ abort();
+ }
+
if (SPCFLAG_TRACE)
do_trace();
break;
}
- if (!test_exception) {
- if (SPCFLAG_DOTRACE)
- Exception(9);
-
- if (cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) {
- // 68000/68010 undocumented special case:
- // if STOP clears S-bit and T was not set:
- // cause privilege violation exception, PC pointing to following instruction.
- // If T was set before STOP: STOP works as documented.
- cpu_stopped = 0;
- Exception(8);
- }
+ if (!SPCFLAG_DOTRACE && cpu_stopped && regs.s == 0 && currprefs.cpu_model <= 68010) {
+ // 68000/68010 undocumented special case:
+ // if STOP clears S-bit and T was not set:
+ // cause privilege violation exception, PC pointing to following instruction.
+ // If T was set before STOP: STOP works as documented.
+ cpu_stopped = 0;
+ Exception(8);
+ }
+
+ // Trace is only added as an exception if there was no other exceptions
+ // Trace stacked with other exception is handled later
+ if (SPCFLAG_DOTRACE && !test_exception) {
+ Exception(9);
}
// Amiga Chip ram does not support TAS or MOVE16
if (regs.pc == endpc || regs.pc == targetpc)
break;
- if (test_exception)
+ if (test_exception || SPCFLAG_DOTRACE)
break;
if (!valid_address(regs.pc, 2, 0))
break;
- if (!feature_loop_mode && !multi_mode) {
- wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n"));
- abort();
+ if (regs.pc + 2 == targetpc) {
+ opc = regs.ir;
+ continue;
}
if (cpu_lvl < 2) {
}
cnt--;
- if (cnt <= 0) {
- wprintf(_T(" Loop mode didn't end!?\n"));
+
+ if (!feature_loop_mode && !multi_mode && opc != 0x4e71) {
+ wprintf(_T(" Test instruction didn't finish in single step in non-loop mode!?\n"));
abort();
}
+
}
testing_active = 0;
static uae_u8 last_exception[256];
static int last_exception_len;
+static int last_exception_extra;
static uae_u8 *save_exception(uae_u8 *p, struct instr *dp)
{
uae_u8 *op = p;
p++;
+ *p++ = test_exception_extra;
uae_u8 *sf = test_memory + test_memory_size + EXTRA_RESERVED_SPACE - exception_stack_frame_size;
// parse exception and store fields that are unique
// SR and PC was already saved with non-exception data
abort();
}
}
- if (last_exception_len > 0 && last_exception_len == exception_stack_frame_size && !memcmp(sf, last_exception, exception_stack_frame_size)) {
+ if (last_exception_len > 0 && last_exception_len == exception_stack_frame_size && test_exception_extra == last_exception_extra && !memcmp(sf, last_exception, exception_stack_frame_size)) {
// stack frame was identical to previous
p = op;
*p++ = 0xff;
} else {
int datalen = (p - op) - 1;
last_exception_len = exception_stack_frame_size;
+ last_exception_extra = test_exception_extra;
*op = (uae_u8)datalen;
memcpy(last_exception, sf, exception_stack_frame_size);
}
int sr_override = 0;
uae_u32 target_ea_bak[2], target_address_bak;
- target_ea_bak[0] = target_ea[0];
- target_ea_bak[1] = target_ea[1];
- target_address_bak = target_address;
for (;;) {
+ target_ea_bak[0] = target_ea[0];
+ target_ea_bak[1] = target_ea[1];
+ target_address_bak = target_address;
+
if (quick)
break;
uae_u32 dstaddr_old = 0xffffffff;
uae_u32 srcaddr = 0xffffffff;
uae_u32 dstaddr = 0xffffffff;
+ uae_u32 branchtarget_old = 0xffffffff;
for (int opcode = 0; opcode < 65536; opcode++) {
// if instruction has immediate(s), repeat instruction test multiple times
// each round generates new random immediate(s)
int constant_loops = 32;
+ if (dp->mnemo == i_ILLG) {
+ constant_loops = 1;
+ }
while (constant_loops-- > 0) {
uae_u8 oldbytes[OPCODE_AREA];
int did_out_of_bounds = 0;
uae_u8 *prev_dst2 = dst;
+ uae_u32 branch_target_swap_address = 0;
+ int branch_target_swap_mode = 0;
+ uae_u32 branch_target_data_original = 0x4afc4e71;
+ uae_u32 branch_target_data = branch_target_data_original;
+
out_of_test_space = 0;
+ noaccesshistory = 0;
+ cpu_bus_error_fake = 0;
+ cpu_bus_error = 0;
ahcnt = 0;
+ ahcnt2 = 0;
multi_mode = 0;
target_ea[0] = target_ea_bak[0];
target_ea[1] = target_ea_bak[1];
target_address = target_address_bak;
- if (opc == 0x0156)
+ if (opc == 0x4ed0)
printf("");
- if (subtest_count == 416)
+ if (subtest_count == 2568)
printf("");
uaecptr pc = opcode_memory_start + 2;
- pc += handle_specials_preea(opc, pc, dp);
-
+ if (dp->mnemo != i_ILLG) {
- uae_u32 srcea = 0xffffffff;
- uae_u32 dstea = 0xffffffff;
+ pc += handle_specials_preea(opc, pc, dp);
- // create source addressing mode
- if (dp->suse) {
- int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea);
- if (o < 0) {
- memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
- if (o == -1)
- goto nextopcode;
- continue;
- }
- pc += o;
- }
- uae_u8 *ao = opcode_memory + 2;
- uae_u16 apw1 = (ao[0] << 8) | (ao[1] << 0);
- uae_u16 apw2 = (ao[2] << 8) | (ao[3] << 0);
- if (opc == 0x4eb1
- && apw1 == 0xee38
- //&& apw2 == 0x7479
- )
- printf("");
+ uae_u32 srcea = 0xffffffff;
+ uae_u32 dstea = 0xffffffff;
- if (target_address != 0xffffffff && (dp->mnemo == i_MVMEL || dp->mnemo == i_MVMLE)) {
- // if MOVEM and more than 1 register: randomize address so that any MOVEM
- // access can hit target address
- uae_u16 mask = (opcode_memory[2] << 8) | opcode_memory[3];
- int count = 0;
- for (int i = 0; i < 16; i++) {
- if (mask & (1 << i))
- count++;
- }
- if (count > 0) {
- int diff = (rand8() % count);
- if (dp->dmode == Apdi) {
- diff = -diff;
+ // create source addressing mode
+ if (dp->suse) {
+ int o = create_ea(&opc, pc, dp->smode, dp->sreg, dp, &isconstant_src, 0, fpuopcode, opcodesize, &srcea);
+ if (o < 0) {
+ memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
+ if (o == -1)
+ goto nextopcode;
+ continue;
}
- uae_u32 ta = target_address;
- target_address -= diff * (1 << dp->size);
- if (target_ea[0] == ta)
- target_ea[0] = target_address;
- if (target_ea[1] == ta)
- target_ea[1] = target_address;
+ pc += o;
}
- }
- // if source EA modified opcode
- dp = table68k + opc;
+ uae_u8 *ao = opcode_memory + 2;
+ uae_u16 apw1 = (ao[0] << 8) | (ao[1] << 0);
+ uae_u16 apw2 = (ao[2] << 8) | (ao[3] << 0);
+ if (opc == 0x4eb1
+ && apw1 == 0xee38
+ //&& apw2 == 0x7479
+ )
+ printf("");
+
+ if (target_address != 0xffffffff && (dp->mnemo == i_MVMEL || dp->mnemo == i_MVMLE)) {
+ // if MOVEM and more than 1 register: randomize address so that any MOVEM
+ // access can hit target address
+ uae_u16 mask = (opcode_memory[2] << 8) | opcode_memory[3];
+ int count = 0;
+ for (int i = 0; i < 16; i++) {
+ if (mask & (1 << i))
+ count++;
+ }
+ if (count > 0) {
+ int diff = (rand8() % count);
+ if (dp->dmode == Apdi) {
+ diff = -diff;
+ }
+ uae_u32 ta = target_address;
+ target_address -= diff * (1 << dp->size);
+ if (target_ea[0] == ta)
+ target_ea[0] = target_address;
+ if (target_ea[1] == ta)
+ target_ea[1] = target_address;
+ }
+ }
- // create destination addressing mode
- if (dp->duse) {
- int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea);
- if (o < 0) {
- memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
- if (o == -1)
- goto nextopcode;
- continue;
+ // if source EA modified opcode
+ dp = table68k + opc;
+
+ // create destination addressing mode
+ if (dp->duse) {
+ int o = create_ea(&opc, pc, dp->dmode, dp->dreg, dp, &isconstant_dst, 1, fpuopcode, opcodesize, &dstea);
+ if (o < 0) {
+ memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
+ if (o == -1)
+ goto nextopcode;
+ continue;
+ }
+ pc += o;
}
- pc += o;
- }
- // requested target address but no EA? skip
- if (target_address != 0xffffffff) {
- if (srcea != target_address && dstea != target_address) {
- memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
- continue;
+ // requested target address but no EA? skip
+ if (target_address != 0xffffffff) {
+ if (srcea != target_address && dstea != target_address) {
+ memcpy(opcode_memory, oldbytes, sizeof(oldbytes));
+ continue;
+ }
}
- }
- pc = handle_specials_extra(opc, pc, dp);
+ pc = handle_specials_extra(opc, pc, dp);
- // if destination EA modified opcode
- dp = table68k + opc;
+ // if destination EA modified opcode
+ dp = table68k + opc;
- uae_u8 *bo = opcode_memory + 2;
- uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0);
- uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0);
- if (opc == 0xf228
- && bopw1 == 0x003a
- //&& bopw2 == 0x2770
- )
- printf("");
+ uae_u8 *bo = opcode_memory + 2;
+ uae_u16 bopw1 = (bo[0] << 8) | (bo[1] << 0);
+ uae_u16 bopw2 = (bo[2] << 8) | (bo[3] << 0);
+ if (opc == 0xf228
+ && bopw1 == 0x003a
+ //&& bopw2 == 0x2770
+ )
+ printf("");
+
+ // bcc.x
+ pc += handle_specials_branch(opc, pc, dp, &isconstant_src);
+ // misc
+ pc += handle_specials_misc(opc, pc, dp, &isconstant_src);
- // bcc.x
- pc += handle_specials_branch(opc, pc, dp, &isconstant_src);
- // misc
- pc += handle_specials_misc(opc, pc, dp, &isconstant_src);
+ }
put_word_test(opcode_memory_start, opc);
// end word, needed to detect if instruction finished normally when
// running on real hardware.
- put_word_test(pc, 0x4afc); // illegal instruction
- pc += 2;
+ uae_u32 originalendopcode = 0x4afc4e71;
+ uae_u32 endopcode = originalendopcode;
+ put_long_test(pc, endopcode); // illegal instruction + nop
+ pc += 4;
if (isconstant_src < 0 || isconstant_dst < 0) {
constant_loops++;
}
#endif
uaecptr branch_target = 0xffffffff;
+ uaecptr branch_target_pc = 0xffffffff;
int bc = isbranchinst(dp);
if (bc) {
if (bc < 0) {
continue;
} else {
// branch target = generate exception
- if (!is_nowrite_address(srcaddr, 2)) {
- put_word_test(srcaddr, 0x4afc);
+ if (!is_nowrite_address(srcaddr, 4)) {
+ branch_target_swap_address = srcaddr;
+ branch_target_swap_mode = 1;
+ put_long_test(srcaddr, branch_target_data);
+ } else {
+ if (!is_nowrite_address(srcaddr, 2)) {
+ put_word_test(srcaddr, branch_target_data >> 16);
+ branch_target_swap_address = srcaddr;
+ branch_target_swap_mode = 2;
+ }
}
branch_target = srcaddr;
dst = store_mem(dst, 1);
- memcpy(&ahist2, &ahist, sizeof(struct accesshistory) *MAX_ACCESSHIST);
+ memcpy(&ahist2, &ahist, sizeof(struct accesshistory) * MAX_ACCESSHIST);
ahcnt2 = ahcnt;
}
testing_active = 0;
dst = store_reg(dst, CT_DSTADDR, dstaddr_old, dstaddr, -1);
dstaddr_old = dstaddr;
}
+ if (branch_target != branchtarget_old) {
+ dst = store_reg(dst, CT_BRANCHTARGET, branchtarget_old, branch_target, -1);
+ branchtarget_old = branch_target;
+ *dst++ = branch_target_swap_mode;
+ }
*dst++ = CT_END_INIT;
int maxflag = fpumode ? 256 : 32;
// if cc-instruction: always do full test
- if (feature_flag_mode == 1 && !dp->ccuse) {
+ if (feature_flag_mode == 1 && (dp->mnemo == i_ILLG || !dp->ccuse)) {
maxflag = fpumode ? 256 / 8 : 2;
}
out_of_test_space = 0;
test_exception = 0;
+ test_exception_extra = 0;
cpu_stopped = 0;
cpu_halted = 0;
ahcnt = 0;
memset(®s, 0, sizeof(regs));
+ // swap end opcode illegal/nop
+ endopcode = (endopcode >> 16) | (endopcode << 16);
+ noaccesshistory++;
+ put_long_test(pc - 4, endopcode);
+ noaccesshistory--;
+ int endopcodesize = (endopcode >> 16) == 0x4e71 ? 2 : 4;
+
+ // swap branch target illegal/nop
+ if (branch_target_swap_mode) {
+ noaccesshistory++;
+ branch_target_data = (branch_target_data >> 16) | (branch_target_data << 16);
+ branch_target_pc = branch_target;
+ if (branch_target_swap_mode == 1) {
+ put_long_test(branch_target_swap_address, branch_target_data);
+ if ((branch_target_data >> 16) == 0x4e71)
+ branch_target_pc = branch_target + 2;
+ else
+ branch_target_pc = branch_target;
+ } else if (branch_target_swap_mode == 2) {
+ put_word_test(branch_target_swap_address, branch_target_data >> 16);
+ }
+ noaccesshistory--;
+ }
+
regs.pc = opcode_memory_start;
+ regs.ir = get_word_test(regs.pc + 0);
regs.irc = get_word_test(regs.pc + 2);
// set up registers
if (regs.sr & 0x2000)
prev_s_cnt++;
- if (subtest_count == 23360)
+ if (subtest_count == 220)
printf("");
- execute_ins(opc, pc - 2, branch_target, dp);
+ execute_ins(opc, pc - endopcodesize, branch_target_pc, dp);
if (regs.s)
s_cnt++;
skipped = 1;
}
}
- if (test_exception == 9) {
+ if (SPCFLAG_DOTRACE || test_exception == 9) {
t_cnt++;
}
} else {
ok++;
// validate branch instructions
if (isbranchinst(dp)) {
- if ((regs.pc != srcaddr && regs.pc != pc - 2) || pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) {
+ if ((regs.pc != branch_target_pc && regs.pc != pc - endopcodesize) || ((pcaddr[0] != 0x4a && pcaddr[1] != 0xfc) && (pcaddr[0] != 0x4e && pcaddr[1] != 0x71))) {
wprintf(_T("Branch instruction target fault\n"));
abort();
}
}
}
+
+ noaccesshistory++;
+ put_long_test(pc - 4, originalendopcode);
+ if (branch_target_data != 0xffffff) {
+ if (branch_target_swap_address == 1) {
+ put_long_test(branch_target_swap_address, branch_target_data_original);
+ } else if (branch_target_swap_mode == 2) {
+ put_word_test(branch_target_swap_address, branch_target_data_original >> 16);
+ }
+ }
+ noaccesshistory--;
+
MakeSR();
+
+ // did we have trace also active?
+ if (SPCFLAG_DOTRACE) {
+ if (regs.t1 && (test_exception == 5 || test_exception == 6 || test_exception == 7 || (test_exception >= 32 && test_exception <= 47))) {
+ test_exception_extra = 9;
+ } else {
+ test_exception_extra = 0;
+ }
+ // clear trace
+ regs.t0 = 0;
+ regs.t1 = 0;
+ }
+
if (!skipped) {
bool storeregs = true;
if (noregistercheck(dp)) {
S_FPIAR = S_FPU+8*12
S_FPCR = S_FPIAR+4
S_FPSR = S_FPCR+4
+S_TRACECNT = S_FPSR+4
+S_TRACESTACK = S_TRACECNT+4
+S_NEXT = S_TRACESTACK+12
| set CPU special registers
_setcpu:
movem.l (a0),d0-d7/a0-a6
rte
+exception_trace000:
+ move.l a0,-(sp)
+ move.l datapointer(pc),a0
+ tst.l S_TRACECNT(a0)
+ bne.s .nexttrace000
+ move.l 4(sp),S_TRACESTACK(a0)
+ move.l 8(sp),S_TRACESTACK+4(a0)
+.nexttrace000:
+ addq.l #1,S_TRACECNT(a0)
+ move.l (sp)+,a0
+ rte
_exceptiontable000:
bsr.s exception | 2
bsr.s exception | 6
bsr.s exception | 7
bsr.s exception | 8
- bsr.s exception | 9
+ bra.s exception_trace000 | 9
bsr.s exception | 10
bsr.s exception | 11
bsr.s exception | 12
movem.l (sp)+,d1-d7/a0-a6
rts
+exception_trace010:
+ move.l a0,-(sp)
+ move.l datapointer(pc),a0
+ tst.l S_TRACECNT(a0)
+ bne.s .nexttrace010
+ move.l 4(sp),S_TRACESTACK(a0)
+ move.l 8(sp),S_TRACESTACK+4(a0)
+ move.l 12(sp),S_TRACESTACK+8(a0)
+.nexttrace010:
+ addq.l #1,S_TRACECNT(a0)
+ move.l (sp)+,a0
+ rte
+
_exceptiontable010:
bsr.s exception010 | 2
bsr.s exception010 | 3
bsr.s exception010 | 6
bsr.s exception010 | 7
bsr.s exception010 | 8
- bsr.s exception010 | 9
+ bra.s exception_trace010 | 9
bsr.s exception010 | 10
bsr.s exception010 | 11
bsr.s exception010 | 12
movem.l (sp)+,d1-d7/a0-a6
rts
+exception_trace010t1:
+ bra exception_trace010
+
_exceptiontable020:
bsr.s exception020 | 2
bsr.s exception020 | 3
bsr.s exception020 | 6
bsr.s exception020 | 7
bsr.s exception020 | 8
- bsr.s exception020 | 9
+ bra.s exception_trace010t1 | 9
bsr.s exception020 | 10
bsr.s exception020 | 11
bsr.s exception020 | 12
movem.l (sp)+,d1-d7/a0-a6
rts
+exception_trace010t2:
+ bra exception_trace010
+
_exceptiontablefpu:
bsr.s exceptionfpu | 2
bsr.s exceptionfpu | 3
bsr.s exceptionfpu | 6
bsr.s exceptionfpu | 7
bsr.s exceptionfpu | 8
- bsr.s exceptionfpu | 9
+ bsr.s exception_trace010t2 | 9
bsr.s exceptionfpu | 10
bsr.s exceptionfpu | 11
bsr.s exceptionfpu | 12
-#define DATA_VERSION 6
+#define DATA_VERSION 7
#define CT_FPREG 0
#define CT_DREG 0
#define CT_FPIAR 20
#define CT_FPSR 21
#define CT_FPCR 22
+#define CT_BRANCHTARGET 27
#define CT_SRCADDR 28
#define CT_DSTADDR 29
#define CT_MEMWRITE 30
uae_u32 excframe;
struct fpureg fpuregs[8];
uae_u32 fpiar, fpcr, fpsr;
- uae_u32 srcaddr, dstaddr;
+ uae_u32 tracecnt;
+ uae_u16 tracedata[6];
+ uae_u32 srcaddr, dstaddr, branchtarget;
+ uae_u8 branchtarget_mode;
};
static struct registers test_regs;
static int high_memory_offset;
static uae_u32 vbr[256];
+static int exceptioncount[256];
+static int supercnt;
static char inst_name[16+1];
#ifndef M68K
#define SIZE_STORED_ADDRESS 16
static uae_u8 srcaddr[SIZE_STORED_ADDRESS];
static uae_u8 dstaddr[SIZE_STORED_ADDRESS];
+static uae_u8 branchtarget[SIZE_STORED_ADDRESS];
static uae_u8 stackaddr[SIZE_STORED_ADDRESS];
static uae_u32 stackaddr_ptr;
extern void *error_vector;
#endif
+static uae_u32 exceptiontableinuse;
struct accesshistory
{
uae_u8 *p = opcode_memory;
for (int i = 0; i < 32 * 2; i += 2) {
uae_u16 v = (p[i] << 8) | (p[i + 1]);
+ printf(" %04x", v);
if (v == 0x4afc && i > 0)
break;
- printf(" %04x", v);
}
printf("\n");
}
for (int i = 32; i < 48; i++) {
p[i] = (uae_u32)(((uae_u32)&exceptiontable000) + (i - 2) * 2);
}
+ exceptiontableinuse = (uae_u32)&exceptiontable000;
} else {
oldvbr = setvbr((uae_u32)vbr);
for (int i = 2; i < 48; i++) {
if (fpu_model) {
vbr[i] = (uae_u32)(((uae_u32)&exceptiontablefpu) + (i - 2) * 2);
+ exceptiontableinuse = (uae_u32)&exceptiontablefpu;
} else if (cpu_lvl == 1) {
vbr[i] = (uae_u32)(((uae_u32)&exceptiontable010) + (i - 2) * 2);
+ exceptiontableinuse = (uae_u32)&exceptiontable010;
} else {
vbr[i] = (uae_u32)(((uae_u32)&exceptiontable020) + (i - 2) * 2);
+ exceptiontableinuse = (uae_u32)&exceptiontable020;
}
if (i >= 2 && i < 12) {
error_vectors[i - 2] = vbr[i];
v &= 31;
if (v == 0)
v = 32;
+#ifndef _MSC_VER
xmemcpy(addr, p, v);
+#endif
p += v;
break;
}
} else if (mode == CT_DSTADDR) {
int size;
p = restore_value(p, ®s.dstaddr, &size);
+ } else if (mode == CT_BRANCHTARGET) {
+ int size;
+ p = restore_value(p, ®s.branchtarget, &size);
+ regs.branchtarget_mode = *p++;
} else if (mode < CT_AREG + 8) {
int size;
if ((v & CT_SIZE_MASK) == CT_SIZE_FPU) {
extern uae_u16 disasm_instr(uae_u16 *, char *);
-static void addinfo(void)
+static void out_disasm(uae_u8 *mem)
{
- if (infoadded)
- return;
- infoadded = 1;
- if (!dooutput)
- return;
- sprintf(outbp, "%lu:", testcnt);
- outbp += strlen(outbp);
-
uae_u16 *code;
#ifndef M68K
uae_u16 swapped[16];
for (int i = 0; i < 16; i++) {
- swapped[i] = (opcode_memory[i * 2 + 0] << 8) | (opcode_memory[i * 2 + 1] << 0);
+ swapped[i] = (mem[i * 2 + 0] << 8) | (mem[i * 2 + 1] << 0);
}
code = swapped;
#else
- code = (uae_u16*)opcode_memory;
+ code = (uae_u16*)mem;
#endif
- uae_u8 *p = opcode_memory;
+ uae_u8 *p = mem;
int offset = 0;
int lines = 0;
while (lines++ < 10) {
+ if (!is_valid_test_addr((uae_u32)p) || !is_valid_test_addr((uae_u32)p + 1))
+ break;
tmpbuffer[0] = 0;
int v = disasm_instr(code + offset, tmpbuffer);
for (int i = 0; i < v; i++) {
uae_u16 v = (p[i * 2 + 0] << 8) | (p[i * 2 + 1]);
- sprintf(outbp, "%s%04x", i ? " " : (lines == 0 ? "\t\t" : "\t"), v);
+ sprintf(outbp, "%s %08lx %04x", i ? " " : (lines == 0 ? "\t\t" : "\t"), &p[i * 2], v);
outbp += strlen(outbp);
}
sprintf(outbp, " %s\n", tmpbuffer);
outbp += strlen(outbp);
- if (v <= 0)
+ if (v <= 0 || code[offset] == 0x4afc)
break;
while (v > 0) {
offset++;
p += 2;
- if (code[offset] == 0x4afc) {
- v = -1;
- break;
- }
v--;
}
if (v < 0)
break;
}
*outbp = 0;
+}
+
+static void addinfo(void)
+{
+ if (infoadded)
+ return;
+ infoadded = 1;
+ if (!dooutput)
+ return;
+ sprintf(outbp, "%lu:", testcnt);
+ outbp += strlen(outbp);
+
+ out_disasm(opcode_memory);
+
+ if (regs.branchtarget != 0xffffffff) {
+ out_disasm((uae_u8*)regs.branchtarget);
+
+ }
+
+ uae_u16 *code = (uae_u16*)opcode_memory;
if (code[0] == 0x4e73 || code[0] == 0x4e74 || code[0] == 0x4e75) {
addinfo_bytes("P", stackaddr, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
addinfo_bytes(" ", (uae_u8 *)stackaddr_ptr - SIZE_STORED_ADDRESS_OFFSET, stackaddr_ptr, -SIZE_STORED_ADDRESS_OFFSET, SIZE_STORED_ADDRESS);
*outbp++ = '\n';
}
-static uae_u8 last_exception[256];
+static uae_u8 last_exception[256], last_exception_extra;
static int last_exception_len;
-static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int sameexc, int *experr)
+static uae_u8 *validate_exception(struct registers *regs, uae_u8 *p, int excnum, int *gotexcnum, int *experr)
{
int exclen = 0;
uae_u8 *exc;
uae_u8 excdatalen = *p++;
int size;
- if (!excdatalen)
+ if (!excdatalen) {
return p;
+ }
+
+ if (excdatalen != 0xff) {
+ // check possible extra trace
+ last_exception_extra = *p++;
+ // some other exception + trace
+ if (last_exception_extra == 9) {
+ exceptioncount[last_exception_extra]++;
+ if (regs->tracecnt == 0) {
+ sprintf(outbp, "Expected trace exception but got none\n", regs->tracecnt);
+ outbp += strlen(outbp);
+ errors = 1;
+ *experr = 1;
+ } else {
+ uae_u16 sr = regs->tracedata[0];
+ if (!(sr & 0x2000) || (sr | 0x2000 | 0xc000) != (regs->sr | 0x2000 | 0xc000)) {
+ sprintf(outbp, "Trace exception stack frame SR mismatch: %04x != %04x\n", sr, regs->sr);
+ outbp += strlen(outbp);
+ errors = 1;
+ *experr = 1;
+ }
+ uae_u32 ret = (regs->tracedata[1] << 16) | regs->tracedata[2];
+ uae_u32 retv = exceptiontableinuse + (excnum - 2) * 2;
+ if (ret != retv) {
+ sprintf(outbp, "Trace exception stacked PC mismatch: %08lx != %08lx (%ld)\n", ret, retv, excnum);
+ outbp += strlen(outbp);
+ errors = 1;
+ *experr = 1;
+ }
+ }
+ } else if (!last_exception_extra && excnum != 9) {
+ if (regs->tracecnt > 0) {
+ sprintf(outbp, "Got unexpected trace exception\n");
+ outbp += strlen(outbp);
+ errors = 1;
+ *experr = 1;
+ }
+ } else if (last_exception_extra) {
+ end_test();
+ printf("Unsupported exception extra %d\n", last_exception_extra);
+ exit(0);
+ }
+ // trace only
+ if (excnum == 9 && *gotexcnum == 4) {
+ sp = (uae_u8 *)regs->tracedata;
+ *gotexcnum = 9;
+ }
+ }
+
+ exceptioncount[*gotexcnum]++;
+
exc = last_exception;
if (excdatalen != 0xff) {
if (cpu_lvl == 0) {
} else {
exclen = last_exception_len;
}
- if (exclen == 0 || !sameexc)
+ if (exclen == 0 || *gotexcnum != excnum)
return p;
if (memcmp(exc, sp, exclen)) {
sprintf(outbp, "Exception %ld stack frame mismatch:\n", excnum);
if (ignore_errors) {
if (exc) {
- p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr);
+ p = validate_exception(&test_regs, p, exc, &cpuexc, &experr);
}
break;
}
break;
}
if (exc) {
- p = validate_exception(&test_regs, p, exc, exc == cpuexc, &experr);
+ p = validate_exception(&test_regs, p, exc, &cpuexc, &experr);
}
if (exc != cpuexc) {
addinfo();
sr_changed = 0;
last_registers.sr = val;
} else if (mode == CT_PC) {
+ volatile uae_u16 *c = (volatile uae_u16 *)0x100;
+ *c = 0x1234;
uae_u32 val = last_registers.pc;
p = restore_rel(p, &val, 0);
pc_changed = 0;
regs.sr = interrupt_mask << 8;
regs.srcaddr = 0xffffffff;
regs.dstaddr = 0xffffffff;
+ regs.branchtarget = 0xffffffff;
start_test();
store_addr(regs.srcaddr, srcaddr);
store_addr(regs.dstaddr, dstaddr);
+ store_addr(regs.branchtarget, branchtarget);
xmemcpy(&last_registers, ®s, sizeof(struct registers));
flushcache(cpu_lvl);
uae_u32 pc = opcode_memory_addr;
+ uae_u32 originalopcodeend = 0x4afc4e71;
+ uae_u8 *opcode_memory_end = (uae_u8*)pc;
+ for (;;) {
+ if (gl(opcode_memory_end) == originalopcodeend)
+ break;
+ opcode_memory_end += 2;
+ if (opcode_memory_end > (uae_u8*)pc + 32) {
+ end_test();
+ printf("Corrupted opcode memory\n");
+ exit(0);
+ }
+ }
+ uae_u32 opcodeend = originalopcodeend;
int extraccr = 0;
int maxccr = *p++;
for (int ccr = 0; ccr < maxccr; ccr++) {
+ opcodeend = (opcodeend >> 16) | (opcodeend << 16);
+ pl(opcode_memory_end, opcodeend);
+
+ if (regs.branchtarget != 0xffffffff) {
+ if (regs.branchtarget_mode == 1) {
+ uae_u32 bv = gl((uae_u8*)regs.branchtarget);
+ bv = (bv >> 16) | (bv << 16);
+ pl((uae_u8*)regs.branchtarget, bv);
+ } else if (regs.branchtarget_mode == 2) {
+ uae_u16 bv = gw((uae_u8 *)regs.branchtarget);
+ if (bv == 0x4e71)
+ bv = 0x4afc;
+ else
+ bv = 0x4e71;
+ pw((uae_u8 *)regs.branchtarget, bv);
+ }
+ }
+
regs.ssp = super_stack_memory - 0x80;
regs.msp = super_stack_memory;
regs.pc = opcode_memory_addr;
}
p = validate_test(p, ignore_errors, ignore_sr);
+ if (regs.sr & 0x2000)
+ supercnt++;
last_pc = last_registers.pc;
last_fpiar = last_registers.fpiar;
}
+ pl(opcode_memory_end, originalopcodeend);
+
restoreahist();
}
printf("\n");
printf(outbuffer);
}
-
}
static void freestuff(void)
printf("%s:\n", inst_name);
testcnt = 0;
+ memset(exceptioncount, 0, sizeof(exceptioncount));
+ supercnt = 0;
for (;;) {
printf("%s. %lu...\n", tfname, testcnt);
filecnt++;
}
+ printf("S=%ld", supercnt);
+ for (int i = 0; i < 256; i++) {
+ if (exceptioncount[i]) {
+ printf(" E%02d=%ld", i, exceptioncount[i]);
+ }
+ }
+ printf("\n");
+
if (!errors && !quit) {
printf("All tests complete (total %lu).\n", testcnt);
}
#define GF_REVERSE 4096
#define GF_REVERSE2 8192
#define GF_SECONDWORDSETFLAGS 16384
+#define GF_SECONDEA 32768
typedef enum
{
static bool no_prefetch_ce020;
static bool got_ea_ce020;
+// 68020-30 needs different implementation than 68040/060
+static void next_level_040_to_030(void)
+{
+ if (cpu_level >= 4) {
+ if (next_cpu_level < 4)
+ next_cpu_level = 4 - 1;
+ }
+}
+
+// 68000 <> 68010
+static void next_level_000(void)
+{
+ if (next_cpu_level < 0)
+ next_cpu_level = 0;
+}
+
static void fpulimit (void)
{
if (limit_braces)
sprintf(bus_error_text, "\t\texception2_fetch(%s, m68k_getpci() + %d);\n", opcode, offset);
}
-static void check_prefetch_bus_error(int offset)
+static void check_prefetch_bus_error(int offset, int secondprefetchmode)
{
if (!using_bus_error)
return;
else
offset = 2;
// full prefetch: opcode field is zero
- if (offset == 2) {
+ if ((offset == 2 && !secondprefetchmode) || secondprefetchmode > 0) {
bus_error_specials = 1;
}
}
if (!using_prefetch)
return;
printf ("\t%s (%d);\n", prefetch_word, m68k_pc_offset + 2);
- check_prefetch_bus_error(m68k_pc_offset + 2);
+ check_prefetch_bus_error(m68k_pc_offset + 2, 0);
did_prefetch = 1;
ir2irc = 0;
count_read++;
{
if (using_prefetch) {
printf ("\t%s (%d);\n", prefetch_word, o);
- check_prefetch_bus_error(o);
+ check_prefetch_bus_error(o, 0);
did_prefetch = 1;
ir2irc = 0;
count_read++;
{
if (using_prefetch) {
printf("\t%s (%d);\n", prefetch_word, o);
- check_prefetch_bus_error(o ? -2 : -1);
+ check_prefetch_bus_error(o ? -2 : -1, 0);
did_prefetch = 1;
ir2irc = 0;
count_read++;
if (!using_prefetch)
return;
printf ("\t%s (0);\n", prefetch_word);
- check_prefetch_bus_error(0);
+ check_prefetch_bus_error(0, 0);
did_prefetch = 1;
ir2irc = 0;
count_read++;
if (!using_prefetch)
return;
printf ("\t%s (%d);\n", srcwi, o);
- check_prefetch_bus_error(o);
+ check_prefetch_bus_error(o, 0);
count_read++;
insn_n_cycles += 4;
}
{
if (using_prefetch) {
irc2ir();
+ if (using_bus_error) {
+ printf("\topcode = regs.ir;\n");
+ }
fill_prefetch_1(m68k_pc_offset + 2);
}
// if (using_prefetch_020) {
// instruction opcode and Instruction/Not field is one!
printf("\t\topcode = regs.ir;\n");
*fcmodeflags |= 0x08; // "Not instruction" = 1
+
+ } else if (dmode == Aipi) {
+
+ // move.w x,(an)+: an is not increased
+ printf("\t\tm68k_areg(regs, dstreg) -= 2;\n");
}
} else if (size == sz_long && ((offset == 0 && dmode != Apdi) || (offset == 2 && dmode == Apdi))) {
static char const *bus_error_reg;
static int bus_error_reg_add;
-static void do_bus_error_fixes(const char *name, int offset, int write)
+static int do_bus_error_fixes(const char *name, int offset, int write)
{
switch (bus_error_reg_add)
{
case 1:
- if (g_instr->mnemo == i_CMPM && write) {
- ;
- } else {
+ case -1:
+ if (g_instr->mnemo == i_CMPM && bus_error_reg_add > 0) {
+ // CMPM.B (an)+,(an)+: first increased normally, second not increased
printf("\t\tm68k_areg(regs, %s) += areg_byteinc[%s] + %d;\n", bus_error_reg, bus_error_reg, offset);
}
break;
case 2:
+ case -2:
printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset);
break;
case 3:
- if (g_instr->mnemo == i_CMPM) {
- // CMPM.L (an)+,(an)+: increased by 2
+ case -3:
+ if (g_instr->mnemo == i_CMPM && bus_error_reg_add > 0) {
+ // CMPM.L (an)+,(an)+: first increased normally, second not increased
printf("\t\tm68k_areg(regs, %s) += 2 + %d;\n", bus_error_reg, offset);
}
break;
case 4:
+ case -4:
if ((g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) && g_instr->size == sz_long) {
// ADDX.L/SUBX.L -(an),-(an) source: stack frame decreased by 2, not 4.
- offset = 2;
+ offset += 2;
} else {
printf("\t\tm68k_areg (regs, %s) = %sa;\n", bus_error_reg, name);
}
break;
}
-
+ return offset;
}
static void check_bus_error(const char *name, int offset, int write, int size, const char *writevar, int fc)
if (!using_prefetch && !using_ce)
return;
+ next_level_000();
+
uae_u32 extra = fc & 0xffff0000;
fc &= 0xffff;
move_68000_bus_error(offset, g_instr->size, &setapdiback, &fc);
}
- do_bus_error_fixes(name, offset, write);
+ offset = do_bus_error_fixes(name, offset, write);
if (g_instr->mnemo == i_BTST && (g_instr->dmode == PC16 || g_instr->dmode == PC8r)) {
// BTST special case where destination is read access
printf("\t\topcode |= 0x%x;\n", extra);
}
- if (cpu_level == 0 && write) {
- printf("\t\topcode = regs.irc;\n");
- }
+ //if (cpu_level == 0 && write) {
+ // printf("\t\topcode = regs.irc;\n");
+ //}
if (write) {
printf("\t\texception2_write(opcode, %sa + %d, %d, %s, %d);\n",
return oph;
}
-// 68020-30 needs different implementation than 68040/060
-static void next_level_040_to_030(void)
-{
- if (cpu_level >= 4) {
- if (next_cpu_level < 4)
- next_cpu_level = 4 - 1;
- }
-}
-
-static void next_level_000 (void)
-{
- if (next_cpu_level < 0)
- next_cpu_level = 0;
-}
-
static void maybeaddop_ce020 (int flags)
{
if (flags & GF_OPCE020)
break;
}
if (dmode == Apdi) {
- // this is buggy, address error stack frame opcode field contains next
- // instruction opcode and Instruction/Not field is one!
- printf("\t\topcode = regs.irc;\n");
- *fcmodeflags |= 0x08; // "Not instruction" = 1
+ // partial prefetch already done
+ printf("\t\tregs.ir = regs.irc;\n");
+ // if trace, I/N is also set
+ printf("\t\tif(regs.t1) opcode |= 0x10000;\n");
+
}
if (set_ccr) {
printf("\t\tccr_68000_word_move_ae_normal((uae_s16)(src));\n");
} else if (mode == Apdi) {
bus_error_reg_add = 4;
}
+ if (flags & GF_SECONDEA) {
+ bus_error_reg_add = -bus_error_reg_add;
+ }
}
exception_pc_offset = 0;
int fcmodeflags = 0;
int exp3rw = getv == 2;
+ next_level_000();
+
printf("\tif (%sa & 1) {\n", name);
if (cpu_level == 1) {
- if (bus_error_reg_add == 4)
+ if (abs(bus_error_reg_add) == 4)
bus_error_reg_add = 0;
// 68010 CLR <memory>: pre and post are not added yet
if (g_instr->mnemo == i_CLR) {
subhead_ce020 = subhead;
curi_ce020 = curi;
genamode3 (curi, smode, sreg, ssize, sname, sgetv, 0, sflags);
- genamode3 (NULL, dmode, dreg, dsize, dname, dgetv, 0, dflags | (eadmode == true ? GF_OPCE020 : 0));
+ genamode3 (NULL, dmode, dreg, dsize, dname, dgetv, 0, dflags | (eadmode == true ? GF_OPCE020 : 0) | GF_SECONDEA);
if (eadmode == false)
maybeaddop_ce020 (GF_OPCE020);
}
start_brace();
if (table68k[opcode].size == sz_long) {
printf("\twhile (dmask) {\n");
- printf("\t\tuae_u32 v = %s (srca) << 16;\n", srcw);
+ printf("\t\tuae_u32 v = (%s(srca) << 16) | (m68k_dreg(regs, movem_index1[dmask]) & 0xffff);\n", srcw);
check_bus_error("src", 0, 0, 1, NULL, 1);
- printf("\t\tv |= %s (srca + 2);\n", srcw);
+ printf("\t\tm68k_dreg(regs, movem_index1[dmask]) = v;\n");
+ printf("\t\tv &= 0xffff0000;\n");
+ printf("\t\tv |= % s(srca + 2); \n", srcw);
check_bus_error("src", 2, 0, 1, NULL, 1);
- printf("\t\tm68k_dreg (regs, movem_index1[dmask]) = v;\n");
+ printf("\t\tm68k_dreg(regs, movem_index1[dmask]) = v;\n");
printf("\t\tsrca += %d;\n", size);
printf("\t\tdmask = movem_next[dmask];\n");
addcycles000_nonce("\t\t", 8);
printf("\t}\n");
printf("\twhile (amask) {\n");
- printf("\t\tuae_u32 v = %s (srca) << 16;\n", srcw);
+ printf("\t\tuae_u32 v = (%s(srca) << 16) | (m68k_areg(regs, movem_index1[amask]) & 0xffff);\n", srcw);
check_bus_error("src", 0, 0, 1, NULL, 1);
- printf("\t\tv |= %s (srca + 2);\n", srcw);
+ printf("\t\tm68k_areg(regs, movem_index1[amask]) = v;\n");
+ printf("\t\tv &= 0xffff0000;\n");
+ printf("\t\tv |= %s(srca + 2);\n", srcw);
check_bus_error("src", 2, 0, 1, NULL, 1);
- printf("\t\tm68k_areg (regs, movem_index1[amask]) = v;\n");
+ printf("\t\tm68k_areg(regs, movem_index1[amask]) = v;\n");
printf("\t\tsrca += %d;\n", size);
printf("\t\tamask = movem_next[amask];\n");
addcycles000_nonce("\t\t", 8);
if (!isreg (curi->smode))
addcycles000 (2);
genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE);
- genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW);
+ genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA);
fill_prefetch_next ();
if (curi->size == sz_long && isreg (curi->smode))
addcycles000 (4);
if (!isreg (curi->smode))
addcycles000 (2);
genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, GF_AA | GF_REVERSE);
- genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW);
+ genamode (curi, curi->dmode, "dstreg", curi->size, "dst", 1, 0, GF_AA | GF_REVERSE | GF_RMW | GF_SECONDEA);
fill_prefetch_next ();
if (curi->size == sz_long && isreg (curi->smode))
addcycles000 (4);
next_level_040_to_030();
break;
case i_JSR:
- // possible idle cycle, prefetch from new address, stack high return addr, stack low, prefetch
- no_prefetch_ce020 = true;
- genamode (curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA|GF_NOREFILL);
- start_brace ();
- printf("\tuaecptr oldpc = %s;\n", getpc);
- printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset);
- if (using_exception_3 && cpu_level <= 1) {
- printf("\tif (srca & 1) {\n");
- printf("\t\texception3i (opcode, srca);\n");
- printf("\t\tgoto %s;\n", endlabelstr);
- printf("\t}\n");
- need_endlabel = 1;
- }
- if (using_mmu) {
- printf ("\t%s (m68k_areg (regs, 7) - 4, nextpc);\n", dstl);
- printf ("\tm68k_areg (regs, 7) -= 4;\n");
- setpc ("srca");
- clear_m68k_offset();
- } else {
- if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16)
- addcycles000 (2);
- if (curi->smode == Ad8r || curi->smode == PC8r) {
- addcycles000 (6);
- if (cpu_level <= 1 && using_prefetch)
- printf ("\tnextpc += 2;\n");
- }
- setpc ("srca");
- clear_m68k_offset();
- if (using_exception_3 && cpu_level >= 2) {
- printf("\tif (%s & 1) {\n", getpc);
- printf("\t\texception3i (opcode, %s);\n", getpc);
- printf("\t\tgoto %s;\n", endlabelstr);
- printf("\t}\n");
- need_endlabel = 1;
- }
- fill_prefetch_1(0);
- if (cpu_level < 4)
- printf("\tm68k_areg (regs, 7) -= 4;\n");
+ {
+ // possible idle cycle, prefetch from new address, stack high return addr, stack low, prefetch
+ no_prefetch_ce020 = true;
+ genamode(curi, curi->smode, "srcreg", curi->size, "src", 0, 0, GF_AA | GF_NOREFILL);
+ start_brace();
+ printf("\tuaecptr oldpc = %s;\n", getpc);
+ printf("\tuaecptr nextpc = oldpc + %d;\n", m68k_pc_offset);
if (using_exception_3 && cpu_level <= 1) {
- printf("\tif (m68k_areg(regs, 7) & 1) {\n");
- printf("\t\texception3_write(opcode, m68k_areg(regs, 7), 1, m68k_areg(regs, 7) >> 16, 1);\n");
+ printf("\tif (srca & 1) {\n");
+ printf("\t\texception3i (opcode, srca);\n");
printf("\t\tgoto %s;\n", endlabelstr);
printf("\t}\n");
need_endlabel = 1;
}
- if (using_ce || using_prefetch) {
- printf("\tuaecptr dsta = m68k_areg(regs, 7);\n");
- printf("\t%s(dsta, nextpc >> 16);\n", dstw);
- check_bus_error("dst", 0, 1, 1, "nextpc >> 16", 1);
- printf("\t%s(dsta + 2, nextpc);\n", dstw);
- check_bus_error("dst", 2, 1, 1, "nextpc", 1);
+ if (using_mmu) {
+ printf("\t%s (m68k_areg (regs, 7) - 4, nextpc);\n", dstl);
+ printf("\tm68k_areg (regs, 7) -= 4;\n");
+ setpc("srca");
+ clear_m68k_offset();
} else {
+ if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16)
+ addcycles000(2);
+ if (curi->smode == Ad8r || curi->smode == PC8r) {
+ addcycles000(6);
+ if (cpu_level <= 1 && using_prefetch)
+ printf("\tnextpc += 2;\n");
+ }
+ setpc("srca");
+ clear_m68k_offset();
+ if (using_exception_3 && cpu_level >= 2) {
+ printf("\tif (%s & 1) {\n", getpc);
+ printf("\t\texception3i (opcode, %s);\n", getpc);
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
+ need_endlabel = 1;
+ }
+ fill_prefetch_1(0);
if (cpu_level < 4)
- printf("\t%s(m68k_areg(regs, 7), nextpc);\n", dstl);
- else
- printf("\t%s(m68k_areg(regs, 7) - 4, nextpc);\n", dstl);
+ printf("\tm68k_areg (regs, 7) -= 4;\n");
+ if (using_exception_3 && cpu_level <= 1) {
+ printf("\tif (m68k_areg(regs, 7) & 1) {\n");
+ printf("\t\texception3_write(opcode, m68k_areg(regs, 7), 1, m68k_areg(regs, 7) >> 16, 1);\n");
+ printf("\t\tgoto %s;\n", endlabelstr);
+ printf("\t}\n");
+ need_endlabel = 1;
+ }
+ if (using_ce || using_prefetch) {
+ printf("\tuaecptr dsta = m68k_areg(regs, 7);\n");
+ printf("\t%s(dsta, nextpc >> 16);\n", dstw);
+ check_bus_error("dst", 0, 1, 1, "nextpc >> 16", 1);
+ printf("\t%s(dsta + 2, nextpc);\n", dstw);
+ check_bus_error("dst", 2, 1, 1, "nextpc", 1);
+ } else {
+ if (cpu_level < 4)
+ printf("\t%s(m68k_areg(regs, 7), nextpc);\n", dstl);
+ else
+ printf("\t%s(m68k_areg(regs, 7) - 4, nextpc);\n", dstl);
+ }
+ if (cpu_level >= 4)
+ printf("\tm68k_areg (regs, 7) -= 4;\n");
+ if (using_debugmem) {
+ printf("\tif (debugmem_trace)\n");
+ printf("\t\tbranch_stack_push(oldpc, nextpc);\n");
+ }
}
- if (cpu_level >= 4)
- printf("\tm68k_areg (regs, 7) -= 4;\n");
- if (using_debugmem) {
- printf("\tif (debugmem_trace)\n");
- printf("\t\tbranch_stack_push(oldpc, nextpc);\n");
+ count_write += 2;
+ fill_prefetch_full_020();
+ if (using_prefetch || using_ce) {
+ int sp = (curi->smode == Ad16 || curi->smode == absw || curi->smode == absl || curi->smode == PC16 || curi->smode == Ad8r || curi->smode == PC8r) ? -1 : 0;
+ irc2ir();
+ printf("\topcode = regs.ir;\n");
+ printf("\t%s (%d);\n", prefetch_word, 2);
+ check_prefetch_bus_error(-2, sp);
+ did_prefetch = 1;
+ ir2irc = 0;
+ count_read++;
+ insn_n_cycles += 4;
+ } else {
+ fill_prefetch_next_empty();
}
+ branch_inst = 1;
+ next_level_040_to_030();
}
- count_write += 2;
- fill_prefetch_full_020 ();
- fill_prefetch_next_empty();
- branch_inst = 1;
- next_level_040_to_030();
break;
case i_JMP:
no_prefetch_ce020 = true;
addcycles000 (6);
setpc ("srca");
clear_m68k_offset();
- fill_prefetch_full ();
+ if (using_prefetch || using_ce) {
+ printf("\t%s (%d);\n", prefetch_word, 0);
+ check_prefetch_bus_error(-1, 0);
+ irc2ir();
+ printf("\t%s (%d);\n", prefetch_word, 2);
+ int sp = (curi->smode == Ad16 || curi->smode == absw || curi->smode == absl || curi->smode == PC16 || curi->smode == Ad8r || curi->smode == PC8r) ? -1 : 0;
+ printf("\topcode = regs.ir;\n");
+ check_prefetch_bus_error(-2, sp);
+ did_prefetch = 1;
+ ir2irc = 0;
+ count_read++;
+ insn_n_cycles += 4;
+ } else {
+ fill_prefetch_full();
+ }
branch_inst = 1;
break;
case i_BSR:
extern uae_u32 exception_pc(int nr);
extern void cpu_restore_fixup(void);
extern bool privileged_copro_instruction(uae_u16 opcode);
+extern bool generates_group1_exception(uae_u16 opcode);
void ccr_68000_long_move_ae_LZN(uae_s32 src);
void ccr_68000_long_move_ae_LN(uae_s32 src);
/* set when writing exception stack frame */
static int exception_in_exception;
+static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc);
+
int mmu_enabled, mmu_triggered;
int cpu_cycles;
int bus_error_offset;
if (nr == 2 || nr == 3)
cpu_halt (CPU_HALT_DOUBLE_FAULT);
else
- exception3_read(regs.ir, newpc, 1, 1);
+ exception3_read_special(regs.ir, newpc, 1, 1);
return;
}
if (interrupt)
if (nr == 2 || nr == 3)
cpu_halt (CPU_HALT_DOUBLE_FAULT);
else
- exception3_read(regs.ir, newpc, 2, 1);
+ exception3_read_special(regs.ir, newpc, 2, 1);
return;
}
if (nr == 2 || nr == 3)
cpu_halt (CPU_HALT_DOUBLE_FAULT);
else
- exception3_read(regs.ir, newpc, 2, 1);
+ exception3_read_special(regs.ir, newpc, 2, 1);
return;
}
m68k_setpc (newpc);
{
exception3f (opcode, addr, true, false, true, 0xffffffff, 1, false, -1);
}
+static void exception3_read_special(uae_u32 opcode, uaecptr addr, int size, int fc)
+{
+ exception3f(opcode, addr, false, 0, false, 0xffffffff, size, false, fc);
+}
void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc)
{
- exception3f (opcode, addr, false, 0, false, 0xffffffff, size, false, fc);
+ bool ni = false;
+ if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
+ if (generates_group1_exception(regs.ir)) {
+ ni = true;
+ fc = -1;
+ }
+ if (opcode & 0x100000)
+ ni = true;
+ opcode = regs.ir;
+ }
+ exception3f (opcode, addr, false, 0, ni, 0xffffffff, size, false, fc);
}
void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc)
{
- exception3f (opcode, addr, true, 0, false, 0xffffffff, size, false, fc);
+ bool ni = false;
+ if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
+ if (generates_group1_exception(regs.ir)) {
+ ni = true;
+ fc = -1;
+ }
+ if (opcode & 0x100000)
+ ni = true;
+ opcode = regs.ir;
+ }
+ exception3f (opcode, addr, true, 0, ni, 0xffffffff, size, false, fc);
regs.write_buffer = val;
}
void exception3i (uae_u32 opcode, uaecptr addr)
last_size_for_exception_3 = size;
last_di_for_exception_3 = 1;
cpu_bus_error = 0;
+
+ if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
+ if (generates_group1_exception(regs.ir)) {
+ last_notinstruction_for_exception_3 = true;
+ fc = -1;
+ }
+ last_op_for_exception_3 = regs.ir;
+ }
}
void exception2(uaecptr addr, bool read, int size, uae_u32 fc)
}
return false;
}
+
+bool generates_group1_exception(uae_u16 opcode)
+{
+ struct instr *table = &table68k[opcode];
+ // illegal/a-line/f-line?
+ if (table->mnemo == i_ILLG)
+ return true;
+ // privilege violation?
+ if (!regs.s) {
+ if (table->plev == 1 && currprefs.cpu_model > 68000)
+ return true;
+ if (table->plev == 2)
+ return true;
+ if (table->plev == 3 && table->size == sz_word)
+ return true;
+ }
+ return false;
+}