--- previous/src/cpu/newcpu.c 2018/04/24 19:25:47 1.1 +++ previous/src/cpu/newcpu.c 2018/04/24 19:31:50 1.1.1.5 @@ -1,4963 +1,2373 @@ -/* -* UAE - The Un*x Amiga Emulator -* -* MC68000 emulation -* -* (c) 1995 Bernd Schmidt -*/ - -#define MOVEC_DEBUG 0 -#define MMUOP_DEBUG 2 -#define DEBUG_CD32CDTVIO 0 - -/* - * #include "compat.h" -#include "sysconfig.h" -#include "sysdeps.h" - -#include "options_cpu.h" -#include "events.h" -//#include "uae.h" -#include "memory.h" -#include "custom.h" -#include "newcpu.h" -#include "cpummu.h" -#include "cpu_prefetch.h" -//#include "autoconf.h" -//#include "traps.h" -//#include "ersatz.h" -//#include "debug.h" -//#include "gui.h" -#include "savestate.h" -#include "blitter.h" -#include "ar.h" -//#include "gayle.h" -//#include "cia.h" -//#include "inputdevice.h" -*/ - -#include "compat.h" -#include "sysconfig.h" -#include "sysdeps.h" -#include "hatari-glue.h" -#include "options_cpu.h" -#include "events.h" -#include "custom.h" -#include "maccess.h" -#include "memory.h" -#include "newcpu.h" -#include "main.h" -#include "cpummu.h" -#include "cpu_prefetch.h" -#include "main.h" -#include "m68000.h" -#include "reset.h" -#include "cycInt.h" -#include "mfp.h" -#include "cart.h" -#include "dialog.h" -#include "screen.h" -#include "video.h" -#include "options.h" -#include "log.h" -#include "debugui.h" -#include "debugcpu.h" - - -#ifdef JIT -#include "jit/compemu.h" -#include -#else -/* Need to have these somewhere */ -// static void build_comp (void) {} -// bool check_prefs_changed_comp (void) { return false; } -#endif -/* For faster JIT cycles handling */ -signed long pissoff = 0; - -uaecptr rtarea_base = RTAREA_DEFAULT; - -/* Opcode of faulting instruction */ -static uae_u16 last_op_for_exception_3; -/* PC at fault time */ -static uaecptr last_addr_for_exception_3; -/* Address that generated the exception */ -static uaecptr last_fault_for_exception_3; -/* read (0) or write (1) access */ -static int last_writeaccess_for_exception_3; -/* instruction (1) or data (0) access */ -static int last_instructionaccess_for_exception_3; -unsigned long irqcycles[15]; -int irqdelay[15]; -int mmu_enabled, mmu_triggered; -int cpu_cycles; -static int baseclock; -int cpucycleunit; - -const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 }; -const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 }; - -int movem_index1[256]; -int movem_index2[256]; -int movem_next[256]; - -cpuop_func *cpufunctbl[65536]; - -int OpcodeFamily; -struct mmufixup mmufixup[2]; - -extern uae_u32 get_fpsr (void); - -#define COUNT_INSTRS 0 -#define MC68060_PCR 0x04300000 -#define MC68EC060_PCR 0x04310000 - -static uae_u64 srp_030, crp_030; -static uae_u32 tt0_030, tt1_030, tc_030; -static uae_u16 mmusr_030; - -static struct cache020 caches020[CACHELINES020]; -static struct cache030 icaches030[CACHELINES030]; -static struct cache030 dcaches030[CACHELINES030]; -static struct cache040 caches040[CACHESETS040]; -static void InterruptAddJitter (int Level , int Pending); - -static void m68k_disasm_2 (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode); - - -#if COUNT_INSTRS -static unsigned long int instrcount[65536]; -static uae_u16 opcodenums[65536]; - -static int compfn (const void *el1, const void *el2) -{ - return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2]; -} - -static TCHAR *icountfilename (void) -{ - TCHAR *name = getenv ("INSNCOUNT"); - if (name) - return name; - return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount"; -} - -void dump_counts (void) -{ - FILE *f = fopen (icountfilename (), "w"); - unsigned long int total; - int i; - - write_log ("Writing instruction count file...\n"); - for (i = 0; i < 65536; i++) { - opcodenums[i] = i; - total += instrcount[i]; - } - qsort (opcodenums, 65536, sizeof (uae_u16), compfn); - - fprintf (f, "Total: %lu\n", total); - for (i=0; i < 65536; i++) { - unsigned long int cnt = instrcount[opcodenums[i]]; - struct instr *dp; - struct mnemolookup *lookup; - if (!cnt) - break; - dp = table68k + opcodenums[i]; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) - ; - fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name); - } - fclose (f); -} -#else -void dump_counts (void) -{ -} -#endif - - -uae_u32 (*x_prefetch)(int); -uae_u32 (*x_next_iword)(void); -uae_u32 (*x_next_ilong)(void); -uae_u32 (*x_get_long)(uaecptr); -uae_u32 (*x_get_word)(uaecptr); -uae_u32 (*x_get_byte)(uaecptr); -void (*x_put_long)(uaecptr,uae_u32); -void (*x_put_word)(uaecptr,uae_u32); -void (*x_put_byte)(uaecptr,uae_u32); - -// shared memory access functions -static void set_x_funcs (void) -{ - if (currprefs.mmu_model) { - x_prefetch = get_iword_mmu; - x_next_iword = next_iword_mmu; - x_next_ilong = next_ilong_mmu; - x_put_long = put_long_mmu; - x_put_word = put_word_mmu; - x_put_byte = put_byte_mmu; - x_get_long = get_long_mmu; - x_get_word = get_word_mmu; - x_get_byte = get_byte_mmu; - } else if (!currprefs.cpu_cycle_exact) { - x_prefetch = get_iword; - x_next_iword = next_iword; - x_next_ilong = next_ilong; - x_put_long = put_long; - x_put_word = put_word; - x_put_byte = put_byte; - x_get_long = get_long; - x_get_word = get_word; - x_get_byte = get_byte; - } else if (currprefs.cpu_model < 68020) { - x_prefetch = NULL; - x_next_iword = NULL; - x_next_ilong = NULL; - x_put_long = put_long_ce; - x_put_word = put_word_ce; - x_put_byte = put_byte_ce; - x_get_long = get_long_ce; - x_get_word = get_word_ce; - x_get_byte = get_byte_ce; - } else if (currprefs.cpu_model == 68020) { - x_prefetch = get_word_ce020_prefetch; - x_next_iword = next_iword_020ce; - x_next_ilong = next_ilong_020ce; - x_put_long = put_long_ce020; - x_put_word = put_word_ce020; - x_put_byte = put_byte_ce020; - x_get_long = get_long_ce020; - x_get_word = get_word_ce020; - x_get_byte = get_byte_ce020; - } else { - x_prefetch = get_word_ce030_prefetch; - x_next_iword = next_iword_030ce; - x_next_ilong = next_ilong_030ce; - x_put_long = put_long_ce030; - x_put_word = put_word_ce030; - x_put_byte = put_byte_ce030; - x_get_long = get_long_ce030; - x_get_word = get_word_ce030; - x_get_byte = get_byte_ce030; - } - -} - -static void set_cpu_caches (void) -{ - int i; - - for (i = 0; i < CPU_PIPELINE_MAX; i++) - regs.prefetch020addr[i] = 0xffffffff; - -#ifdef JIT - if (currprefs.cachesize) { - if (currprefs.cpu_model < 68040) { - set_cache_state (regs.cacr & 1); - if (regs.cacr & 0x08) { - flush_icache (0, 3); - } - } else { - set_cache_state ((regs.cacr & 0x8000) ? 1 : 0); - } - } -#endif - if (currprefs.cpu_model == 68020) { - if (regs.cacr & 0x08) { // clear instr cache - for (i = 0; i < CACHELINES020; i++) - caches020[i].valid = 0; - } - if (regs.cacr & 0x04) { // clear entry in instr cache - caches020[(regs.caar >> 2) & (CACHELINES020 - 1)].valid = 0; - regs.cacr &= ~0x04; - } - } else if (currprefs.cpu_model == 68030) { - //regs.cacr |= 0x100; - if (regs.cacr & 0x08) { // clear instr cache - for (i = 0; i < CACHELINES030; i++) { - icaches030[i].valid[0] = 0; - icaches030[i].valid[1] = 0; - icaches030[i].valid[2] = 0; - icaches030[i].valid[3] = 0; - } - } - if (regs.cacr & 0x04) { // clear entry in instr cache - icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0; - regs.cacr &= ~0x04; - } - if (regs.cacr & 0x800) { // clear data cache - for (i = 0; i < CACHELINES030; i++) { - dcaches030[i].valid[0] = 0; - dcaches030[i].valid[1] = 0; - dcaches030[i].valid[2] = 0; - dcaches030[i].valid[3] = 0; - } - regs.cacr &= ~0x800; - } - if (regs.cacr & 0x400) { // clear entry in data cache - dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0; - regs.cacr &= ~0x400; - } - } else if (currprefs.cpu_model == 68040) { - if (!(regs.cacr & 0x8000)) { - for (i = 0; i < CACHESETS040; i++) { - caches040[i].valid[0] = 0; - caches040[i].valid[1] = 0; - caches040[i].valid[2] = 0; - caches040[i].valid[3] = 0; - } - } - } -} - -STATIC_INLINE void count_instr (unsigned int opcode) -{ -} - -static unsigned long REGPARAM3 op_illg_1 (uae_u32 opcode) REGPARAM; - -static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode) -{ - op_illg (opcode); - return 4; -} - -void build_cpufunctbl (void) -{ - int i, opcnt; - unsigned long opcode; - const struct cputbl *tbl = 0; - int lvl; - - switch (currprefs.cpu_model) - { -#ifdef CPUEMU_0 -#ifndef CPUEMU_68000_ONLY - case 68060: - lvl = 5; - tbl = op_smalltbl_0_ff; - if (currprefs.cpu_cycle_exact) - tbl = op_smalltbl_21_ff; - if (currprefs.mmu_model) - tbl = op_smalltbl_31_ff; - break; - case 68040: - lvl = 4; - tbl = op_smalltbl_1_ff; - if (currprefs.cpu_cycle_exact) - tbl = op_smalltbl_22_ff; - if (currprefs.mmu_model) - tbl = op_smalltbl_31_ff; - break; - case 68030: - lvl = 3; - tbl = op_smalltbl_2_ff; - if (currprefs.cpu_cycle_exact) - tbl = op_smalltbl_23_ff; - break; - case 68020: - lvl = 2; - tbl = op_smalltbl_3_ff; - if (currprefs.cpu_cycle_exact) - tbl = op_smalltbl_20_ff; - break; - case 68010: - lvl = 1; - tbl = op_smalltbl_4_ff; - break; -#endif -#endif - default: - changed_prefs.cpu_model = currprefs.cpu_model = 68000; - case 68000: - lvl = 0; - tbl = op_smalltbl_5_ff; -#ifdef CPUEMU_11 - if (currprefs.cpu_compatible) - tbl = op_smalltbl_11_ff; /* prefetch */ -#endif -#ifdef CPUEMU_12 - if (currprefs.cpu_cycle_exact) - tbl = op_smalltbl_12_ff; /* prefetch and cycle-exact */ -#endif - break; - } - - if (tbl == 0) { - write_log ("no CPU emulation cores available CPU=%d!", currprefs.cpu_model); - abort (); - } - - for (opcode = 0; opcode < 65536; opcode++) - cpufunctbl[opcode] = op_illg_1; - for (i = 0; tbl[i].handler != NULL; i++) { - opcode = tbl[i].opcode; - cpufunctbl[opcode] = tbl[i].handler; - } - - /* hack fpu to 68000/68010 mode */ - if (currprefs.fpu_model && currprefs.cpu_model < 68020) { - tbl = op_smalltbl_3_ff; - for (i = 0; tbl[i].handler != NULL; i++) { - if ((tbl[i].opcode & 0xfe00) == 0xf200) - cpufunctbl[tbl[i].opcode] = tbl[i].handler; - } - } - opcnt = 0; - for (opcode = 0; opcode < 65536; opcode++) { - cpuop_func *f; - - if (table68k[opcode].mnemo == i_ILLG) - continue; - if (currprefs.fpu_model && currprefs.cpu_model < 68020) { - /* more hack fpu to 68000/68010 mode */ - if (table68k[opcode].clev > lvl && (opcode & 0xfe00) != 0xf200) - continue; - } else if (table68k[opcode].clev > lvl) { - continue; - } - - if (table68k[opcode].handler != -1) { - int idx = table68k[opcode].handler; - f = cpufunctbl[idx]; - if (f == op_illg_1) - abort (); - cpufunctbl[opcode] = f; - opcnt++; - } - } - write_log ("Building CPU, %d opcodes (%d %d %d)\n", - opcnt, lvl, - currprefs.cpu_cycle_exact ? -1 : currprefs.cpu_compatible ? 1 : 0, currprefs.address_space_24); - write_log ("CPU=%d, FPU=%d, MMU=%d, JIT%s=%d.\n", - currprefs.cpu_model, currprefs.fpu_model, - currprefs.mmu_model, - currprefs.cachesize ? (currprefs.compfpu ? "=CPU/FPU" : "=CPU") : "", - currprefs.cachesize); -#ifdef JIT - build_comp (); -#endif - set_cpu_caches (); - if (currprefs.mmu_model) { - mmu_reset (); - mmu_set_tc (regs.tcr); - mmu_set_super (regs.s != 0); - } -} - -void fill_prefetch_slow (void) -{ - if (currprefs.mmu_model) - return; - regs.ir = x_get_word (m68k_getpc ()); - regs.irc = x_get_word (m68k_getpc () + 2); -} - -unsigned long cycles_mask, cycles_val; - -static void update_68k_cycles (void) -{ - cycles_mask = 0; - cycles_val = currprefs.m68k_speed; - if (currprefs.m68k_speed < 1) { - cycles_mask = 0xFFFFFFFF; - cycles_val = 0; - } - currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier; - currprefs.cpu_frequency = changed_prefs.cpu_frequency; - - baseclock = currprefs.ntscmode ? 28636360 : 28375160; - cpucycleunit = CYCLE_UNIT / 2; - if (currprefs.cpu_clock_multiplier) { - if (currprefs.cpu_clock_multiplier >= 256) { - cpucycleunit = CYCLE_UNIT / (currprefs.cpu_clock_multiplier >> 8); - } else { - cpucycleunit = CYCLE_UNIT * currprefs.cpu_clock_multiplier; - } - } else if (currprefs.cpu_frequency) { - cpucycleunit = CYCLE_UNIT * baseclock / currprefs.cpu_frequency; - } - if (cpucycleunit < 1) - cpucycleunit = 1; - if (currprefs.cpu_cycle_exact) - write_log ("CPU cycleunit: %d (%.3f)\n", cpucycleunit, (float)cpucycleunit / CYCLE_UNIT); - config_changed = 1; -} - -static void prefs_changed_cpu (void) -{ - fixup_cpu (&changed_prefs); - currprefs.cpu_model = changed_prefs.cpu_model; - currprefs.fpu_model = changed_prefs.fpu_model; - currprefs.mmu_model = changed_prefs.mmu_model; - currprefs.cpu_compatible = changed_prefs.cpu_compatible; - currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact; - currprefs.blitter_cycle_exact = changed_prefs.cpu_cycle_exact; -} - -void check_prefs_changed_cpu (void) -{ - bool changed = 0; - - if (!config_changed) - return; -#ifdef JIT - changed = check_prefs_changed_comp (); -#endif - if (changed - || currprefs.cpu_model != changed_prefs.cpu_model - || currprefs.fpu_model != changed_prefs.fpu_model - || currprefs.mmu_model != changed_prefs.mmu_model - || currprefs.cpu_compatible != changed_prefs.cpu_compatible - || currprefs.cpu_cycle_exact != changed_prefs.cpu_cycle_exact) { - - prefs_changed_cpu (); - if (!currprefs.cpu_compatible && changed_prefs.cpu_compatible) - fill_prefetch_slow (); - build_cpufunctbl (); - changed = 1; - } - if (changed - || currprefs.m68k_speed != changed_prefs.m68k_speed - || currprefs.cpu_clock_multiplier != changed_prefs.cpu_clock_multiplier - || currprefs.cpu_frequency != changed_prefs.cpu_frequency) { - currprefs.m68k_speed = changed_prefs.m68k_speed; - reset_frame_rate_hack (); - update_68k_cycles (); - changed = 1; - } - - if (currprefs.cpu_idle != changed_prefs.cpu_idle) { - currprefs.cpu_idle = changed_prefs.cpu_idle; - } - if (changed) - set_special (SPCFLAG_BRK); - -} - -void init_m68k (void) -{ - int i; - - prefs_changed_cpu (); - update_68k_cycles (); - - for (i = 0 ; i < 256 ; i++) { - int j; - for (j = 0 ; j < 8 ; j++) { - if (i & (1 << j)) break; - } - movem_index1[i] = j; - movem_index2[i] = 7-j; - movem_next[i] = i & (~(1 << j)); - } - -#if COUNT_INSTRS - { - FILE *f = fopen (icountfilename (), "r"); - memset (instrcount, 0, sizeof instrcount); - if (f) { - uae_u32 opcode, count, total; - TCHAR name[20]; - write_log ("Reading instruction count file...\n"); - fscanf (f, "Total: %lu\n", &total); - while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) { - instrcount[opcode] = count; - } - fclose (f); - } - } -#endif - write_log ("Building CPU table for configuration: %d", currprefs.cpu_model); - regs.address_space_mask = 0xffffffff; -// if (currprefs.cpu_compatible) { -// if (currprefs.address_space_24 && currprefs.cpu_model >= 68030) -// currprefs.address_space_24 = false; -// } - if (currprefs.fpu_model > 0) - write_log ("/%d", currprefs.fpu_model); - if (currprefs.cpu_cycle_exact) { - if (currprefs.cpu_model == 68000) - write_log (" prefetch and cycle-exact"); - else - write_log (" ~cycle-exact"); - } else if (currprefs.cpu_compatible) - write_log (" prefetch"); - if (currprefs.address_space_24) { - regs.address_space_mask = 0x00ffffff; - write_log (" 24-bit"); - } - write_log ("\n"); - - read_table68k (); - do_merges (); - - write_log ("%d CPU functions\n", nr_cpuop_funcs); - - build_cpufunctbl (); - set_x_funcs (); - -#ifdef JIT - /* We need to check whether NATMEM settings have changed - * before starting the CPU */ - check_prefs_changed_comp (); -#endif -} - -struct regstruct regs, mmu_backup_regs; -struct flag_struct regflags; -static struct regstruct regs_backup[16]; -static int backup_pointer = 0; -static long int m68kpc_offset; - -#define get_ibyte_1(o) get_byte (regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1) -#define get_iword_1(o) get_word (regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) -#define get_ilong_1(o) get_long (regs.pc + (regs.pc_p - regs.pc_oldp) + (o)) - -static uae_s32 ShowEA (FILE *f, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode) -{ - uae_u16 dp; - uae_s8 disp8; - uae_s16 disp16; - int r; - uae_u32 dispreg; - uaecptr addr = 0; - uae_s32 offset = 0; - TCHAR buffer[80]; - - switch (mode){ - case Dreg: - _stprintf (buffer, "D%d", reg); - break; - case Areg: - _stprintf (buffer, "A%d", reg); - break; - case Aind: - _stprintf (buffer, "(A%d)", reg); - addr = regs.regs[reg + 8]; - break; - case Aipi: - _stprintf (buffer, "(A%d)+", reg); - addr = regs.regs[reg + 8]; - break; - case Apdi: - _stprintf (buffer, "-(A%d)", reg); - addr = regs.regs[reg + 8]; - break; - case Ad16: - { - TCHAR offtxt[80]; - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - if (disp16 < 0) - _stprintf (offtxt, "-$%04x", -disp16); - else - _stprintf (offtxt, "$%04x", disp16); - addr = m68k_areg (regs, reg) + disp16; - _stprintf (buffer, "(A%d, %s) == $%08lx", reg, offtxt, (unsigned long)addr); - } - break; - case Ad8r: - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0, disp = 0; - uae_s32 base = m68k_areg (regs, reg); - TCHAR name[10]; - _stprintf (name, "A%d, ", reg); - if (dp & 0x80) { base = 0; name[0] = 0; } - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if ((dp & 3) && !safemode) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - _stprintf (buffer, "(%s%c%d.%c*%d+%d)+%d == $%08lx", name, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), - disp, outer, - (unsigned long)addr); - } else { - addr = m68k_areg (regs, reg) + (uae_s32)((uae_s8)disp8) + dispreg; - _stprintf (buffer, "(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), disp8, - (unsigned long)addr); - } - break; - case PC16: - addr = m68k_getpc () + m68kpc_offset; - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr += (uae_s16)disp16; - _stprintf (buffer, "(PC,$%04x) == $%08lx", disp16 & 0xffff, (unsigned long)addr); - break; - case PC8r: - addr = m68k_getpc () + m68kpc_offset; - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0, disp = 0; - uae_s32 base = addr; - TCHAR name[10]; - _stprintf (name, "PC, "); - if (dp & 0x80) { base = 0; name[0] = 0; } - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if ((dp & 3) && !safemode) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - _stprintf (buffer, "(%s%c%d.%c*%d+%d)+%d == $%08lx", name, - dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', - 1 << ((dp >> 9) & 3), - disp, outer, - (unsigned long)addr); - } else { - addr += (uae_s32)((uae_s8)disp8) + dispreg; - _stprintf (buffer, "(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D', - (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), - disp8, (unsigned long)addr); - } - break; - case absw: - addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - _stprintf (buffer, "$%08lx", (unsigned long)addr); - m68kpc_offset += 2; - break; - case absl: - addr = get_ilong_1 (m68kpc_offset); - _stprintf (buffer, "$%08lx", (unsigned long)addr); - m68kpc_offset += 4; - break; - case imm: - switch (size){ - case sz_byte: - _stprintf (buffer, "#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff)); - m68kpc_offset += 2; - break; - case sz_word: - _stprintf (buffer, "#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff)); - m68kpc_offset += 2; - break; - case sz_long: - _stprintf (buffer, "#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset))); - m68kpc_offset += 4; - break; - default: - break; - } - break; - case imm0: - offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - _stprintf (buffer, "#$%02x", (unsigned int)(offset & 0xff)); - break; - case imm1: - offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - buffer[0] = 0; - _stprintf (buffer, "#$%04x", (unsigned int)(offset & 0xffff)); - break; - case imm2: - offset = (uae_s32)get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - _stprintf (buffer, "#$%08lx", (unsigned long)offset); - break; - case immi: - offset = (uae_s32)(uae_s8)(reg & 0xff); - _stprintf (buffer, "#$%08lx", (unsigned long)offset); - break; - default: - break; - } - if (buf == 0) - f_out (f, "%s", buffer); - else - _tcscat (buf, buffer); - if (eaddr) - *eaddr = addr; - return offset; -} - -#if 0 -/* The plan is that this will take over the job of exception 3 handling - -* the CPU emulation functions will just do a longjmp to m68k_go whenever -* they hit an odd address. */ -static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val) -{ - uae_u16 dp; - uae_s8 disp8; - uae_s16 disp16; - int r; - uae_u32 dispreg; - uaecptr addr; - uae_s32 offset = 0; - - switch (mode){ - case Dreg: - *val = m68k_dreg (regs, reg); - return 1; - case Areg: - *val = m68k_areg (regs, reg); - return 1; - - case Aind: - case Aipi: - addr = m68k_areg (regs, reg); - break; - case Apdi: - addr = m68k_areg (regs, reg); - break; - case Ad16: - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr = m68k_areg (regs, reg) + (uae_s16)disp16; - break; - case Ad8r: - addr = m68k_areg (regs, reg); -d8r_common: - dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - disp8 = dp & 0xFF; - r = (dp & 0x7000) >> 12; - dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r); - if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); - dispreg <<= (dp >> 9) & 3; - - if (dp & 0x100) { - uae_s32 outer = 0, disp = 0; - uae_s32 base = addr; - if (dp & 0x80) base = 0; - if (dp & 0x40) dispreg = 0; - if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - base += disp; - - if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; } - if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; } - - if (!(dp & 4)) base += dispreg; - if (dp & 3) base = get_long (base); - if (dp & 4) base += dispreg; - - addr = base + outer; - } else { - addr += (uae_s32)((uae_s8)disp8) + dispreg; - } - break; - case PC16: - addr = m68k_getpc () + m68kpc_offset; - disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2; - addr += (uae_s16)disp16; - break; - case PC8r: - addr = m68k_getpc () + m68kpc_offset; - goto d8r_common; - case absw: - addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - break; - case absl: - addr = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - break; - case imm: - switch (size){ - case sz_byte: - *val = get_iword_1 (m68kpc_offset) & 0xff; - m68kpc_offset += 2; - break; - case sz_word: - *val = get_iword_1 (m68kpc_offset) & 0xffff; - m68kpc_offset += 2; - break; - case sz_long: - *val = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - break; - default: - break; - } - return 1; - case imm0: - *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - return 1; - case imm1: - *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); - m68kpc_offset += 2; - return 1; - case imm2: - *val = get_ilong_1 (m68kpc_offset); - m68kpc_offset += 4; - return 1; - case immi: - *val = (uae_s32)(uae_s8)(reg & 0xff); - return 1; - default: - addr = 0; - break; - } - if ((addr & 1) == 0) - return 1; - - last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset; - last_fault_for_exception_3 = addr; - last_writeaccess_for_exception_3 = 0; - last_instructionaccess_for_exception_3 = 0; - return 0; -} -#endif - -int get_cpu_model (void) -{ - return currprefs.cpu_model; -} - -/* -* extract bitfield data from memory and return it in the MSBs -* bdata caches the unmodified data for put_bitfield() -*/ -uae_u32 REGPARAM2 get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) -{ - uae_u32 tmp, res, mask; - - offset &= 7; - mask = 0xffffffffu << (32 - width); - switch ((offset + width + 7) >> 3) { - case 1: - tmp = get_byte (src); - res = tmp << (24 + offset); - bdata[0] = tmp & ~(mask >> (24 + offset)); - break; - case 2: - tmp = get_word (src); - res = tmp << (16 + offset); - bdata[0] = tmp & ~(mask >> (16 + offset)); - break; - case 3: - tmp = get_word (src); - res = tmp << (16 + offset); - bdata[0] = tmp & ~(mask >> (16 + offset)); - tmp = get_byte (src + 2); - res |= tmp << (8 + offset); - bdata[1] = tmp & ~(mask >> (8 + offset)); - break; - case 4: - tmp = get_long (src); - res = tmp << offset; - bdata[0] = tmp & ~(mask >> offset); - break; - case 5: - tmp = get_long (src); - res = tmp << offset; - bdata[0] = tmp & ~(mask >> offset); - tmp = get_byte (src + 4); - res |= tmp >> (8 - offset); - bdata[1] = tmp & ~(mask << (8 - offset)); - break; - default: - /* Panic? */ - res = 0; - break; - } - return res; -} -/* -* write bitfield data (in the LSBs) back to memory, upper bits -* must be cleared already. -*/ -void REGPARAM2 put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) -{ - offset = (offset & 7) + width; - switch ((offset + 7) >> 3) { - case 1: - put_byte (dst, bdata[0] | (val << (8 - offset))); - break; - case 2: - put_word (dst, bdata[0] | (val << (16 - offset))); - break; - case 3: - put_word (dst, bdata[0] | (val >> (offset - 16))); - put_byte (dst + 2, bdata[1] | (val << (24 - offset))); - break; - case 4: - put_long (dst, bdata[0] | (val << (32 - offset))); - break; - case 5: - put_long (dst, bdata[0] | (val >> (offset - 32))); - put_byte (dst + 4, bdata[1] | (val << (40 - offset))); - break; - } -} - -uae_u32 REGPARAM2 x_get_bitfield (uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) -{ - uae_u32 tmp, res, mask; - - offset &= 7; - mask = 0xffffffffu << (32 - width); - switch ((offset + width + 7) >> 3) { - case 1: - tmp = x_get_byte (src); - res = tmp << (24 + offset); - bdata[0] = tmp & ~(mask >> (24 + offset)); - break; - case 2: - tmp = x_get_word (src); - res = tmp << (16 + offset); - bdata[0] = tmp & ~(mask >> (16 + offset)); - break; - case 3: - tmp = x_get_word (src); - res = tmp << (16 + offset); - bdata[0] = tmp & ~(mask >> (16 + offset)); - tmp = x_get_byte (src + 2); - res |= tmp << (8 + offset); - bdata[1] = tmp & ~(mask >> (8 + offset)); - break; - case 4: - tmp = x_get_long (src); - res = tmp << offset; - bdata[0] = tmp & ~(mask >> offset); - break; - case 5: - tmp = x_get_long (src); - res = tmp << offset; - bdata[0] = tmp & ~(mask >> offset); - tmp = x_get_byte (src + 4); - res |= tmp >> (8 - offset); - bdata[1] = tmp & ~(mask << (8 - offset)); - break; - default: - /* Panic? */ - res = 0; - break; - } - return res; -} - -void REGPARAM2 x_put_bitfield (uae_u32 dst, uae_u32 bdata[2], uae_u32 val, uae_s32 offset, int width) -{ - offset = (offset & 7) + width; - switch ((offset + 7) >> 3) { - case 1: - x_put_byte (dst, bdata[0] | (val << (8 - offset))); - break; - case 2: - x_put_word (dst, bdata[0] | (val << (16 - offset))); - break; - case 3: - x_put_word (dst, bdata[0] | (val >> (offset - 16))); - x_put_byte (dst + 2, bdata[1] | (val << (24 - offset))); - break; - case 4: - x_put_long (dst, bdata[0] | (val << (32 - offset))); - break; - case 5: - x_put_long (dst, bdata[0] | (val >> (offset - 32))); - x_put_byte (dst + 4, bdata[1] | (val << (40 - offset))); - break; - } -} - -uae_u32 REGPARAM2 get_disp_ea_020 (uae_u32 base, uae_u32 dp) -{ - int reg = (dp >> 12) & 15; - uae_s32 regd = regs.regs[reg]; - if ((dp & 0x800) == 0) - regd = (uae_s32)(uae_s16)regd; - regd <<= (dp >> 9) & 3; - if (dp & 0x100) { - uae_s32 outer = 0; - if (dp & 0x80) base = 0; - if (dp & 0x40) regd = 0; - - if ((dp & 0x30) == 0x20) - base += (uae_s32)(uae_s16) next_iword (); - if ((dp & 0x30) == 0x30) - base += next_ilong (); - - if ((dp & 0x3) == 0x2) - outer = (uae_s32)(uae_s16) next_iword (); - if ((dp & 0x3) == 0x3) - outer = next_ilong (); - - if ((dp & 0x4) == 0) - base += regd; - if (dp & 0x3) - base = get_long (base); - if (dp & 0x4) - base += regd; - - return base + outer; - } else { - return base + (uae_s32)((uae_s8)dp) + regd; - } -} - -uae_u32 REGPARAM2 x_get_disp_ea_020 (uae_u32 base, uae_u32 dp) -{ - int reg = (dp >> 12) & 15; - int cycles = 0; - uae_u32 v; - - uae_s32 regd = regs.regs[reg]; - if ((dp & 0x800) == 0) - regd = (uae_s32)(uae_s16)regd; - regd <<= (dp >> 9) & 3; - if (dp & 0x100) { - uae_s32 outer = 0; - if (dp & 0x80) - base = 0; - if (dp & 0x40) - regd = 0; - - if ((dp & 0x30) == 0x20) { - base += (uae_s32)(uae_s16) x_next_iword (); - cycles++; - } - if ((dp & 0x30) == 0x30) { - base += x_next_ilong (); - cycles++; - } - - if ((dp & 0x3) == 0x2) { - outer = (uae_s32)(uae_s16) x_next_iword (); - cycles++; - } - if ((dp & 0x3) == 0x3) { - outer = x_next_ilong (); - cycles++; - } - - if ((dp & 0x4) == 0) { - base += regd; - cycles++; - } - if (dp & 0x3) { - base = x_get_long (base); - cycles++; - } - if (dp & 0x4) { - base += regd; - cycles++; - } - v = base + outer; - } else { - v = base + (uae_s32)((uae_s8)dp) + regd; - } - if (cycles) - do_cycles_ce020 (cycles); - return v; -} - - -uae_u32 REGPARAM3 get_disp_ea_000 (uae_u32 base, uae_u32 dp) REGPARAM -{ - int reg = (dp >> 12) & 15; - uae_s32 regd = regs.regs[reg]; -#if 1 - if ((dp & 0x800) == 0) - regd = (uae_s32)(uae_s16)regd; - return base + (uae_s8)dp + regd; -#else - /* Branch-free code... benchmark this again now that - * things are no longer inline. */ - uae_s32 regd16; - uae_u32 mask; - mask = ((dp & 0x800) >> 11) - 1; - regd16 = (uae_s32)(uae_s16)regd; - regd16 &= mask; - mask = ~mask; - base += (uae_s8)dp; - regd &= mask; - regd |= regd16; - return base + regd; -#endif -} - -STATIC_INLINE int in_rom (uaecptr pc) -{ - return (munge24 (pc) & 0xFFF80000) == 0xF80000; -} - -#if AMIGA_ONLY -STATIC_INLINE int in_rtarea (uaecptr pc) -{ - return (munge24 (pc) & 0xFFFF0000) == rtarea_base && uae_boot_rom; -} -#endif - -void REGPARAM2 MakeSR (void) -{ - regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) - | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) - | (GET_XFLG () << 4) | (GET_NFLG () << 3) - | (GET_ZFLG () << 2) | (GET_VFLG () << 1) - | GET_CFLG ()); -} - -void REGPARAM2 MakeFromSR (void) -{ - int oldm = regs.m; - int olds = regs.s; - - if (currprefs.cpu_cycle_exact && currprefs.cpu_model >= 68020) { - do_cycles_ce (6 * CYCLE_UNIT); - regs.ce020memcycles = 0; - } - - SET_XFLG ((regs.sr >> 4) & 1); - SET_NFLG ((regs.sr >> 3) & 1); - SET_ZFLG ((regs.sr >> 2) & 1); - SET_VFLG ((regs.sr >> 1) & 1); - SET_CFLG (regs.sr & 1); - if (regs.t1 == ((regs.sr >> 15) & 1) && - regs.t0 == ((regs.sr >> 14) & 1) && - regs.s == ((regs.sr >> 13) & 1) && - regs.m == ((regs.sr >> 12) & 1) && - regs.intmask == ((regs.sr >> 8) & 7)) - return; - regs.t1 = (regs.sr >> 15) & 1; - regs.t0 = (regs.sr >> 14) & 1; - regs.s = (regs.sr >> 13) & 1; - regs.m = (regs.sr >> 12) & 1; - regs.intmask = (regs.sr >> 8) & 7; - if (currprefs.cpu_model >= 68020) { - /* 68060 does not have MSP but does have M-bit.. */ - if (currprefs.cpu_model >= 68060) - regs.msp = regs.isp; - if (olds != regs.s) { - if (olds) { - if (oldm) - regs.msp = m68k_areg (regs, 7); - else - regs.isp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.usp; - } else { - regs.usp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp; - } - } else if (olds && oldm != regs.m) { - if (oldm) { - regs.msp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.isp; - } else { - regs.isp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.msp; - } - } - if (currprefs.cpu_model >= 68060) - regs.t0 = 0; - } else { - regs.t0 = regs.m = 0; - if (olds != regs.s) { - if (olds) { - regs.isp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.usp; - } else { - regs.usp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.isp; - } - } - } - if (currprefs.mmu_model) - mmu_set_super (regs.s != 0); - - doint (); - if (regs.t1 || regs.t0) - set_special (SPCFLAG_TRACE); - else - /* Keep SPCFLAG_DOTRACE, we still want a trace exception for - SR-modifying instructions (including STOP). */ - unset_special (SPCFLAG_TRACE); -} - -static void exception_trace (int nr) -{ - unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); - if (regs.t1 && !regs.t0) { - /* trace stays pending if exception is div by zero, chk, - * trapv or trap #x - */ - if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47)) - set_special (SPCFLAG_DOTRACE); - } - regs.t1 = regs.t0 = regs.m = 0; -} - -static void exception_debug (int nr) -{ -#ifdef DEBUGGER - if (!exception_debugging) - return; - console_out_f ("Exception %d, PC=%08X\n", nr, M68K_GETPC); -#endif -} - -#ifdef CPUEMU_12 - -/* cycle-exact exception handler, 68000 only */ - -/* - -Address/Bus Error: - -- 6 idle cycles -- write PC low word -- write SR -- write PC high word -- write instruction word -- write fault address low word -- write status code -- write fault address high word -- 2 idle cycles -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -Division by Zero: - -- 6 idle cycles -- write PC low word -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -Traps: - -- 2 idle cycles -- write PC low word -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -TrapV: - -- write PC low word -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -CHK: - -- 6 idle cycles -- write PC low word -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -Illegal Instruction: - -- 2 idle cycles -- write PC low word -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -Interrupt cycle diagram: - -- 6 idle cycles -- write PC low word -- read exception number byte from (0xfffff1 | (interrupt number << 1)) -- 4 idle cycles -- write SR -- write PC high word -- read exception address high word -- read exception address low word -- prefetch -- 2 idle cycles -- prefetch - -*/ - -static void Exception_ce000 (int nr, uaecptr oldpc) -{ - uae_u32 currpc = m68k_getpc (), newpc; - int sv = regs.s; - int start, interrupt; - - start = 6; - if (nr == 7) // TRAPV - start = 0; - else if (nr >= 32 && nr < 32 + 16) // TRAP #x - start = 2; - else if (nr == 4 || nr == 8) // ILLG & PRIVIL VIOL - start = 2; - interrupt = nr >= 24 && nr < 24 + 8; - - if (start) - do_cycles_ce000 (start); - - exception_debug (nr); - MakeSR (); - - if (!regs.s) { - regs.usp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.isp; - regs.s = 1; - } - if (nr == 2 || nr == 3) { /* 2=bus error, 3=address error */ - uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); - mode |= last_writeaccess_for_exception_3 ? 0 : 16; - m68k_areg (regs, 7) -= 14; - /* fixme: bit3=I/N */ - put_word_ce (m68k_areg (regs, 7) + 12, last_addr_for_exception_3); - put_word_ce (m68k_areg (regs, 7) + 8, regs.sr); - put_word_ce (m68k_areg (regs, 7) + 10, last_addr_for_exception_3 >> 16); - put_word_ce (m68k_areg (regs, 7) + 6, last_op_for_exception_3); - put_word_ce (m68k_areg (regs, 7) + 4, last_fault_for_exception_3); - put_word_ce (m68k_areg (regs, 7) + 0, mode); - put_word_ce (m68k_areg (regs, 7) + 2, last_fault_for_exception_3 >> 16); - do_cycles_ce000 (2); - write_log ("Exception %d (%x) at %x -> %x!\n", nr, oldpc, currpc, get_long (4 * nr)); - goto kludge_me_do; - } - m68k_areg (regs, 7) -= 6; - put_word_ce (m68k_areg (regs, 7) + 4, currpc); // write low address - if (interrupt) { - // fetch interrupt vector number - nr = get_byte_ce (0x00fffff1 | ((nr - 24) << 1)); - do_cycles_ce000 (4); - } - put_word_ce (m68k_areg (regs, 7) + 0, regs.sr); // write SR - put_word_ce (m68k_areg (regs, 7) + 2, currpc >> 16); // write high address -kludge_me_do: - newpc = get_word_ce (4 * nr) << 16; // read high address - newpc |= get_word_ce (4 * nr + 2); // read low address - if (newpc & 1) { - if (nr == 2 || nr == 3) - Reset_Cold(); /* there is nothing else we can do.. */ - else - exception3 (regs.ir, m68k_getpc (), newpc); - return; - } - m68k_setpc (newpc); - regs.ir = get_word_ce (m68k_getpc ()); // prefetch 1 - do_cycles_ce000 (2); - regs.irc = get_word_ce (m68k_getpc () + 2); // prefetch 2 -#ifdef JIT - set_special (SPCFLAG_END_COMPILE); -#endif - exception_trace (nr); -} -#endif - -static void Exception_mmu (int nr, uaecptr oldpc) -{ - uae_u32 currpc = m68k_getpc (), newpc; - int sv = regs.s; - int i; - - exception_debug (nr); - MakeSR (); - - if (!regs.s) { - regs.usp = m68k_areg (regs, 7); - if (currprefs.cpu_model >= 68020) - m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp; - else - m68k_areg (regs, 7) = regs.isp; - regs.s = 1; - mmu_set_super (1); - } - if (nr == 2) { -// write_log ("%08x %08x %08x\n", currpc, oldpc, regs.mmu_fault_addr); -// if (currpc == 0x0013b5e2) -// activate_debugger (); - // bus error - for (i = 0 ; i < 7 ; i++) { - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), 0); - } - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), regs.wb3_data); - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), regs.mmu_fault_addr); - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), regs.mmu_fault_addr); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), regs.wb3_status); - regs.wb3_status = 0; - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), regs.mmu_ssw); - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), regs.mmu_fault_addr); - - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0x7000 + nr * 4); - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), oldpc); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), regs.sr); - goto kludge_me_do; - - } else if (nr == 3) { - - // address error - uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); - ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40; - ssw |= 0x20; - for (i = 0 ; i < 36; i++) { - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - } - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), last_fault_for_exception_3); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), ssw); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0xb000 + nr * 4); - write_log ("Exception %d (%x) at %x -> %x!\n", nr, oldpc, currpc, get_long (regs.vbr + 4*nr)); - - } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { - - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), oldpc); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0x2000 + nr * 4); - - } else if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */ - - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), nr * 4); - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), currpc); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), regs.sr); - regs.sr |= (1 << 13); - regs.msp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.isp; - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), 0x1000 + nr * 4); - - } else { - - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), nr * 4); - - } - m68k_areg (regs, 7) -= 4; - put_long_mmu (m68k_areg (regs, 7), currpc); - m68k_areg (regs, 7) -= 2; - put_word_mmu (m68k_areg (regs, 7), regs.sr); -kludge_me_do: - newpc = get_long_mmu (regs.vbr + 4 * nr); - if (newpc & 1) { - if (nr == 2 || nr == 3) - Reset_Cold(); /* there is nothing else we can do.. */ - else - exception3 (regs.ir, m68k_getpc (), newpc); - return; - } - m68k_setpc (newpc); -#ifdef JIT - set_special (SPCFLAG_END_COMPILE); -#endif - fill_prefetch_slow (); - exception_trace (nr); -} - -/* Handle exceptions. We need a special case to handle MFP exceptions */ -/* on Atari ST, because it's possible to change the MFP's vector base */ -/* and get a conflict with 'normal' cpu exceptions. */ -static void Exception_normal (int nr, uaecptr oldpc, int ExceptionSource) -{ - uae_u32 currpc = m68k_getpc (), newpc; - int sv = regs.s; - - -#if AMIGA_ONLY - if (nr >= 24 && nr < 24 + 8 && currprefs.cpu_model <= 68010) - nr = x_get_byte (0x00fffff1 | (nr << 1)); -#endif - - exception_debug (nr); - MakeSR (); - - /* Change to supervisor mode if necessary */ - if (!regs.s) { - regs.usp = m68k_areg (regs, 7); - if (currprefs.cpu_model >= 68020) - m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp; - else - m68k_areg (regs, 7) = regs.isp; - regs.s = 1; - if (currprefs.mmu_model) - mmu_set_super (regs.s != 0); - } - if (currprefs.cpu_model > 68000) { - /* Build additional exception stack frame for 68010 and higher */ - /* (special case for MFP) */ - - if (nr == 2 || nr == 3) { - int i; - if (currprefs.cpu_model >= 68040) { - if (nr == 2) { - // bus error - if (currprefs.mmu_model) { - - for (i = 0 ; i < 7 ; i++) { - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), 0); - } - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), regs.wb3_data); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.wb3_status); - regs.wb3_status = 0; - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.mmu_ssw); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); - - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x7000 + nr * 4); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), oldpc); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.sr); - newpc = x_get_long (regs.vbr + 4 * nr); - if (newpc & 1) { - if (nr == 2 || nr == 3) - uae_reset (1); /* there is nothing else we can do.. */ - else - exception3 (regs.ir, m68k_getpc (), newpc); - return; - } - m68k_setpc (newpc); -#ifdef JIT - set_special (SPCFLAG_END_COMPILE); -#endif - exception_trace (nr); - return; - - } else { - - for (i = 0 ; i < 18 ; i++) { - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - } - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x0140 | (sv ? 6 : 2)); /* SSW */ - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), last_addr_for_exception_3); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x7000 + nr * 4); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), oldpc); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.sr); - goto kludge_me_do; - - } - - } else { - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x2000 + nr * 4); - } - } else { - // address error - uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); - ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40; - ssw |= 0x20; - for (i = 0 ; i < 36; i++) { - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - } - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), last_fault_for_exception_3); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), ssw); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0xb000 + nr * 4); - } - write_log ("Exception %d (%x) at %x -> %x!\n", nr, oldpc, currpc, x_get_long (regs.vbr + 4*nr)); - } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) { - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), oldpc); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x2000 + nr * 4); - } else if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */ - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), nr * 4); - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), currpc); - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.sr); - regs.sr |= (1 << 13); - regs.msp = m68k_areg (regs, 7); - m68k_areg (regs, 7) = regs.isp; - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), 0x1000 + nr * 4); - } else { - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), nr * 4); - } - } else if (nr == 2 || nr == 3) { - uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1); - mode |= last_writeaccess_for_exception_3 ? 0 : 16; - m68k_areg (regs, 7) -= 14; - /* fixme: bit3=I/N */ - x_put_word (m68k_areg (regs, 7) + 0, mode); - x_put_long (m68k_areg (regs, 7) + 2, last_fault_for_exception_3); - x_put_word (m68k_areg (regs, 7) + 6, last_op_for_exception_3); - x_put_word (m68k_areg (regs, 7) + 8, regs.sr); - x_put_long (m68k_areg (regs, 7) + 10, last_addr_for_exception_3); - write_log ("Exception %d (%x) at %x -> %x!\n", nr, oldpc, currpc, x_get_long (regs.vbr + 4*nr)); - goto kludge_me_do; - } - - /* Push PC on stack: */ - m68k_areg (regs, 7) -= 4; - x_put_long (m68k_areg (regs, 7), currpc); - /* Push SR on stack: */ - m68k_areg (regs, 7) -= 2; - x_put_word (m68k_areg (regs, 7), regs.sr); -kludge_me_do: - newpc = x_get_long (regs.vbr + 4 * nr); - if (newpc & 1) { - if (nr == 2 || nr == 3) - uae_reset (1); /* there is nothing else we can do.. */ - else - exception3 (regs.ir, m68k_getpc (), newpc); - return; - } - m68k_setpc (newpc); -#ifdef JIT - set_special (SPCFLAG_END_COMPILE); -#endif - fill_prefetch_slow (); - exception_trace (nr); - - /* Handle exception cycles (special case for MFP) */ - if (ExceptionSource == M68000_EXC_SRC_INT_MFP) - { - M68000_AddCycles(44+12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */ - } - else if (nr >= 24 && nr <= 31) - { - if ( nr == 26 ) /* HBL */ - { - /* store current cycle pos when then interrupt was received (see video.c) */ - // LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO); - M68000_AddCycles(44+12); /* Video Interrupt */ - } - else if ( nr == 28 ) /* VBL */ - M68000_AddCycles(44+12); /* Video Interrupt */ - else - M68000_AddCycles(44+4); /* Other Interrupts */ - } - else if(nr >= 32 && nr <= 47) - { - M68000_AddCycles(34-4); /* Trap (total is 34, but cpuemu.c already adds 4) */ - } - else switch(nr) - { - case 2: M68000_AddCycles(50); break; /* Bus error */ - case 3: M68000_AddCycles(50); break; /* Address error */ - case 4: M68000_AddCycles(34); break; /* Illegal instruction */ - case 5: M68000_AddCycles(38); break; /* Div by zero */ - case 6: M68000_AddCycles(40); break; /* CHK */ - case 7: M68000_AddCycles(34); break; /* TRAPV */ - case 8: M68000_AddCycles(34); break; /* Privilege violation */ - case 9: M68000_AddCycles(34); break; /* Trace */ - case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */ - case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */ - default: - /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */ - if(nr < 64) - M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */ - else - M68000_AddCycles(44+12); /* Must be a MFP or DSP interrupt */ - break; - } - -} - -/* Handle exceptions. We need a special case to handle MFP exceptions */ -/* on Atari ST, because it's possible to change the MFP's vector base */ -/* and get a conflict with 'normal' cpu exceptions. */ -void REGPARAM2 Exception (int nr, uaecptr oldpc, int ExceptionSource) -{ -#ifdef CPUEMU_12 - if (currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000) - Exception_ce000 (nr, oldpc); - else -#endif - if (currprefs.mmu_model) - Exception_mmu (nr, oldpc); // Todo: add ExceptionSource - else - Exception_normal (nr, oldpc, ExceptionSource); - -#if AMIGA_ONLY - if (debug_illegal && !in_rom (M68K_GETPC)) { - int v = nr; - if (nr <= 63 && (debug_illegal_mask & ((uae_u64)1 << nr))) { - write_log ("Exception %d breakpoint\n", nr); - activate_debugger (); - } - } -#endif -} - -STATIC_INLINE void do_interrupt (int nr, int Pending) -{ -#if AMIGA_ONLY - if (debug_dma) - record_dma_event (DMA_EVENT_CPUIRQ, current_hpos (), vpos); -#endif - - regs.stopped = 0; - unset_special (SPCFLAG_STOP); - assert (nr < 8 && nr >= 0); - - /* On Hatari, only video ints are using SPCFLAG_INT (see m68000.c) */ - Exception (nr + 24, 0, M68000_EXC_SRC_AUTOVEC); - - regs.intmask = nr; - doint (); - - set_special (SPCFLAG_INT); - /* Handle Atari ST's specific jitter for hbl/vbl */ - InterruptAddJitter (nr , Pending); -} - - -void NMI (void) -{ - do_interrupt (7, false); -} - -#ifndef CPUEMU_68000_ONLY - -int movec_illg (int regno) -{ - int regno2 = regno & 0x7ff; - - if (currprefs.cpu_model == 68060) { - if (regno <= 8) - return 0; - if (regno == 0x800 || regno == 0x801 || - regno == 0x806 || regno == 0x807 || regno == 0x808) - return 0; - return 1; - } else if (currprefs.cpu_model == 68010) { - if (regno2 < 2) - return 0; - return 1; - } else if (currprefs.cpu_model == 68020) { - if (regno == 3) - return 1; /* 68040/060 only */ - /* 4 is >=68040, but 0x804 is in 68020 */ - if (regno2 < 4 || regno == 0x804) - return 0; - return 1; - } else if (currprefs.cpu_model == 68030) { - if (regno2 <= 2) - return 0; - if (regno == 0x803 || regno == 0x804) - return 0; - return 1; - } else if (currprefs.cpu_model == 68040) { - if (regno == 0x802) - return 1; /* 68020 only */ - if (regno2 < 8) return 0; - return 1; - } - return 1; -} - -int m68k_move2c (int regno, uae_u32 *regp) -{ -#if MOVEC_DEBUG > 0 - write_log ("move2c %04X <- %08X PC=%x\n", regno, *regp, M68K_GETPC); -#endif - if (movec_illg (regno)) { - op_illg (0x4E7B); - return 0; - } else { - switch (regno) { - case 0: regs.sfc = *regp & 7; break; - case 1: regs.dfc = *regp & 7; break; - case 2: - { - uae_u32 cacr_mask = 0; - if (currprefs.cpu_model == 68020) - cacr_mask = 0x0000000f; - else if (currprefs.cpu_model == 68030) - cacr_mask = 0x00003f1f; - else if (currprefs.cpu_model == 68040) - cacr_mask = 0x80008000; - else if (currprefs.cpu_model == 68060) - cacr_mask = 0xf8e0e000; - regs.cacr = *regp & cacr_mask; - set_cpu_caches (); - } - break; - /* 68040/060 only */ - case 3: - regs.tcr = *regp & (currprefs.cpu_model == 68060 ? 0xfffe : 0xc000); - if (currprefs.mmu_model) - mmu_set_tc (regs.tcr); - break; - - /* no differences between 68040 and 68060 */ - case 4: regs.itt0 = *regp & 0xffffe364; break; - case 5: regs.itt1 = *regp & 0xffffe364; break; - case 6: regs.dtt0 = *regp & 0xffffe364; break; - case 7: regs.dtt1 = *regp & 0xffffe364; break; - /* 68060 only */ - case 8: regs.buscr = *regp & 0xf0000000; break; - - case 0x800: regs.usp = *regp; break; - case 0x801: regs.vbr = *regp; break; - case 0x802: regs.caar = *regp & 0xfc; break; - case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg (regs, 7) = regs.msp; break; - case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg (regs, 7) = regs.isp; break; - /* 68040 only */ - case 0x805: regs.mmusr = *regp; break; - /* 68040/060 */ - case 0x806: regs.urp = *regp & 0xfffffe00; break; - case 0x807: regs.srp = *regp & 0xfffffe00; break; - /* 68060 only */ - case 0x808: - { - uae_u32 opcr = regs.pcr; - regs.pcr &= ~(0x40 | 2 | 1); - regs.pcr |= (*regp) & (0x40 | 2 | 1); - if (((opcr ^ regs.pcr) & 2) == 2) { - write_log ("68060 FPU state: %s\n", regs.pcr & 2 ? "disabled" : "enabled"); - /* flush possible already translated FPU instructions */ - flush_icache (0, 3); - } - } - break; - default: - op_illg (0x4E7B); - return 0; - } - } - return 1; -} - -int m68k_movec2 (int regno, uae_u32 *regp) -{ -#if MOVEC_DEBUG > 0 - write_log ("movec2 %04X PC=%x\n", regno, M68K_GETPC); -#endif - if (movec_illg (regno)) { - op_illg (0x4E7A); - return 0; - } else { - switch (regno) { - case 0: *regp = regs.sfc; break; - case 1: *regp = regs.dfc; break; - case 2: - { - uae_u32 v = regs.cacr; - uae_u32 cacr_mask = 0; - if (currprefs.cpu_model == 68020) - cacr_mask = 0x00000003; - else if (currprefs.cpu_model == 68030) - cacr_mask = 0x00003313; - else if (currprefs.cpu_model == 68040) - cacr_mask = 0x80008000; - else if (currprefs.cpu_model == 68060) - cacr_mask = 0xf880e000; - *regp = v & cacr_mask; - } - break; - case 3: *regp = regs.tcr; break; - case 4: *regp = regs.itt0; break; - case 5: *regp = regs.itt1; break; - case 6: *regp = regs.dtt0; break; - case 7: *regp = regs.dtt1; break; - case 8: *regp = regs.buscr; break; - - case 0x800: *regp = regs.usp; break; - case 0x801: *regp = regs.vbr; break; - case 0x802: *regp = regs.caar; break; - case 0x803: *regp = regs.m == 1 ? m68k_areg (regs, 7) : regs.msp; break; - case 0x804: *regp = regs.m == 0 ? m68k_areg (regs, 7) : regs.isp; break; - case 0x805: *regp = regs.mmusr; break; - case 0x806: *regp = regs.urp; break; - case 0x807: *regp = regs.srp; break; - case 0x808: *regp = regs.pcr; break; - - default: - op_illg (0x4E7A); - return 0; - } - } -#if MOVEC_DEBUG > 0 - write_log ("-> %08X\n", *regp); -#endif - return 1; -} - -STATIC_INLINE int div_unsigned (uae_u32 src_hi, uae_u32 src_lo, uae_u32 div, uae_u32 *quot, uae_u32 *rem) -{ - uae_u32 q = 0, cbit = 0; - int i; - - if (div <= src_hi) { - return 1; - } - for (i = 0 ; i < 32 ; i++) { - cbit = src_hi & 0x80000000ul; - src_hi <<= 1; - if (src_lo & 0x80000000ul) src_hi++; - src_lo <<= 1; - q = q << 1; - if (cbit || div <= src_hi) { - q |= 1; - src_hi -= div; - } - } - *quot = q; - *rem = src_hi; - return 0; -} - -void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc) -{ -#if defined (uae_s64) - if (src == 0) { - Exception (5, oldpc, M68000_EXC_SRC_CPU); - return; - } - if (extra & 0x800) { - /* signed variant */ - uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - uae_s64 quot, rem; - - if (extra & 0x400) { - a &= 0xffffffffu; - a |= (uae_s64)m68k_dreg (regs, extra & 7) << 32; - } - rem = a % (uae_s64)(uae_s32)src; - quot = a / (uae_s64)(uae_s32)src; - if ((quot & UVAL64 (0xffffffff80000000)) != 0 - && (quot & UVAL64 (0xffffffff80000000)) != UVAL64 (0xffffffff80000000)) - { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = (uae_u32)rem; - m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)quot; - } - } else { - /* unsigned */ - uae_u64 a = (uae_u64)(uae_u32)m68k_dreg (regs, (extra >> 12) & 7); - uae_u64 quot, rem; - - if (extra & 0x400) { - a &= 0xffffffffu; - a |= (uae_u64)m68k_dreg (regs, extra & 7) << 32; - } - rem = a % (uae_u64)src; - quot = a / (uae_u64)src; - if (quot > 0xffffffffu) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = (uae_u32)rem; - m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)quot; - } - } -#else - if (src == 0) { - Exception (5, oldpc, M68000_EXC_SRC_CPU); - return; - } - if (extra & 0x800) { - /* signed variant */ - uae_s32 lo = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - uae_s32 hi = lo < 0 ? -1 : 0; - uae_s32 save_high; - uae_u32 quot, rem; - uae_u32 sign; - - if (extra & 0x400) { - hi = (uae_s32)m68k_dreg (regs, extra & 7); - } - save_high = hi; - sign = (hi ^ src); - if (hi < 0) { - hi = ~hi; - lo = -lo; - if (lo == 0) hi++; - } - if ((uae_s32)src < 0) src = -src; - if (div_unsigned (hi, lo, src, ", &rem) || - (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - if (sign & 0x80000000) quot = -quot; - if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = rem; - m68k_dreg (regs, (extra >> 12) & 7) = quot; - } - } else { - /* unsigned */ - uae_u32 lo = (uae_u32)m68k_dreg (regs, (extra >> 12) & 7); - uae_u32 hi = 0; - uae_u32 quot, rem; - - if (extra & 0x400) { - hi = (uae_u32)m68k_dreg (regs, extra & 7); - } - if (div_unsigned (hi, lo, src, ", &rem)) { - SET_VFLG (1); - SET_NFLG (1); - SET_CFLG (0); - } else { - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (((uae_s32)quot) == 0); - SET_NFLG (((uae_s32)quot) < 0); - m68k_dreg (regs, extra & 7) = rem; - m68k_dreg (regs, (extra >> 12) & 7) = quot; - } - } -#endif -} - -STATIC_INLINE void mul_unsigned (uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo) -{ - uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff); - uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff); - uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff); - uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff); - uae_u32 lo; - - lo = r0 + ((r1 << 16) & 0xffff0000ul); - if (lo < r0) r3++; - r0 = lo; - lo = r0 + ((r2 << 16) & 0xffff0000ul); - if (lo < r0) r3++; - r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff); - *dst_lo = lo; - *dst_hi = r3; -} - -void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra) -{ -#if defined (uae_s64) - if (extra & 0x800) { - /* signed variant */ - uae_s64 a = (uae_s64)(uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - - a *= (uae_s64)(uae_s32)src; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (a == 0); - SET_NFLG (a < 0); - if (extra & 0x400) - m68k_dreg (regs, extra & 7) = (uae_u32)(a >> 32); - else if ((a & UVAL64 (0xffffffff80000000)) != 0 - && (a & UVAL64 (0xffffffff80000000)) != UVAL64 (0xffffffff80000000)) - { - SET_VFLG (1); - } - m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)a; - } else { - /* unsigned */ - uae_u64 a = (uae_u64)(uae_u32)m68k_dreg (regs, (extra >> 12) & 7); - - a *= (uae_u64)src; - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (a == 0); - SET_NFLG (((uae_s64)a) < 0); - if (extra & 0x400) - m68k_dreg (regs, extra & 7) = (uae_u32)(a >> 32); - else if ((a & UVAL64 (0xffffffff00000000)) != 0) { - SET_VFLG (1); - } - m68k_dreg (regs, (extra >> 12) & 7) = (uae_u32)a; - } -#else - if (extra & 0x800) { - /* signed variant */ - uae_s32 src1, src2; - uae_u32 dst_lo, dst_hi; - uae_u32 sign; - - src1 = (uae_s32)src; - src2 = (uae_s32)m68k_dreg (regs, (extra >> 12) & 7); - sign = (src1 ^ src2); - if (src1 < 0) src1 = -src1; - if (src2 < 0) src2 = -src2; - mul_unsigned ((uae_u32)src1, (uae_u32)src2, &dst_hi, &dst_lo); - if (sign & 0x80000000) { - dst_hi = ~dst_hi; - dst_lo = -dst_lo; - if (dst_lo == 0) dst_hi++; - } - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (dst_hi == 0 && dst_lo == 0); - SET_NFLG (((uae_s32)dst_hi) < 0); - if (extra & 0x400) - m68k_dreg (regs, extra & 7) = dst_hi; - else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) - && ((dst_hi & 0xffffffff) != 0xffffffff - || (dst_lo & 0x80000000) != 0x80000000)) - { - SET_VFLG (1); - } - m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; - } else { - /* unsigned */ - uae_u32 dst_lo, dst_hi; - - mul_unsigned (src, (uae_u32)m68k_dreg (regs, (extra >> 12) & 7), &dst_hi, &dst_lo); - - SET_VFLG (0); - SET_CFLG (0); - SET_ZFLG (dst_hi == 0 && dst_lo == 0); - SET_NFLG (((uae_s32)dst_hi) < 0); - if (extra & 0x400) - m68k_dreg (regs, extra & 7) = dst_hi; - else if (dst_hi != 0) { - SET_VFLG (1); - } - m68k_dreg (regs, (extra >> 12) & 7) = dst_lo; - } -#endif -} - -#endif - -void m68k_reset (int hardreset) -{ - regs.spcflags = 0; - regs.ipl = regs.ipl_pin = 0; -#ifdef SAVESTATE - if (savestate_state == STATE_RESTORE || savestate_state == STATE_REWIND) { - m68k_setpc (regs.pc); - SET_XFLG ((regs.sr >> 4) & 1); - SET_NFLG ((regs.sr >> 3) & 1); - SET_ZFLG ((regs.sr >> 2) & 1); - SET_VFLG ((regs.sr >> 1) & 1); - SET_CFLG (regs.sr & 1); - regs.t1 = (regs.sr >> 15) & 1; - regs.t0 = (regs.sr >> 14) & 1; - regs.s = (regs.sr >> 13) & 1; - regs.m = (regs.sr >> 12) & 1; - regs.intmask = (regs.sr >> 8) & 7; - /* set stack pointer */ - if (regs.s) - m68k_areg (regs, 7) = regs.isp; - else - m68k_areg (regs, 7) = regs.usp; - return; - } -#endif - regs.s = 1; - regs.m = 0; - regs.stopped = 0; - regs.t1 = 0; - regs.t0 = 0; - SET_ZFLG (0); - SET_XFLG (0); - SET_CFLG (0); - SET_VFLG (0); - SET_NFLG (0); - regs.intmask = 7; - regs.vbr = regs.sfc = regs.dfc = 0; - regs.irc = 0xffff; - - m68k_areg (regs, 7) = get_long (0); - m68k_setpc (get_long (4)); - -#ifdef FPUEMU - fpu_reset (); -#endif - regs.caar = regs.cacr = 0; - regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0; - regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0; - if (currprefs.cpu_model == 68020) { - regs.cacr |= 8; - set_cpu_caches (); - } - - mmufixup[0].reg = -1; - mmufixup[1].reg = -1; - if (currprefs.mmu_model) { - mmu_reset (); - mmu_set_tc (regs.tcr); - mmu_set_super (regs.s != 0); - } - -#if AMIGA_ONLY - a3000_fakekick (0); -#endif - /* only (E)nable bit is zeroed when CPU is reset, A3000 SuperKickstart expects this */ - tc_030 &= ~0x80000000; - tt0_030 &= ~0x80000000; - tt1_030 &= ~0x80000000; - if (hardreset) { - srp_030 = crp_030 = 0; - tt0_030 = tt1_030 = tc_030 = 0; - } - mmusr_030 = 0; - - /* 68060 FPU is not compatible with 68040, - * 68060 accelerators' boot ROM disables the FPU - */ - regs.pcr = 0; - if (currprefs.cpu_model == 68060) { - regs.pcr = currprefs.fpu_model == 68060 ? MC68060_PCR : MC68EC060_PCR; - regs.pcr |= (currprefs.cpu060_revision & 0xff) << 8; - if (kickstart_rom) - regs.pcr |= 2; /* disable FPU */ - } - fill_prefetch_slow (); -} - -unsigned long REGPARAM2 op_illg (uae_u32 opcode) -{ - uaecptr pc = m68k_getpc (); - static int warned; - -#if AMIGA_ONLY - int inrom = in_rom (pc); - int inrt = in_rtarea (pc); - - if (cloanto_rom && (opcode & 0xF100) == 0x7100) { - m68k_dreg (regs, (opcode >> 9) & 7) = (uae_s8)(opcode & 0xFF); - m68k_incpc (2); - fill_prefetch_slow (); - return 4; - } - - if (opcode == 0x4E7B && inrom && get_long (0x10) == 0) { - notify_user (NUMSG_KS68020); - uae_restart (-1, NULL); - } -#endif - -#ifdef AUTOCONFIG - if (opcode == 0xFF0D) { - if (inrom) { - /* This is from the dummy Kickstart replacement */ - uae_u16 arg = get_iword (2); - m68k_incpc (4); - ersatz_perform (arg); - fill_prefetch_slow (); - return 4; - } else if (inrt) { - /* User-mode STOP replacement */ - m68k_setstopped (); - return 4; - } - } - - if ((opcode & 0xF000) == 0xA000 && inrt) { - /* Calltrap. */ - m68k_incpc (2); - m68k_handle_trap (opcode & 0xFFF); - fill_prefetch_slow (); - return 4; - } -#endif - - if ((opcode & 0xF000) == 0xF000) { - if (warned < 20) { - write_log ("B-Trap %x at %x (%p)\n", opcode, pc, regs.pc_p); - warned++; - } - Exception (0xB, 0, M68000_EXC_SRC_CPU); - //activate_debugger (); - return 4; - } - if ((opcode & 0xF000) == 0xA000) { - if (warned < 20) { - write_log ("A-Trap %x at %x (%p)\n", opcode, pc, regs.pc_p); - warned++; - } - Exception (0xA, 0, M68000_EXC_SRC_CPU); - //activate_debugger(); - return 4; - } - if (warned < 20) { - write_log ("Illegal instruction: %04x at %08X -> %08X\n", opcode, pc, get_long (regs.vbr + 0x10)); - warned++; - //activate_debugger(); - } - - Exception (4, 0, M68000_EXC_SRC_CPU); - return 4; -} - -#ifdef CPUEMU_0 - -static const TCHAR *mmu30regs[] = { "TCR", "", "SRP", "CRP", "", "", "", "" }; - -static void mmu_op30_pmove (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra) -{ - int preg = (next >> 10) & 31; - int rw = (next >> 9) & 1; - int fd = (next >> 8) & 1; - const TCHAR *reg = NULL; - uae_u32 otc = tc_030; - int siz; - - switch (preg) - { - case 0x10: // TC - reg = "TC"; - siz = 4; - if (rw) - x_put_long (extra, tc_030); - else - tc_030 = x_get_long (extra); - break; - case 0x12: // SRP - reg = "SRP"; - siz = 8; - if (rw) { - x_put_long (extra, srp_030 >> 32); - x_put_long (extra + 4, srp_030); - } else { - srp_030 = (uae_u64)x_get_long (extra) << 32; - srp_030 |= x_get_long (extra + 4); - } - break; - case 0x13: // CRP - reg = "CRP"; - siz = 8; - if (rw) { - x_put_long (extra, crp_030 >> 32); - x_put_long (extra + 4, crp_030); - } else { - crp_030 = (uae_u64)x_get_long (extra) << 32; - crp_030 |= x_get_long (extra + 4); - } - break; - case 0x18: // MMUSR - reg = "MMUSR"; - siz = 2; - if (rw) - x_put_word (extra, mmusr_030); - else - mmusr_030 = x_get_word (extra); - break; - case 0x02: // TT0 - reg = "TT0"; - siz = 4; - if (rw) - x_put_long (extra, tt0_030); - else - tt0_030 = x_get_long (extra); - break; - case 0x03: // TT1 - reg = "TT1"; - siz = 4; - if (rw) - x_put_long (extra, tt1_030); - else - tt1_030 = x_get_long (extra); - break; - } - - if (!reg) { - op_illg (opcode); - return; - } -#if MMUOP_DEBUG > 0 - { - uae_u32 val; - if (siz == 8) { - uae_u32 val2 = x_get_long (extra); - val = x_get_long (extra + 4); - if (rw) - write_log ("PMOVE %s,%08X%08X", reg, val2, val); - else - write_log ("PMOVE %08X%08X,%s", val2, val, reg); - } else { - if (siz == 4) - val = x_get_long (extra); - else - val = x_get_word (extra); - if (rw) - write_log ("PMOVE %s,%08X", reg, val); - else - write_log ("PMOVE %08X,%s", val, reg); - } - write_log (" PC=%08X\n", pc); - } -#endif - if (currprefs.cs_mbdmac == 1 && currprefs.mbresmem_low_size > 0) { - if (otc != tc_030) { -#if AMIGA_ONLY - a3000_fakekick (tc_030 & 0x80000000); -#endif - } - } -} - -static void mmu_op30_ptest (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra) -{ -#if MMUOP_DEBUG > 0 - TCHAR tmp[10]; - - tmp[0] = 0; - if ((next >> 8) & 1) - _stprintf (tmp, ",A%d", (next >> 4) & 15); - write_log ("PTEST%c %02X,%08X,#%X%s PC=%08X\n", - ((next >> 9) & 1) ? 'W' : 'R', (next & 15), extra, (next >> 10) & 7, tmp, pc); -#endif - mmusr_030 = 0; -} - -static void mmu_op30_pflush (uaecptr pc, uae_u32 opcode, uae_u16 next, uaecptr extra) -{ -#if MMUOP_DEBUG > 0 - write_log ("PFLUSH PC=%08X\n", pc); -#endif -} - -void mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa) -{ - if (currprefs.cpu_model != 68030) { - m68k_setpc (pc); - op_illg (opcode); - return; - } - if (extra & 0x8000) - mmu_op30_ptest (pc, opcode, extra, extraa); - else if (extra & 0x2000) - mmu_op30_pflush (pc, opcode, extra, extraa); - else - mmu_op30_pmove (pc, opcode, extra, extraa); -} - -void mmu_op (uae_u32 opcode, uae_u32 extra) -{ - if (currprefs.cpu_model) { - mmu_op_real (opcode, extra); - return; - } -#if MMUOP_DEBUG > 1 - write_log ("mmu_op %04X PC=%08X\n", opcode, m68k_getpc ()); -#endif - if ((opcode & 0xFE0) == 0x0500) { - /* PFLUSH */ - regs.mmusr = 0; -#if MMUOP_DEBUG > 0 - write_log ("PFLUSH\n"); -#endif - return; - } else if ((opcode & 0x0FD8) == 0x548) { - if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */ - /* PTEST */ -#if MMUOP_DEBUG > 0 - write_log ("PTEST\n"); -#endif - return; - } - } else if ((opcode & 0x0FB8) == 0x588) { - /* PLPA */ - if (currprefs.cpu_model == 68060) { -#if MMUOP_DEBUG > 0 - write_log ("PLPA\n"); -#endif - return; - } - } -#if MMUOP_DEBUG > 0 - write_log ("Unknown MMU OP %04X\n", opcode); -#endif - m68k_setpc (m68k_getpc () - 2); - op_illg (opcode); -} - -#endif - -static uaecptr last_trace_ad = 0; - -static void do_trace (void) -{ - if (regs.t0 && currprefs.cpu_model >= 68020) { - uae_u16 opcode; - /* should also include TRAP, CHK, SR modification FPcc */ - /* probably never used so why bother */ - /* We can afford this to be inefficient... */ - m68k_setpc (m68k_getpc ()); - fill_prefetch_slow (); - opcode = x_get_word (regs.pc); - if (opcode == 0x4e73 /* RTE */ - || opcode == 0x4e74 /* RTD */ - || opcode == 0x4e75 /* RTS */ - || opcode == 0x4e77 /* RTR */ - || opcode == 0x4e76 /* TRAPV */ - || (opcode & 0xffc0) == 0x4e80 /* JSR */ - || (opcode & 0xffc0) == 0x4ec0 /* JMP */ - || (opcode & 0xff00) == 0x6100 /* BSR */ - || ((opcode & 0xf000) == 0x6000 /* Bcc */ - && cctrue ((opcode >> 8) & 0xf)) - || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ - && !cctrue ((opcode >> 8) & 0xf) - && (uae_s16)m68k_dreg (regs, opcode & 7) != 0)) - { - last_trace_ad = m68k_getpc (); - unset_special (SPCFLAG_TRACE); - set_special (SPCFLAG_DOTRACE); - } - } else if (regs.t1) { - last_trace_ad = m68k_getpc (); - unset_special (SPCFLAG_TRACE); - set_special (SPCFLAG_DOTRACE); - } -} - - -// handle interrupt delay (few cycles) -STATIC_INLINE int time_for_interrupt (void) -{ - if (regs.ipl > regs.intmask || regs.ipl == 7) { -#if 0 - if (regs.ipl == 3 && current_hpos () < 11) { - write_log ("%d\n", current_hpos ()); - activate_debugger (); - } -#endif - return 1; - } - return 0; -} - -void doint (void) -{ - if (currprefs.cpu_cycle_exact) { - regs.ipl_pin = intlev (); - set_special (SPCFLAG_INT); - return; - } - if (currprefs.cpu_compatible) - set_special (SPCFLAG_INT); - else - set_special (SPCFLAG_DOINT); -} - -#define IDLETIME (currprefs.cpu_idle * sleep_resolution / 700) - -/* - * Compute the number of jitter cycles to add when a video interrupt occurs - * (this is specific to the Atari ST) - */ -STATIC_INLINE void InterruptAddJitter (int Level , int Pending) -{ -} - - -/* - * Handle special flags - */ - -static bool do_specialties_interrupt (int Pending) -{ - return false; /* no interrupt was found */ -} - -STATIC_INLINE int do_specialties (int cycles) -{ -#ifdef JIT - unset_special (SPCFLAG_END_COMPILE); /* has done its job */ -#endif - -#if AMIGA_ONLY - while ((regs.spcflags & SPCFLAG_BLTNASTY) && dmaen (DMA_BLITTER) && cycles > 0 && !currprefs.blitter_cycle_exact) { - /* Laurent : I don't know if our blitter code should be called here ! */ - int c = blitnasty (); - if (c > 0) { - cycles -= c * CYCLE_UNIT * 2; - if (cycles < CYCLE_UNIT) - cycles = 0; - } else - c = 4; - do_cycles (c * CYCLE_UNIT); - if (regs.spcflags & SPCFLAG_COPPER) - do_copper (); - } -#endif - - if (regs.spcflags & SPCFLAG_BUSERROR) { - /* We can not execute bus errors directly in the memory handler - * functions since the PC should point to the address of the next - * instruction, so we're executing the bus errors here: */ - unset_special(SPCFLAG_BUSERROR); - Exception(2, 0, M68000_EXC_SRC_CPU); - } - - if(regs.spcflags & SPCFLAG_EXTRA_CYCLES) { - /* Add some extra cycles to simulate a wait state */ - unset_special(SPCFLAG_EXTRA_CYCLES); - M68000_AddCycles(nWaitStateCycles); - nWaitStateCycles = 0; - } - - if (regs.spcflags & SPCFLAG_DOTRACE) - Exception (9, last_trace_ad, M68000_EXC_SRC_CPU); - - if (regs.spcflags & SPCFLAG_TRAP) { - unset_special (SPCFLAG_TRAP); - Exception (3, 0, M68000_EXC_SRC_CPU); - } - - /* Handle the STOP instruction */ - if ( regs.spcflags & SPCFLAG_STOP ) { - /* We first test if there's a pending interrupt that would */ - /* allow to immediatly leave the STOP state */ - if ( do_specialties_interrupt(true) ) { /* test if there's an interrupt and add pending jitter */ - regs.stopped = 0; - unset_special (SPCFLAG_STOP); - } - - while (regs.spcflags & SPCFLAG_STOP) { - - /* Take care of quit event if needed */ - if (regs.spcflags & SPCFLAG_BRK) - return 1; - - do_cycles (currprefs.cpu_cycle_exact ? 2 * CYCLE_UNIT : 4 * CYCLE_UNIT); - M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT); - - /* It is possible one or more ints happen at the same time */ - /* We must process them during the same cpu cycle until the special INT flag is set */ - while (PendingInterruptCount<=0 && PendingInterruptFunction) { - /* 1st, we call the interrupt handler */ - CALL_VAR(PendingInterruptFunction); - - /* Then we check if this handler triggered an interrupt to process */ - if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */ - regs.stopped = 0; - unset_special (SPCFLAG_STOP); - break; - } - -#if AMIGA_ONLY - if (regs.spcflags & SPCFLAG_COPPER) - do_copper (); -#endif - - if (currprefs.cpu_cycle_exact) { - ipl_fetch (); - if (time_for_interrupt ()) { - do_interrupt (regs.ipl, true); - } - } else { -#if 0 - if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) { - int intr = intlev (); - unset_special (SPCFLAG_INT | SPCFLAG_DOINT); - if (intr > 0 && intr > regs.intmask) - do_interrupt (intr, true); - } -#endif - } - if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) { - unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); - // SPCFLAG_BRK breaks STOP condition, need to prefetch - m68k_resumestopped (); - return 1; - } - - if (currprefs.cpu_idle && currprefs.m68k_speed != 0 && ((regs.spcflags & SPCFLAG_STOP)) == SPCFLAG_STOP) { - /* sleep 1ms if STOP-instruction is executed */ - if (1) { - static int sleepcnt, lvpos, zerocnt; - if (vpos != lvpos) { - sleepcnt--; -#ifdef JIT - if (pissoff == 0 && currprefs.cachesize && --zerocnt < 0) { - sleepcnt = -1; - zerocnt = IDLETIME / 4; - } -#endif - lvpos = vpos; - if (sleepcnt < 0) { - /*sleepcnt = IDLETIME / 2; */ /* Laurent : badly removed for now */ - sleep_millis (1); - } - } - } - } - } - } - } - - if (regs.spcflags & SPCFLAG_TRACE) - do_trace (); - - if (currprefs.cpu_cycle_exact) { - if (time_for_interrupt ()) { - do_interrupt (regs.ipl, true); - } - } else { - if (regs.spcflags & SPCFLAG_INT) { - int intr = intlev (); - unset_special (SPCFLAG_INT | SPCFLAG_DOINT); - if (intr > 0 && (intr > regs.intmask || intr == 7)) - do_interrupt (intr, false); /* call do_interrupt() with Pending=false, not necessarily true but harmless */ - } - } - - if (regs.spcflags & SPCFLAG_DOINT) { - unset_special (SPCFLAG_DOINT); - set_special (SPCFLAG_INT); - } - - if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */ - /* TODO: Always do do_specialties_interrupt() in m68k_run_x instead? */ - regs.stopped = 0; - } - - if (regs.spcflags & SPCFLAG_DEBUGGER) - DebugCpu_Check(); - - if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) { - unset_special(SPCFLAG_MODE_CHANGE); - return 1; - } - return 0; -} - -//static uae_u32 pcs[1000]; - -#if DEBUG_CD32CDTVIO - -static uae_u32 cd32nextpc, cd32request; - -static void out_cd32io2 (void) -{ - uae_u32 request = cd32request; - write_log ("%08x returned\n", request); - //write_log ("ACTUAL=%d ERROR=%d\n", get_long (request + 32), get_byte (request + 31)); - cd32nextpc = 0; - cd32request = 0; -} - -static void out_cd32io (uae_u32 pc) -{ - TCHAR out[100]; - int ioreq = 0; - uae_u32 request = m68k_areg (regs, 1); - - if (pc == cd32nextpc) { - out_cd32io2 (); - return; - } - out[0] = 0; - switch (pc) - { - case 0xe57cc0: - case 0xf04c34: - _stprintf (out, "opendevice"); - break; - case 0xe57ce6: - case 0xf04c56: - _stprintf (out, "closedevice"); - break; - case 0xe57e44: - case 0xf04f2c: - _stprintf (out, "beginio"); - ioreq = 1; - break; - case 0xe57ef2: - case 0xf0500e: - _stprintf (out, "abortio"); - ioreq = -1; - break; - } - if (out[0] == 0) - return; - if (cd32request) - write_log ("old request still not returned!\n"); - cd32request = request; - cd32nextpc = get_long (m68k_areg (regs, 7)); - write_log ("%s A1=%08X\n", out, request); - if (ioreq) { - static int cnt = 0; - int cmd = get_word (request + 28); -#if 0 - if (cmd == 37) { - cnt--; - if (cnt <= 0) - activate_debugger (); - } -#endif - write_log ("CMD=%d DATA=%08X LEN=%d %OFF=%d PC=%x\n", - cmd, get_long (request + 40), - get_long (request + 36), get_long (request + 44), M68K_GETPC); - } - if (ioreq < 0) - ;//activate_debugger (); -} - -#endif /* DEBUG_CD32CDTVIO */ - -#ifndef CPUEMU_11 - -static void m68k_run_1 (void) -{ -} - -#else - -/* It's really sad to have two almost identical functions for this, but we -do it all for performance... :( -This version emulates 68000's prefetch "cache" */ -static void m68k_run_1 (void) -{ - struct regstruct *r = ®s; - - for (;;) { - uae_u32 opcode = r->ir; - - count_instr (opcode); - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - -#if DEBUG_CD32CDTVIO - out_cd32io (m68k_getpc ()); -#endif - -#if 0 - int pc = m68k_getpc (); - if (pc == 0xdff002) - write_log ("hip\n"); - if (pc != pcs[0] && (pc < 0xd00000 || pc > 0x1000000)) { - memmove (pcs + 1, pcs, 998 * 4); - pcs[0] = pc; - //write_log ("%08X-%04X ", pc, opcode); - } -#endif - do_cycles (cpu_cycles); - cpu_cycles = (*cpufunctbl[opcode])(opcode); - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - - /* We can have several interrupts at the same time before the next CPU instruction */ - /* We must check for pending interrupt and call do_specialties_interrupt() only */ - /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ - /* and prevent exiting the STOP state when calling do_specialties() after. */ - /* For performance, we first test PendingInterruptCount, then regs.spcflags */ - while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { - CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */ - do_specialties_interrupt(false); /* test if there's an mfp/video interrupt and add non pending jitter */ - } - - if (r->spcflags) { - if (do_specialties (cpu_cycles)) - return; - } - regs.ipl = regs.ipl_pin; - if (!currprefs.cpu_compatible || (currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000)) - return; - } -} - -#endif /* CPUEMU_11 */ - -#ifndef CPUEMU_12 - -static void m68k_run_1_ce (void) -{ -} - -#else - -/* cycle-exact m68k_run () */ - -static void m68k_run_1_ce (void) -{ - struct regstruct *r = ®s; - - ipl_fetch (); - for (;;) { - uae_u32 opcode = r->ir; - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - -#if DEBUG_CD32CDTVIO - out_cd32io (m68k_getpc ()); -#endif - (*cpufunctbl[opcode])(opcode); - if (r->spcflags) { - if (do_specialties (0)) - return; - } - if (!currprefs.cpu_cycle_exact || currprefs.cpu_model > 68000) - return; - } -} -#endif - -#ifdef JIT /* Completely different run_2 replacement */ - -void do_nothing (void) -{ - /* What did you expect this to do? */ - do_cycles (0); - /* I bet you didn't expect *that* ;-) */ -} - -void exec_nostats (void) -{ - struct regstruct *r = ®s; - - for (;;) - { - uae_u16 opcode = get_iword (0); - - cpu_cycles = (*cpufunctbl[opcode])(opcode); - - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - - do_cycles (cpu_cycles); - - if (end_block (opcode) || r->spcflags || uae_int_requested) - return; /* We will deal with the spcflags in the caller */ - } -} - -static int triggered; - -void execute_normal (void) -{ - struct regstruct *r = ®s; - int blocklen; - cpu_history pc_hist[MAXRUN]; - int total_cycles; - - if (check_for_cache_miss ()) - return; - - total_cycles = 0; - blocklen = 0; - start_pc_p = r->pc_oldp; - start_pc = r->pc; - for (;;) { - /* Take note: This is the do-it-normal loop */ - uae_u16 opcode = get_iword (0); - - special_mem = DISTRUST_CONSISTENT_MEM; - pc_hist[blocklen].location = (uae_u16*)r->pc_p; - - cpu_cycles = (*cpufunctbl[opcode])(opcode); - - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - do_cycles (cpu_cycles); - total_cycles += cpu_cycles; - pc_hist[blocklen].specmem = special_mem; - blocklen++; - if (end_block (opcode) || blocklen >= MAXRUN || r->spcflags || uae_int_requested) { - compile_block (pc_hist, blocklen, total_cycles); - return; /* We will deal with the spcflags in the caller */ - } - /* No need to check regs.spcflags, because if they were set, - we'd have ended up inside that "if" */ - } -} - -typedef void compiled_handler (void); - -static void m68k_run_jit (void) -{ - for (;;) { - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - - ((compiled_handler*)(pushall_call_handler))(); - /* Whenever we return from that, we should check spcflags */ - if (uae_int_requested) { - INTREQ_f (0x8008); - set_special (SPCFLAG_INT); - } - if (regs.spcflags) { - if (do_specialties (0)) { - return; - } - } - } -} -#endif /* JIT */ - -#ifndef CPUEMU_0 - -static void m68k_run_2 (void) -{ -} - -#else - -#if 0 -static void opcodedebug (uae_u32 pc, uae_u16 opcode) -{ - struct mnemolookup *lookup; - struct instr *dp; - uae_u32 addr; - int fault; - - if (cpufunctbl[opcode] == op_illg_1) - opcode = 0x4AFC; - dp = table68k + opcode; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) - ; - fault = 0; -// TRY(prb) { - except = 0; - addr = mmu_translate (pc, (regs.mmu_ssw & 4) ? 1 : 0, 0, 0); -// } CATCH (prb) { - if (except != 0) { - fault = 1; - } - if (!fault) { - write_log ("mmufixup=%d %04x %04x\n", mmufixup[0].reg, regs.wb3_status, regs.mmu_ssw); - m68k_disasm_2 (stdout, addr, NULL, 1, NULL, NULL, 0); - write_log ("%s\n", buf); - m68k_dumpstate (stdout, NULL); - } -} -#endif - -/* Aranym MMU 68040 */ -static void m68k_run_mmu040 (void) -{ - uae_u32 opcode; - uaecptr pc; - m68k_exception save_except; - -retry: -// TRY (prb) { - except = 0; - for (;;) { - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - - pc = regs.fault_pc = m68k_getpc (); -#if 0 - static int done; - if (pc == 0x16AF94) { -// write_log ("D0=%d A7=%08x\n", regs.regs[0], regs.regs[15]); - if (regs.regs[0] == 360) { - done = 1; - activate_debugger (); - } - } -/* - if (pc == 0x16B01A) { - write_log ("-> ERR\n"); - } - if (pc == 0x16B018) { - write_log ("->\n"); - } -*/ - if (pc == 0x17967C || pc == 0x13b5e2 - 4) { - if (done) { - write_log ("*\n"); - mmu_dump_tables (); - activate_debugger (); - } - } -#endif - opcode = x_prefetch (0); - count_instr (opcode); - do_cycles (cpu_cycles); - cpu_cycles = (*cpufunctbl[opcode])(opcode); - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - - - M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT); - - if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { - /* Add some extra cycles to simulate a wait state */ - unset_special(SPCFLAG_EXTRA_CYCLES); - M68000_AddCycles(nWaitStateCycles); - nWaitStateCycles = 0; - } - - /* We can have several interrupts at the same time before the next CPU instruction */ - /* We must check for pending interrupt and call do_specialties_interrupt() only */ - /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ - /* and prevent exiting the STOP state when calling do_specialties() after. */ - /* For performance, we first test PendingInterruptCount, then regs.spcflags */ - while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { - CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */ - do_specialties_interrupt(false); /* test if there's an mfp/video interrupt and add non pending jitter */ - } - - if (regs.spcflags) { - if (do_specialties (cpu_cycles* 2 / CYCLE_UNIT)) - return; - } - } - -// } CATCH (prb) { - if (except != 0) { - save_except = except; - if (currprefs.mmu_model == 68060) { - regs.fault_pc = pc; - if (mmufixup[1].reg >= 0) { - m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value; - mmufixup[1].reg = -1; - } - } else { - if (regs.wb3_status & 0x80) { - // movem to memory? - if ((opcode & 0xff80) == 0x4880) { - regs.mmu_ssw |= MMU_SSW_CM; - //write_log ("MMU_SSW_CM\n"); - } - } - } - - //opcodedebug (regs.fault_pc, opcode); - - if (mmufixup[0].reg >= 0) { - m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; - mmufixup[0].reg = -1; - } - //activate_debugger (); -// TRY (prb2) { - except = 0; - Exception (save_except, regs.fault_pc, true); -// } CATCH (prb2) { - if (except != 0) { - write_log ("MMU: double bus error, rebooting..\n"); - regs.tcr = 0; - m68k_reset (0); - m68k_setpc (0xf80002); - mmu_reset (); - uae_reset (1); - return; - } - goto retry; - } - -} - -/* "cycle exact" 68020/030 */ -#define MAX68020CYCLES 4 -static void m68k_run_2ce (void) -{ - struct regstruct *r = ®s; - int tmpcycles = MAX68020CYCLES; - - ipl_fetch (); - for (;;) { - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - - uae_u32 opcode = x_prefetch (0); - (*cpufunctbl[opcode])(opcode); - if (r->ce020memcycles > 0) { - tmpcycles = CYCLE_UNIT * MAX68020CYCLES; - do_cycles_ce (r->ce020memcycles); - r->ce020memcycles = 0; - } - if (r->spcflags) { - if (do_specialties (0)) - return; - } - tmpcycles -= cpucycleunit; - if (tmpcycles <= 0) { - do_cycles_ce (1 * CYCLE_UNIT); - tmpcycles = CYCLE_UNIT * MAX68020CYCLES;; - } - regs.ipl = regs.ipl_pin; - } -} - -/* emulate simple prefetch */ -static void m68k_run_2p (void) -{ - uae_u32 prefetch, prefetch_pc; - struct regstruct *r = ®s; - - prefetch_pc = m68k_getpc (); - prefetch = get_longi (prefetch_pc); - for (;;) { - uae_u32 opcode; - uae_u32 pc = m68k_getpc (); - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - -#if DEBUG_CD32CDTVIO - out_cd32io (m68k_getpc ()); -#endif - - do_cycles (cpu_cycles); - - if (pc == prefetch_pc) - opcode = prefetch >> 16; - else if (pc == prefetch_pc + 2) - opcode = prefetch & 0xffff; - else - opcode = get_wordi (pc); - - count_instr (opcode); - - prefetch_pc = m68k_getpc () + 2; - prefetch = get_longi (prefetch_pc); - cpu_cycles = (*cpufunctbl[opcode])(opcode); - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - - M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT); - - if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { - /* Add some extra cycles to simulate a wait state */ - unset_special(SPCFLAG_EXTRA_CYCLES); - M68000_AddCycles(nWaitStateCycles); - nWaitStateCycles = 0; - } - - /* We can have several interrupts at the same time before the next CPU instruction */ - /* We must check for pending interrupt and call do_specialties_interrupt() only */ - /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ - /* and prevent exiting the STOP state when calling do_specialties() after. */ - /* For performance, we first test PendingInterruptCount, then regs.spcflags */ - while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { - CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */ - do_specialties_interrupt(false); /* test if there's an mfp/video interrupt and add non pending jitter */ - } - - if (r->spcflags) { - if (do_specialties (cpu_cycles* 2 / CYCLE_UNIT)) - return; - } - } -} - - -//static int used[65536]; - -/* Same thing, but don't use prefetch to get opcode. */ -static void m68k_run_2 (void) -{ - struct regstruct *r = ®s; - - for (;;) { - uae_u32 opcode = get_iword (0); - count_instr (opcode); - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - -#if 0 - if (!used[opcode]) { - write_log ("%04X ", opcode); - used[opcode] = 1; - } -#endif - do_cycles (cpu_cycles); - cpu_cycles = (*cpufunctbl[opcode])(opcode); - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - - M68000_AddCycles(cpu_cycles * 2 / CYCLE_UNIT); - - if (regs.spcflags & SPCFLAG_EXTRA_CYCLES) { - /* Add some extra cycles to simulate a wait state */ - unset_special(SPCFLAG_EXTRA_CYCLES); - M68000_AddCycles(nWaitStateCycles); - nWaitStateCycles = 0; - } - - /* We can have several interrupts at the same time before the next CPU instruction */ - /* We must check for pending interrupt and call do_specialties_interrupt() only */ - /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ - /* and prevent exiting the STOP state when calling do_specialties() after. */ - /* For performance, we first test PendingInterruptCount, then regs.spcflags */ - while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { - CALL_VAR(PendingInterruptFunction); /* call the interrupt handler */ - do_specialties_interrupt(false); /* test if there's an mfp/video interrupt and add non pending jitter */ - } - - - if (r->spcflags) { - if (do_specialties (cpu_cycles* 2 / CYCLE_UNIT)) - return; - } - } -} - - -/* fake MMU 68k */ -static void m68k_run_mmu (void) -{ - for (;;) { - - /*m68k_dumpstate(stderr, NULL);*/ - if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM)) - { - int FrameCycles, HblCounterVideo, LineCycles; - Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles ); - LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo ); - m68k_disasm(stderr, m68k_getpc (), NULL, 1); - } - - uae_u32 opcode = get_iword (0); - do_cycles (cpu_cycles); - mmu_backup_regs = regs; - cpu_cycles = (*cpufunctbl[opcode])(opcode); - cpu_cycles &= cycles_mask; - cpu_cycles |= cycles_val; - if (mmu_triggered) - mmu_do_hit (); - if (regs.spcflags) { - if (do_specialties (cpu_cycles)) - return; - } - } -} - -#endif /* CPUEMU_0 */ - -int in_m68k_go = 0; - -static void exception2_handle (uaecptr addr, uaecptr fault) -{ - last_addr_for_exception_3 = addr; - last_fault_for_exception_3 = fault; - last_writeaccess_for_exception_3 = 0; - last_instructionaccess_for_exception_3 = 0; - Exception (2, m68k_getpc (), true); -} - -void m68k_go (int may_quit) -{ - int hardboot = 1; - - if (in_m68k_go || !may_quit) { - write_log ("Bug! m68k_go is not reentrant.\n"); - abort (); - } - - reset_frame_rate_hack (); - update_68k_cycles (); - - in_m68k_go++; - for (;;) { - void (*run_func)(void); - - if (regs.spcflags & SPCFLAG_BRK) { - unset_special(SPCFLAG_BRK); - break; - } - - quit_program = 0; - hardboot = 0; - -#ifdef DEBUGGER - if (debugging) - debug (); -#endif - if (regs.panic) { - regs.panic = 0; - /* program jumped to non-existing memory and cpu was >= 68020 */ - get_real_address (regs.isp); /* stack in no one's land? -> reboot */ - if (regs.isp & 1) - regs.panic = 1; - if (!regs.panic) - exception2_handle (regs.panic_pc, regs.panic_addr); - if (regs.panic) { - /* system is very badly confused */ - write_log ("double bus error or corrupted stack, forcing reboot..\n"); - regs.panic = 0; - uae_reset (1); - } - } - -#if 0 /* what was the meaning of this? this breaks trace emulation if debugger is used */ - if (regs.spcflags) { - uae_u32 of = regs.spcflags; - regs.spcflags &= ~(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); - do_specialties (0); - regs.spcflags |= of & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); - } -#endif - - set_x_funcs (); - if (mmu_enabled && !currprefs.cachesize) { - run_func = m68k_run_mmu; - } else { - run_func = currprefs.cpu_cycle_exact && currprefs.cpu_model == 68000 ? m68k_run_1_ce : - currprefs.cpu_compatible && currprefs.cpu_model == 68000 ? m68k_run_1 : -#ifdef JIT - currprefs.cpu_model >= 68020 && currprefs.cachesize ? m68k_run_jit : -#endif - (currprefs.cpu_model == 68040 || currprefs.cpu_model == 68060) && currprefs.mmu_model ? m68k_run_mmu040 : - currprefs.cpu_model >= 68020 && currprefs.cpu_cycle_exact ? m68k_run_2ce : - currprefs.cpu_compatible ? m68k_run_2p : m68k_run_2; - } - run_func (); - } - in_m68k_go--; -} - -#if 0 -static void m68k_verify (uaecptr addr, uaecptr *nextpc) -{ - uae_u32 opcode, val; - struct instr *dp; - - opcode = get_iword_1 (0); - last_op_for_exception_3 = opcode; - m68kpc_offset = 2; - - if (cpufunctbl[opcode] == op_illg_1) { - opcode = 0x4AFC; - } - dp = table68k + opcode; - - if (dp->suse) { - if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) { - Exception (3, 0); - return; - } - } - if (dp->duse) { - if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) { - Exception (3, 0); - return; - } - } -} -#endif - -static const TCHAR *ccnames[] = -{ "T ","F ","HI","LS","CC","CS","NE","EQ", -"VC","VS","PL","MI","GE","LT","GT","LE" }; - -static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg) -{ - TCHAR *p = out + _tcslen (out); - if (*prevreg < 0) { - *prevreg = reg; - *lastreg = reg; - return; - } - if ((*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) { - _stprintf (p, "%s%c%d", (*first) ? "" : "/", (*lastreg) < 8 ? 'D' : 'A', (*lastreg) & 7); - p = p + _tcslen (p); - if ((*lastreg) + 2 == reg) { - _stprintf (p, "/%c%d", (*prevreg) < 8 ? 'D' : 'A', (*prevreg) & 7); - } else if ((*lastreg) != (*prevreg)) { - _stprintf (p, "-%c%d", (*prevreg) < 8 ? 'D' : 'A', (*prevreg) & 7); - } - *lastreg = reg; - *first = 0; - } - *prevreg = reg; -} - -static void movemout (TCHAR *out, uae_u16 mask, int mode) -{ - unsigned int dmask, amask; - int prevreg = -1, lastreg = -1, first = 1; - - if (mode == Apdi) { - int i; - uae_u8 dmask2 = (mask >> 8) & 0xff; - uae_u8 amask2 = mask & 0xff; - dmask = 0; - amask = 0; - for (i = 0; i < 8; i++) { - if (dmask2 & (1 << i)) - dmask |= 1 << (7 - i); - if (amask2 & (1 << i)) - amask |= 1 << (7 - i); - } - } else { - dmask = mask & 0xff; - amask = (mask >> 8) & 0xff; - } - while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask]); dmask = movem_next[dmask]; } - while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8); amask = movem_next[amask]; } - addmovemreg (out, &prevreg, &lastreg, &first, -1); -} - -static void disasm_size (TCHAR *instrname, struct instr *dp) -{ -#if 0 - int i, size; - uae_u16 mnemo = dp->mnemo; - - size = dp->size; - for (i = 0; i < 65536; i++) { - struct instr *in = &table68k[i]; - if (in->mnemo == mnemo && in != dp) { - if (size != in->size) - break; - } - } - if (i == 65536) - size = -1; -#endif - switch (dp->size) - { - case sz_byte: - _tcscat (instrname, ".B "); - break; - case sz_word: - _tcscat (instrname, ".W "); - break; - case sz_long: - _tcscat (instrname, ".L "); - break; - default: - _tcscat (instrname, " "); - break; - } -} - -static void m68k_disasm_2 (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode) -{ - uaecptr newpc = 0; - m68kpc_offset = addr - m68k_getpc (); - - if (!table68k) - return; - while (cnt-- > 0) { - TCHAR instrname[100], *ccpt; - int i; - uae_u32 opcode; - struct mnemolookup *lookup; - struct instr *dp; - int oldpc; - - oldpc = m68kpc_offset; - opcode = get_iword_1 (m68kpc_offset); - if (cpufunctbl[opcode] == op_illg_1) { - opcode = 0x4AFC; - } - dp = table68k + opcode; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) - ; - - fprintf(f, "%08lX ", m68k_getpc () + m68kpc_offset); - m68kpc_offset += 2; - - if (strcmp(lookup->friendlyname, "")) - _tcscpy (instrname, lookup->friendlyname); - else - _tcscpy (instrname, lookup->name); - ccpt = _tcsstr (instrname, "cc"); - if (ccpt != 0) { - _tcsncpy (ccpt, ccnames[dp->cc], 2); - } - disasm_size (instrname, dp); - - if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) { - uae_u16 imm = get_iword_1 (m68kpc_offset); - uae_u16 creg = imm & 0x0fff; - uae_u16 r = imm >> 12; - TCHAR regs[16]; - const TCHAR *cname = "?"; - int i; - for (i = 0; m2cregs[i].regname; i++) { - if (m2cregs[i].regno == creg) - break; - } - _stprintf (regs, "%c%d", r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r); - if (m2cregs[i].regname) - cname = m2cregs[i].regname; - if (lookup->mnemo == i_MOVE2C) { - _tcscat (instrname, regs); - _tcscat (instrname, ","); - _tcscat (instrname, cname); - } else { - _tcscat (instrname, cname); - _tcscat (instrname, ","); - _tcscat (instrname, regs); - } - m68kpc_offset += 2; - } else if (lookup->mnemo == i_MVMEL) { - newpc = m68k_getpc () + m68kpc_offset; - m68kpc_offset += 2; - newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); - _tcscat (instrname, ","); - movemout (instrname, get_iword_1 (oldpc + 2), dp->dmode); - } else if (lookup->mnemo == i_MVMLE) { - m68kpc_offset += 2; - movemout (instrname, get_iword_1 (oldpc + 2), dp->dmode); - _tcscat (instrname, ","); - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); - } else { - if (dp->suse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (0, opcode, dp->sreg, dp->smode, dp->size, instrname, seaddr, safemode); - } - if (dp->suse && dp->duse) - _tcscat (instrname, ","); - if (dp->duse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); - } - } - - for (i = 0; i < (m68kpc_offset - oldpc) / 2; i++) { - fprintf(f, "%04x ", get_iword_1 (oldpc + i * 2)); - } - - while (i++ < 5) - fprintf(f, "%s", " "); - - fprintf(f, "%s", instrname); - - if (ccpt != 0) { - if (deaddr) - *deaddr = newpc; - if (cctrue (dp->cc)) - fprintf(f, " == $%08X (T)", newpc); - else - fprintf(f, " == $%08X (F)", newpc); - } else if ((opcode & 0xff00) == 0x6100) { /* BSR */ - if (deaddr) - *deaddr = newpc; - fprintf(f, " == $%08X", newpc); - } - fprintf(f, "%s", "\n"); - } - if (nextpc) - *nextpc = m68k_getpc () + m68kpc_offset; -} - -void m68k_disasm_ea (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr) -{ - m68k_disasm_2 (f, addr, nextpc, cnt, seaddr, deaddr, 1); -} -void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt) -{ - m68k_disasm_2 (f, addr, nextpc, cnt, NULL, NULL, 0); -} - -/************************************************************* -Disasm the m68kcode at the given address into instrname -and instrcode -*************************************************************/ -void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc) -{ - TCHAR *ccpt; - uae_u32 opcode; - struct mnemolookup *lookup; - struct instr *dp; - int oldpc; - - uaecptr newpc = 0; - - m68kpc_offset = addr - m68k_getpc (); - - oldpc = m68kpc_offset; - opcode = get_iword_1 (m68kpc_offset); - if (cpufunctbl[opcode] == op_illg_1) { - opcode = 0x4AFC; - } - dp = table68k + opcode; - for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++); - - m68kpc_offset += 2; - - _tcscpy (instrname, lookup->name); - ccpt = _tcsstr (instrname, "cc"); - if (ccpt != 0) { - _tcsncpy (ccpt, ccnames[dp->cc], 2); - } - switch (dp->size){ - case sz_byte: _tcscat (instrname, ".B "); break; - case sz_word: _tcscat (instrname, ".W "); break; - case sz_long: _tcscat (instrname, ".L "); break; - default: _tcscat (instrname, " "); break; - } - - if (dp->suse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (0, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0); - } - if (dp->suse && dp->duse) - _tcscat (instrname, ","); - if (dp->duse) { - newpc = m68k_getpc () + m68kpc_offset; - newpc += ShowEA (0, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0); - } - - if (instrcode) - { - int i; - for (i = 0; i < (m68kpc_offset - oldpc) / 2; i++) - { - _stprintf (instrcode, "%04x ", get_iword_1 (oldpc + i * 2)); - instrcode += _tcslen (instrcode); - } - } - - if (nextpc) - *nextpc = m68k_getpc () + m68kpc_offset; -} - -struct cpum2c m2cregs[] = { - { 0, "SFC" }, - { 1, "DFC" }, - { 2, "CACR" }, - { 3, "TC" }, - { 4, "ITT0" }, - { 5, "ITT1" }, - { 6, "DTT0" }, - { 7, "DTT1" }, - { 8, "BUSC" }, - { 0x800, "USP" }, - { 0x801, "VBR" }, - { 0x802, "CAAR" }, - { 0x803, "MSP" }, - { 0x804, "ISP" }, - { 0x805, "MMUS" }, - { 0x806, "URP" }, - { 0x807, "SRP" }, - { 0x808, "PCR" }, - { -1, NULL } -}; - -void val_move2c2 (int regno, uae_u32 val) -{ - switch (regno) { - case 0: regs.sfc = val; break; - case 1: regs.dfc = val; break; - case 2: regs.cacr = val; break; - case 3: regs.tcr = val; break; - case 4: regs.itt0 = val; break; - case 5: regs.itt1 = val; break; - case 6: regs.dtt0 = val; break; - case 7: regs.dtt1 = val; break; - case 8: regs.buscr = val; break; - case 0x800: regs.usp = val; break; - case 0x801: regs.vbr = val; break; - case 0x802: regs.caar = val; break; - case 0x803: regs.msp = val; break; - case 0x804: regs.isp = val; break; - case 0x805: regs.mmusr = val; break; - case 0x806: regs.urp = val; break; - case 0x807: regs.srp = val; break; - case 0x808: regs.pcr = val; break; - } -} - -uae_u32 val_move2c (int regno) -{ - switch (regno) { - case 0: return regs.sfc; - case 1: return regs.dfc; - case 2: return regs.cacr; - case 3: return regs.tcr; - case 4: return regs.itt0; - case 5: return regs.itt1; - case 6: return regs.dtt0; - case 7: return regs.dtt1; - case 8: return regs.buscr; - case 0x800: return regs.usp; - case 0x801: return regs.vbr; - case 0x802: return regs.caar; - case 0x803: return regs.msp; - case 0x804: return regs.isp; - case 0x805: return regs.mmusr; - case 0x806: return regs.urp; - case 0x807: return regs.srp; - case 0x808: return regs.pcr; - default: return 0; - } -} - -void m68k_dumpstate (FILE *f, uaecptr *nextpc) -{ - int i, j; - - for (i = 0; i < 8; i++){ - f_out (f, " D%d %08lX ", i, m68k_dreg (regs, i)); - if ((i & 3) == 3) f_out (f, "\n"); - } - for (i = 0; i < 8; i++){ - f_out (f, " A%d %08lX ", i, m68k_areg (regs, i)); - if ((i & 3) == 3) f_out (f, "\n"); - } - if (regs.s == 0) - regs.usp = m68k_areg (regs, 7); - if (regs.s && regs.m) - regs.msp = m68k_areg (regs, 7); - if (regs.s && regs.m == 0) - regs.isp = m68k_areg (regs, 7); - j = 2; - f_out (f, "USP %08X ISP %08X ", regs.usp, regs.isp); - for (i = 0; m2cregs[i].regno>= 0; i++) { - if (!movec_illg (m2cregs[i].regno)) { - if (!_tcscmp (m2cregs[i].regname, "USP") || !_tcscmp (m2cregs[i].regname, "ISP")) - continue; - if (j > 0 && (j % 4) == 0) - f_out (f, "\n"); - f_out (f, "%-4s %08X ", m2cregs[i].regname, val_move2c (m2cregs[i].regno)); - j++; - } - } - if (j > 0) - f_out (f, "\n"); - f_out (f, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d STP=%d\n", - regs.t1, regs.t0, regs.s, regs.m, - GET_XFLG (), GET_NFLG (), GET_ZFLG (), - GET_VFLG (), GET_CFLG (), - regs.intmask, regs.stopped); -#ifdef FPUEMU - if (currprefs.fpu_model) { - uae_u32 fpsr; - for (i = 0; i < 8; i++){ - f_out (f, "FP%d: %g ", i, regs.fp[i]); - if ((i & 3) == 3) - f_out (f, "\n"); - } - fpsr = get_fpsr (); - f_out (f, "N=%d Z=%d I=%d NAN=%d\n", - (fpsr & 0x8000000) != 0, - (fpsr & 0x4000000) != 0, - (fpsr & 0x2000000) != 0, - (fpsr & 0x1000000) != 0); - } -#endif - if (currprefs.cpu_compatible && currprefs.cpu_model == 68000) { - struct instr *dp; - struct mnemolookup *lookup1, *lookup2; - dp = table68k + regs.irc; - for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++); - dp = table68k + regs.ir; - for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++); - f_out (f, "Prefetch %04x (%s) %04x (%s)\n", regs.irc, lookup1->name, regs.ir, lookup2->name); - } - - m68k_disasm (f, m68k_getpc (), nextpc, 1); - if (nextpc) - f_out (f, "Next PC: %08lx\n", *nextpc); -} - -#ifdef SAVESTATE - -/* CPU save/restore code */ - -#define CPUTYPE_EC 1 -#define CPUMODE_HALT 1 - - - -uae_u8 *restore_cpu (uae_u8 *src) -{ - int i, flags, model; - uae_u32 l; - - changed_prefs.cpu_model = model = restore_u32 (); - flags = restore_u32 (); - changed_prefs.address_space_24 = 0; - if (flags & CPUTYPE_EC) - changed_prefs.address_space_24 = 1; - if (model > 68020) - changed_prefs.cpu_compatible = 0; - currprefs.address_space_24 = changed_prefs.address_space_24; - currprefs.cpu_compatible = changed_prefs.cpu_compatible; - currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact; - currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact; - currprefs.cpu_frequency = changed_prefs.cpu_frequency = 0; - currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = 0; - for (i = 0; i < 15; i++) - regs.regs[i] = restore_u32 (); - regs.pc = restore_u32 (); - regs.irc = restore_u16 (); - regs.ir = restore_u16 (); - regs.usp = restore_u32 (); - regs.isp = restore_u32 (); - regs.sr = restore_u16 (); - l = restore_u32 (); - if (l & CPUMODE_HALT) { - regs.stopped = 1; - } else { - regs.stopped = 0; - } - if (model >= 68010) { - regs.dfc = restore_u32 (); - regs.sfc = restore_u32 (); - regs.vbr = restore_u32 (); - } - if (model >= 68020) { - regs.caar = restore_u32 (); - regs.cacr = restore_u32 (); - regs.msp = restore_u32 (); - /* A500 speed in 68020 mode isn't too logical.. */ - if (changed_prefs.m68k_speed == 0 && !(currprefs.cpu_cycle_exact)) - currprefs.m68k_speed = changed_prefs.m68k_speed = -1; - } - if (model >= 68030) { - crp_030 = restore_u64 (); - srp_030 = restore_u64 (); - tt0_030 =restore_u32 (); - tt1_030 = restore_u32 (); - tc_030 = restore_u32 (); - mmusr_030 = restore_u16 (); - } - if (model >= 68040) { - regs.itt0 = restore_u32 (); - regs.itt1 = restore_u32 (); - regs.dtt0 = restore_u32 (); - regs.dtt1 = restore_u32 (); - regs.tcr = restore_u32 (); - regs.urp = restore_u32 (); - regs.srp = restore_u32 (); - } - if (model >= 68060) { - regs.buscr = restore_u32 (); - regs.pcr = restore_u32 (); - } - if (flags & 0x80000000) { - int khz = restore_u32 (); - restore_u32 (); - if (khz > 0 && khz < 800000) - currprefs.m68k_speed = changed_prefs.m68k_speed = 0; - } - write_log ("CPU: %d%s%03d, PC=%08X\n", - model / 1000, flags & 1 ? "EC" : "", model % 1000, regs.pc); - - return src; -} - -void restore_cpu_finish (void) -{ - init_m68k (); - m68k_setpc (regs.pc); - set_cpu_caches (); - doint (); - if (regs.stopped) - set_special (SPCFLAG_STOP); - //activate_debugger (); -} - -uae_u8 *restore_cpu_extra (uae_u8 *src) -{ - restore_u32 (); - uae_u32 flags = restore_u32 (); - - - currprefs.cpu_cycle_exact = changed_prefs.cpu_cycle_exact = (flags & 1) ? true : false; - currprefs.blitter_cycle_exact = changed_prefs.blitter_cycle_exact = currprefs.cpu_cycle_exact; - currprefs.cpu_compatible = changed_prefs.cpu_compatible = (flags & 2) ? true : false; - currprefs.cpu_frequency = changed_prefs.cpu_frequency = restore_u32 (); - currprefs.cpu_clock_multiplier = changed_prefs.cpu_clock_multiplier = restore_u32 (); - currprefs.cachesize = changed_prefs.cachesize = (flags & 8) ? 8192 : 0; - - currprefs.m68k_speed = changed_prefs.m68k_speed = 0; - if (flags & 4) - currprefs.m68k_speed = changed_prefs.m68k_speed = -1; - - currprefs.cpu060_revision = changed_prefs.cpu060_revision = restore_u8 (); - currprefs.fpu_revision = changed_prefs.fpu_revision = restore_u8 (); - - return src; -} - -uae_u8 *save_cpu_extra (int *len, uae_u8 *dstptr) -{ - uae_u8 *dstbak, *dst; - uae_u32 flags; - - if (dstptr) - dstbak = dst = dstptr; - else - dstbak = dst = xmalloc (uae_u8, 1000); - save_u32 (0); // version - flags = 0; - flags |= currprefs.cpu_cycle_exact ? 1 : 0; - flags |= currprefs.cpu_compatible ? 2 : 0; - flags |= currprefs.m68k_speed < 0 ? 4 : 0; - flags |= currprefs.cachesize > 0 ? 8 : 0; - save_u32 (flags); - save_u32 (currprefs.cpu_frequency); - save_u32 (currprefs.cpu_clock_multiplier); - save_u8 (currprefs.cpu060_revision); - save_u8 (currprefs.fpu_revision); - *len = dst - dstbak; - return dstbak; -} - -uae_u8 *save_cpu (int *len, uae_u8 *dstptr) -{ - uae_u8 *dstbak, *dst; - int model, i, khz; - - if (dstptr) - dstbak = dst = dstptr; - else - dstbak = dst = xmalloc (uae_u8, 1000); - model = currprefs.cpu_model; - save_u32 (model); /* MODEL */ - save_u32 (0x80000000 | (currprefs.address_space_24 ? 1 : 0)); /* FLAGS */ - for (i = 0;i < 15; i++) - save_u32 (regs.regs[i]); /* D0-D7 A0-A6 */ - save_u32 (m68k_getpc ()); /* PC */ - save_u16 (regs.irc); /* prefetch */ - save_u16 (regs.ir); /* instruction prefetch */ - MakeSR (); - save_u32 (!regs.s ? regs.regs[15] : regs.usp); /* USP */ - save_u32 (regs.s ? regs.regs[15] : regs.isp); /* ISP */ - save_u16 (regs.sr); /* SR/CCR */ - save_u32 (regs.stopped ? CPUMODE_HALT : 0); /* flags */ - if (model >= 68010) { - save_u32 (regs.dfc); /* DFC */ - save_u32 (regs.sfc); /* SFC */ - save_u32 (regs.vbr); /* VBR */ - } - if (model >= 68020) { - save_u32 (regs.caar); /* CAAR */ - save_u32 (regs.cacr); /* CACR */ - save_u32 (regs.msp); /* MSP */ - } - if (model >= 68030) { - save_u64 (crp_030); /* CRP */ - save_u64 (srp_030); /* SRP */ - save_u32 (tt0_030); /* TT0/AC0 */ - save_u32 (tt1_030); /* TT1/AC1 */ - save_u32 (tc_030); /* TCR */ - save_u16 (mmusr_030); /* MMUSR/ACUSR */ - } - if (model >= 68040) { - save_u32 (regs.itt0); /* ITT0 */ - save_u32 (regs.itt1); /* ITT1 */ - save_u32 (regs.dtt0); /* DTT0 */ - save_u32 (regs.dtt1); /* DTT1 */ - save_u32 (regs.tcr); /* TCR */ - save_u32 (regs.urp); /* URP */ - save_u32 (regs.srp); /* SRP */ - } - if (model >= 68060) { - save_u32 (regs.buscr); /* BUSCR */ - save_u32 (regs.pcr); /* PCR */ - } - khz = -1; - if (currprefs.m68k_speed == 0) { - khz = currprefs.ntscmode ? 715909 : 709379; - if (currprefs.cpu_model >= 68020) - khz *= 2; - } - save_u32 (khz); // clock rate in KHz: -1 = fastest possible - save_u32 (0); // spare - *len = dst - dstbak; - return dstbak; -} - -uae_u8 *save_mmu (int *len, uae_u8 *dstptr) -{ - uae_u8 *dstbak, *dst; - int model; - - model = currprefs.mmu_model; - if (model != 68040 && model != 68060) - return NULL; - if (dstptr) - dstbak = dst = dstptr; - else - dstbak = dst = xmalloc (uae_u8, 1000); - save_u32 (model); /* MODEL */ - save_u32 (0); /* FLAGS */ - *len = dst - dstbak; - return dstbak; -} - -uae_u8 *restore_mmu (uae_u8 *src) -{ - int flags, model; - - changed_prefs.mmu_model = model = restore_u32 (); - flags = restore_u32 (); - write_log ("MMU: %d\n", model); - return src; -} - -#endif /* SAVESTATE */ - -static void exception3f (uae_u32 opcode, uaecptr addr, uaecptr fault, int writeaccess, int instructionaccess) -{ - if (currprefs.cpu_model >= 68040) - addr &= ~1; - last_addr_for_exception_3 = addr; - last_fault_for_exception_3 = fault; - last_op_for_exception_3 = opcode; - last_writeaccess_for_exception_3 = writeaccess; - last_instructionaccess_for_exception_3 = instructionaccess; - Exception (3, fault, true); -} - -void exception3 (uae_u32 opcode, uaecptr addr, uaecptr fault) -{ - exception3f (opcode, addr, fault, 0, 0); -} - -void exception3i (uae_u32 opcode, uaecptr addr, uaecptr fault) -{ - exception3f (opcode, addr, fault, 0, 1); -} - -void exception2 (uaecptr addr, uaecptr fault) -{ - write_log ("delayed exception2!\n"); - regs.panic_pc = m68k_getpc (); - regs.panic_addr = addr; - regs.panic = 2; - set_special (SPCFLAG_BRK); - m68k_setpc (0xf80000); -#ifdef JIT - set_special (SPCFLAG_END_COMPILE); -#endif - fill_prefetch_slow (); -} - -void cpureset (void) -{ - uaecptr pc; - uaecptr ksboot = 0xf80002 - 2; /* -2 = RESET hasn't increased PC yet */ - uae_u16 ins; - - if (currprefs.cpu_compatible || currprefs.cpu_cycle_exact) { -// customreset (0); - customreset (); - return; - } - pc = m68k_getpc (); - if (pc >= currprefs.chipmem_size) { - addrbank *b = &get_mem_bank (pc); - if (b->check (pc, 2 + 2)) { - /* We have memory, hope for the best.. */ -// customreset (0); - customreset (); - return; - } - write_log ("M68K RESET PC=%x, rebooting..\n", pc); -// customreset (0); - customreset (); - m68k_setpc (ksboot); - return; - } - /* panic, RAM is going to disappear under PC */ - ins = get_word (pc + 2); - if ((ins & ~7) == 0x4ed0) { - int reg = ins & 7; - uae_u32 addr = m68k_areg (regs, reg); - write_log ("reset/jmp (ax) combination emulated -> %x\n", addr); -// customreset (0); - customreset (); - if (addr < 0x80000) - addr += 0xf80000; - m68k_setpc (addr - 2); - return; - } - write_log ("M68K RESET PC=%x, rebooting..\n", pc); -// customreset (0); - customreset (); - m68k_setpc (ksboot); -} - - -void m68k_setstopped (void) -{ - regs.stopped = 1; - /* A traced STOP instruction drops through immediately without - actually stopping. */ - if ((regs.spcflags & SPCFLAG_DOTRACE) == 0) - set_special (SPCFLAG_STOP); - else - m68k_resumestopped (); -} - -void m68k_resumestopped (void) -{ - if (!regs.stopped) - return; - regs.stopped = 0; - if (currprefs.cpu_cycle_exact) { - if (currprefs.cpu_model == 68000) - do_cycles_ce000 (6); - } - fill_prefetch_slow (); - unset_special (SPCFLAG_STOP); -} - -/* -* Compute exact number of CPU cycles taken -* by DIVU and DIVS on a 68000 processor. -* -* Copyright (c) 2005 by Jorge Cwik, pasti@fxatari.com -* -* This is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This software is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this software; if not, write to the Free Software -* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -*/ - - -/* - -The routines below take dividend and divisor as parameters. -They return 0 if division by zero, or exact number of cycles otherwise. - -The number of cycles returned assumes a register operand. -Effective address time must be added if memory operand. - -For 68000 only (not 68010, 68012, 68020, etc). -Probably valid for 68008 after adding the extra prefetch cycle. - - -Best and worst cases for register operand: -(Note the difference with the documented range.) - - -DIVU: - -Overflow (always): 10 cycles. -Worst case: 136 cycles. -Best case: 76 cycles. - - -DIVS: - -Absolute overflow: 16-18 cycles. -Signed overflow is not detected prematurely. - -Worst case: 156 cycles. -Best case without signed overflow: 122 cycles. -Best case with signed overflow: 120 cycles - - -*/ - -int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor) -{ - int mcycles; - uae_u32 hdivisor; - int i; - - if (divisor == 0) - return 0; - - // Overflow - if ((dividend >> 16) >= divisor) - return (mcycles = 5) * 2; - - mcycles = 38; - hdivisor = divisor << 16; - - for (i = 0; i < 15; i++) { - uae_u32 temp; - temp = dividend; - - dividend <<= 1; - - // If carry from shift - if ((uae_s32)temp < 0) - dividend -= hdivisor; - else { - mcycles += 2; - if (dividend >= hdivisor) { - dividend -= hdivisor; - mcycles--; - } - } - } - return mcycles * 2; -} - -int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor) -{ - int mcycles; - uae_u32 aquot; - int i; - - if (divisor == 0) - return 0; - - mcycles = 6; - - if (dividend < 0) - mcycles++; - - // Check for absolute overflow - if (((uae_u32)abs (dividend) >> 16) >= (uae_u16)abs (divisor)) - return (mcycles + 2) * 2; - - // Absolute quotient - aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor); - - mcycles += 55; - - if (divisor >= 0) { - if (dividend >= 0) - mcycles--; - else - mcycles++; - } - - // Count 15 msbits in absolute of quotient - - for (i = 0; i < 15; i++) { - if ((uae_s16)aquot >= 0) - mcycles++; - aquot <<= 1; - } - - return mcycles * 2; -} - -STATIC_INLINE void fill_cache040 (uae_u32 addr) -{ - int index, i, lws; - uae_u32 tag; - uae_u32 data; - struct cache040 *c; - static int linecnt; - - addr &= ~15; - index = (addr >> 4) & (CACHESETS040 - 1); - tag = regs.s | (addr & ~((CACHESETS040 << 4) - 1)); - lws = (addr >> 2) & 3; - c = &caches040[index]; - for (i = 0; i < CACHELINES040; i++) { - if (c->valid[i] && c->tag[i] == tag) { - // cache hit - regs.prefetch020addr[0] = addr; - regs.prefetch020data[0] = c->data[i][lws]; - return; - } - } - // cache miss - data = mem_access_delay_longi_read_ce020 (addr); - int line = linecnt; - for (i = 0; i < CACHELINES040; i++) { - int line = (linecnt + i) & (CACHELINES040 - 1); - if (c->tag[i] != tag || c->valid[i] == false) { - c->tag[i] = tag; - c->valid[i] = true; - c->data[i][0] = data; - } - } - regs.prefetch020addr[0] = addr; - regs.prefetch020data[0] = data; -} - -// this one is really simple and easy -STATIC_INLINE void fill_icache020 (uae_u32 addr, int idx) -{ - int index; - uae_u32 tag; - uae_u32 data; - struct cache020 *c; - - addr &= ~3; - index = (addr >> 2) & (CACHELINES020 - 1); - tag = regs.s | (addr & ~((CACHELINES020 << 2) - 1)); - c = &caches020[index]; - if (c->valid && c->tag == tag) { - // cache hit - regs.prefetch020addr[idx] = addr; - regs.prefetch020data[idx] = c->data; - return; - } - // cache miss - data = mem_access_delay_longi_read_ce020 (addr); - if (!(regs.cacr & 2)) { - c->tag = tag; - c->valid = !!(regs.cacr & 1); - c->data = data; - } - regs.prefetch020addr[idx] = addr; - regs.prefetch020data[idx] = data; -} - -uae_u32 get_word_ce020_prefetch (int o) -{ - int i; - uae_u32 pc = m68k_getpc () + o; - - for (;;) { - for (i = 0; i < 2; i++) { - if (pc == regs.prefetch020addr[0]) { - uae_u32 v = regs.prefetch020data[0] >> 16; - fill_icache020 (regs.prefetch020addr[0] + 4, 1); - return v; - } - if (pc == regs.prefetch020addr[0] + 2) { - uae_u32 v = regs.prefetch020data[0] & 0xffff; - if (regs.prefetch020addr[1] == regs.prefetch020addr[0] + 4) { - regs.prefetch020addr[0] = regs.prefetch020addr[1]; - regs.prefetch020data[0] = regs.prefetch020data[1]; - fill_icache020 (regs.prefetch020addr[0] + 4, 1); - } else { - fill_icache020 (pc + 4, 0); - fill_icache020 (regs.prefetch020addr[0] + 4, 1); - } - return v; - } - regs.prefetch020addr[0] = regs.prefetch020addr[1]; - regs.prefetch020data[0] = regs.prefetch020data[1]; - } - fill_icache020 (pc + 0, 0); - fill_icache020 (pc + 4, 1); - } -} - -// 68030 caches aren't so simple as 68020 cache.. -STATIC_INLINE struct cache030 *getcache030 (struct cache030 *cp, uaecptr addr, uae_u32 *tagp, int *lwsp) -{ - int index, lws; - uae_u32 tag; - struct cache030 *c; - - addr &= ~3; - index = (addr >> 4) & (CACHELINES030 - 1); - tag = regs.s | (addr & ~((CACHELINES030 << 4) - 1)); - lws = (addr >> 2) & 3; - c = &cp[index]; - *tagp = tag; - *lwsp = lws; - return c; -} - -STATIC_INLINE void update_cache030 (struct cache030 *c, uae_u32 val, uae_u32 tag, int lws) -{ - if (c->tag != tag) - c->valid[0] = c->valid[1] = c->valid[2] = c->valid[3] = false; - c->tag = tag; - c->valid[lws] = true; - c->data[lws] = val; -} - -STATIC_INLINE void fill_icache030 (uae_u32 addr, int idx) -{ - int lws; - uae_u32 tag; - uae_u32 data; - struct cache030 *c; - - addr &= ~3; - c = getcache030 (icaches030, addr, &tag, &lws); - if (c->valid[lws] && c->tag == tag) { - // cache hit - regs.prefetch020addr[idx] = addr; - regs.prefetch020data[idx] = c->data[lws]; - return; - } - // cache miss - data = mem_access_delay_longi_read_ce020 (addr); - if ((regs.cacr & 3) == 1) { // not frozen and enabled - update_cache030 (c, data, tag, lws); -#if 0 - if ((regs.cacr & 0x11) == 0x11 && lws == 0 && !c->valid[0] && !c->valid[1] && !c->valid[2] && !c->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST) { - // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram - c->data[1] = mem_access_delay_long_read_ce020 (addr + 4); - c->data[2] = mem_access_delay_long_read_ce020 (addr + 8); - c->data[3] = mem_access_delay_long_read_ce020 (addr + 12); - c->valid[1] = c->valid[2] = c->valid[3] = true; - } -#endif - } - regs.prefetch020addr[idx] = addr; - regs.prefetch020data[idx] = data; -} - -STATIC_INLINE bool cancache030 (uaecptr addr) -{ - return ce_cachable[addr >> 16] != 0; -} - -// and finally the worst part, 68030 data cache.. -void write_dcache030 (uaecptr addr, uae_u32 val, int size) -{ - struct cache030 *c1, *c2; - int lws1, lws2; - uae_u32 tag1, tag2; - int aligned = addr & 3; - - if (!(regs.cacr & 0x100) || currprefs.cpu_model == 68040) // data cache disabled? 68040 shares this too. - return; - if (!cancache030 (addr)) - return; - - c1 = getcache030 (dcaches030, addr, &tag1, &lws1); - if (!(regs.cacr & 0x2000)) { // write allocate - if (c1->tag != tag1 || c1->valid[lws1] == false) - return; - } - -#if 0 - uaecptr a = 0x1db0c; - if (addr - (1 << size) + 1 <= a && addr + (1 << size) >= a) { - write_log ("%08x %d %d %08x %08x %d\n", addr, aligned, size, val, tag1, lws1); - if (aligned == 2) - write_log ("*\n"); - } -#endif - - // easy one - if (size == 2 && aligned == 0) { - update_cache030 (c1, val, tag1, lws1); -#if 0 - if ((regs.cacr & 0x1100) == 0x1100 && lws1 == 0 && !c1->valid[0] && !c1->valid[1] && !c1->valid[2] && !c1->valid[3] && ce_banktype[addr >> 16] == CE_MEMBANK_FAST) { - // do burst fetch if cache enabled, not frozen, all slots invalid, no chip ram - c1->data[1] = mem_access_delay_long_read_ce020 (addr + 4); - c1->data[2] = mem_access_delay_long_read_ce020 (addr + 8); - c1->data[3] = mem_access_delay_long_read_ce020 (addr + 12); - c1->valid[1] = c1->valid[2] = c1->valid[3] = true; - } -#endif - return; - } - // argh!! merge partial write - c2 = getcache030 (dcaches030, addr + 4, &tag2, &lws2); - if (size == 2) { - if (c1->valid[lws1] && c1->tag == tag1) { - c1->data[lws1] &= ~(0xffffffff >> (aligned * 8)); - c1->data[lws1] |= val >> (aligned * 8); - } - if (c2->valid[lws2] && c2->tag == tag2) { - c2->data[lws2] &= 0xffffffff >> ((4 - aligned) * 8); - c2->data[lws2] |= val << ((4 - aligned) * 8); - } - } else if (size == 1) { - val <<= 16; - if (c1->valid[lws1] && c1->tag == tag1) { - c1->data[lws1] &= ~(0xffff0000 >> (aligned * 8)); - c1->data[lws1] |= val >> (aligned * 8); - } - if (c2->valid[lws2] && c2->tag == tag2 && aligned == 3) { - c2->data[lws2] &= 0x00ffffff; - c2->data[lws2] |= val << 8; - } - } else if (size == 0) { - val <<= 24; - if (c1->valid[lws1] && c1->tag == tag1) { - c1->data[lws1] &= ~(0xff000000 >> (aligned * 8)); - c1->data[lws1] |= val >> (aligned * 8); - } - } -} - -uae_u32 read_dcache030 (uaecptr addr, int size) -{ - struct cache030 *c1, *c2; - int lws1, lws2; - uae_u32 tag1, tag2; - int aligned = addr & 3; - int len = (1 << size) * 8; - uae_u32 v1, v2; - - if (!(regs.cacr & 0x100) || currprefs.cpu_model == 68040 || !cancache030 (addr)) { // data cache disabled? shared with 68040 "ce" - if (size == 2) - return mem_access_delay_long_read_ce020 (addr); - else if (size == 1) - return mem_access_delay_word_read_ce020 (addr); - else - return mem_access_delay_byte_read_ce020 (addr); - } - - c1 = getcache030 (dcaches030, addr, &tag1, &lws1); - addr &= ~3; - if (!c1->valid[lws1] || c1->tag != tag1) { - v1 = mem_access_delay_long_read_ce020 (addr); - update_cache030 (c1, v1, tag1, lws1); - } else { - v1 = c1->data[lws1]; - if (get_long (addr) != v1) { - write_log ("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n", - size, aligned, addr, get_long (addr), v1, tag1, lws1, M68K_GETPC); - v1 = get_long (addr); - } - } - // only one long fetch needed? - if (size == 0) { - v1 >>= (3 - aligned) * 8; - return v1; - } else if (size == 1 && aligned <= 2) { - v1 >>= (2 - aligned) * 8; - return v1; - } else if (size == 2 && aligned == 0) { - return v1; - } - // need two longs - addr += 4; - c2 = getcache030 (dcaches030, addr, &tag2, &lws2); - if (!c2->valid[lws2] || c2->tag != tag2) { - v2 = mem_access_delay_long_read_ce020 (addr); - update_cache030 (c2, v2, tag2, lws2); - } else { - v2 = c2->data[lws2]; - if (get_long (addr) != v2) { - write_log ("data cache mismatch %d %d %08x %08x != %08x %08x %d PC=%08x\n", - size, aligned, addr, get_long (addr), v2, tag2, lws2, M68K_GETPC); - v2 = get_long (addr); - } - } - if (size == 1 && aligned == 3) - return (v1 << 8) | (v2 >> 24); - else if (size == 2 && aligned == 1) - return (v1 << 8) | (v2 >> 24); - else if (size == 2 && aligned == 2) - return (v1 << 16) | (v2 >> 16); - else if (size == 2 && aligned == 3) - return (v1 << 24) | (v2 >> 8); - - write_log ("dcache030 weirdness!?\n"); - return 0; -} - -uae_u32 get_word_ce030_prefetch (int o) -{ - int i; - uae_u32 pc = m68k_getpc () + o; - - for (;;) { - for (i = 0; i < 2; i++) { - if (pc == regs.prefetch020addr[0]) { - uae_u32 v = regs.prefetch020data[0] >> 16; - fill_icache030 (regs.prefetch020addr[0] + 4, 1); - return v; - } - if (pc == regs.prefetch020addr[0] + 2) { - uae_u32 v = regs.prefetch020data[0] & 0xffff; - if (regs.prefetch020addr[1] == regs.prefetch020addr[0] + 4) { - regs.prefetch020addr[0] = regs.prefetch020addr[1]; - regs.prefetch020data[0] = regs.prefetch020data[1]; - fill_icache030 (regs.prefetch020addr[0] + 4, 1); - } else { - fill_icache030 (pc + 4, 0); - fill_icache030 (regs.prefetch020addr[0] + 4, 1); - } - return v; - } - regs.prefetch020addr[0] = regs.prefetch020addr[1]; - regs.prefetch020data[0] = regs.prefetch020data[1]; - } - fill_icache030 (pc + 0, 0); - fill_icache030 (pc + 4, 1); - } -} - - -void flush_dcache (uaecptr addr, int size) -{ - int i; - if (!currprefs.cpu_cycle_exact) - return; - if (currprefs.cpu_model >= 68030) { - for (i = 0; i < CACHELINES030; i++) { - dcaches030[i].valid[0] = 0; - dcaches030[i].valid[1] = 0; - dcaches030[i].valid[2] = 0; - dcaches030[i].valid[3] = 0; - } - } -} - -void do_cycles_ce020 (int clocks) -{ - do_cycles_ce (clocks * cpucycleunit); -} -void do_cycles_ce020_mem (int clocks) -{ - regs.ce020memcycles -= clocks * cpucycleunit; - do_cycles_ce (clocks * cpucycleunit); -} - -void do_cycles_ce000 (int clocks) -{ - do_cycles_ce (clocks * cpucycleunit); -} - -void m68k_do_rte_mmu (uaecptr a7) -{ - uae_u16 ssr = get_word_mmu (a7 + 8 + 4); - if (ssr & MMU_SSW_CT) { - uaecptr src_a7 = a7 + 8 - 8; - uaecptr dst_a7 = a7 + 8 + 52; - put_word_mmu (dst_a7 + 0, get_word_mmu (src_a7 + 0)); - put_long_mmu (dst_a7 + 2, get_long_mmu (src_a7 + 2)); - // skip this word - put_long_mmu (dst_a7 + 8, get_long_mmu (src_a7 + 8)); - } -} - -void flush_mmu (uaecptr addr, int n) -{ -} - -void m68k_do_rts_mmu (void) -{ - m68k_setpc (get_long_mmu (m68k_areg (regs, 7))); - m68k_areg (regs, 7) += 4; -} - -void m68k_do_bsr_mmu (uaecptr oldpc, uae_s32 offset) -{ - put_long_mmu (m68k_areg (regs, 7) - 4, oldpc); - m68k_areg (regs, 7) -= 4; - m68k_incpci (offset); -} +/* +* UAE - The Un*x Amiga Emulator +* +* MC68000 emulation +* +* (c) 1995 Bernd Schmidt +*/ + +#define MMUOP_DEBUG 2 +#define DEBUG_CD32CDTVIO 0 + +#include "main.h" +#include "m68000.h" +#include "compat.h" +#include "sysconfig.h" +#include "sysdeps.h" +#include "hatari-glue.h" +#include "options_cpu.h" +#include "maccess.h" +#include "memory.h" +#include "newcpu.h" +#include "cpummu.h" +#include "cpummu030.h" +#ifdef WITH_SOFTFLOAT +#include "fpp-softfloat.h" +#else +#include "md-fpp.h" +#endif +#include "main.h" +#include "dsp.h" +#include "dimension.h" +#include "reset.h" +#include "cycInt.h" +#include "dialog.h" +#include "screen.h" +#include "video.h" +#include "options.h" +#include "log.h" +#include "debugui.h" +#include "debugcpu.h" + + +/* Opcode of faulting instruction */ +static uae_u16 last_op_for_exception_3; +/* PC at fault time */ +static uaecptr last_addr_for_exception_3; +/* Address that generated the exception */ +static uaecptr last_fault_for_exception_3; +/* read (0) or write (1) access */ +static int last_writeaccess_for_exception_3; +/* instruction (1) or data (0) access */ +static int last_instructionaccess_for_exception_3; +int mmu_enabled, mmu_triggered; +int cpu_cycles; + +const int areg_byteinc[] = { 1, 1, 1, 1, 1, 1, 1, 2 }; +const int imm8_table[] = { 8, 1, 2, 3, 4, 5, 6, 7 }; + +int movem_index1[256]; +int movem_index2[256]; +int movem_next[256]; + +cpuop_func *cpufunctbl[65536]; + +int OpcodeFamily; +struct mmufixup mmufixup[2]; + +uae_u32 fpp_get_fpsr (void); + +static struct cache030 icaches030[CACHELINES030]; +static struct cache030 dcaches030[CACHELINES030]; + +void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode); + +uae_u32 (*x_prefetch)(int); +uae_u32 (*x_next_iword)(void); +uae_u32 (*x_next_ilong)(void); +uae_u32 (*x_get_ilong)(int); +uae_u32 (*x_get_iword)(int); +uae_u32 (*x_get_ibyte)(int); +uae_u32 (*x_get_long)(uaecptr); +uae_u32 (*x_get_word)(uaecptr); +uae_u32 (*x_get_byte)(uaecptr); +void (*x_put_long)(uaecptr,uae_u32); +void (*x_put_word)(uaecptr,uae_u32); +void (*x_put_byte)(uaecptr,uae_u32); + +uae_u32 (*x_cp_next_iword)(void); +uae_u32 (*x_cp_next_ilong)(void); +uae_u32 (*x_cp_get_long)(uaecptr); +uae_u32 (*x_cp_get_word)(uaecptr); +uae_u32 (*x_cp_get_byte)(uaecptr); +void (*x_cp_put_long)(uaecptr,uae_u32); +void (*x_cp_put_word)(uaecptr,uae_u32); +void (*x_cp_put_byte)(uaecptr,uae_u32); +uae_u32 (REGPARAM3 *x_cp_get_disp_ea_020)(uae_u32 base, int idx) REGPARAM; + +// shared memory access functions +static void set_x_funcs (void) +{ + if (currprefs.cpu_model == 68040) { + x_prefetch = get_iword_mmu040; + x_get_ilong = get_ilong_mmu040; + x_get_iword = get_iword_mmu040; + x_get_ibyte = get_ibyte_mmu040; + x_next_iword = next_iword_mmu040; + x_next_ilong = next_ilong_mmu040; + x_put_long = put_long_mmu040; + x_put_word = put_word_mmu040; + x_put_byte = put_byte_mmu040; + x_get_long = get_long_mmu040; + x_get_word = get_word_mmu040; + x_get_byte = get_byte_mmu040; + } else { + x_prefetch = get_iword_mmu030; + x_get_ilong = get_ilong_mmu030; + x_get_iword = get_iword_mmu030; + x_get_ibyte = get_ibyte_mmu030; + x_next_iword = next_iword_mmu030; + x_next_ilong = next_ilong_mmu030; + x_put_long = put_long_mmu030; + x_put_word = put_word_mmu030; + x_put_byte = put_byte_mmu030; + x_get_long = get_long_mmu030; + x_get_word = get_word_mmu030; + x_get_byte = get_byte_mmu030; + } + + if (currprefs.mmu_model == 68030) { + x_cp_put_long = put_long_mmu030_state; + x_cp_put_word = put_word_mmu030_state; + x_cp_put_byte = put_byte_mmu030_state; + x_cp_get_long = get_long_mmu030_state; + x_cp_get_word = get_word_mmu030_state; + x_cp_get_byte = get_byte_mmu030_state; + x_cp_next_iword = next_iword_mmu030_state; + x_cp_next_ilong = next_ilong_mmu030_state; + x_cp_get_disp_ea_020 = get_disp_ea_020_mmu030; + } else { + x_cp_put_long = x_put_long; + x_cp_put_word = x_put_word; + x_cp_put_byte = x_put_byte; + x_cp_get_long = x_get_long; + x_cp_get_word = x_get_word; + x_cp_get_byte = x_get_byte; + x_cp_next_iword = x_next_iword; + x_cp_next_ilong = x_next_ilong; + x_cp_get_disp_ea_020 = x_get_disp_ea_020; + } +} + +void flush_cpu_caches_040(uae_u16 opcode) +{ + int cache = (opcode >> 6) & 3; + if (!(cache & 2)) + return; + set_cpu_caches(true); +} + +void set_cpu_caches (bool flush) +{ + int i; + + if (currprefs.cpu_model == 68030) { + if (regs.cacr & 0x08) { // clear instr cache + for (i = 0; i < CACHELINES030; i++) { + icaches030[i].valid[0] = 0; + icaches030[i].valid[1] = 0; + icaches030[i].valid[2] = 0; + icaches030[i].valid[3] = 0; + } + regs.cacr &= ~0x08; + } + if (regs.cacr & 0x04) { // clear entry in instr cache + icaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0; + regs.cacr &= ~0x04; + } + if (regs.cacr & 0x800) { // clear data cache + for (i = 0; i < CACHELINES030; i++) { + dcaches030[i].valid[0] = 0; + dcaches030[i].valid[1] = 0; + dcaches030[i].valid[2] = 0; + dcaches030[i].valid[3] = 0; + } + regs.cacr &= ~0x800; + } + if (regs.cacr & 0x400) { // clear entry in data cache + dcaches030[(regs.caar >> 4) & (CACHELINES030 - 1)].valid[(regs.caar >> 2) & 3] = 0; + regs.cacr &= ~0x400; + } + } else if (currprefs.cpu_model == 68040) { + if(ConfigureParams.System.bRealtime) { +#if 0 /* FIXME */ + if(regs.cacr & 0x8000) { + flush_icache(0, -1); + x_prefetch = getc_iword_mmu040; + x_get_ilong = getc_ilong_mmu040; + x_get_iword = getc_iword_mmu040; + x_get_ibyte = getc_ibyte_mmu040; + x_next_iword = nextc_iword_mmu040; + x_next_ilong = nextc_ilong_mmu040; + } else +#endif + { + x_prefetch = get_iword_mmu040; + x_get_ilong = get_ilong_mmu040; + x_get_iword = get_iword_mmu040; + x_get_ibyte = get_ibyte_mmu040; + x_next_iword = next_iword_mmu040; + x_next_ilong = next_ilong_mmu040; + } + } + } +} + +static uae_u32 REGPARAM2 op_illg_1 (uae_u32 opcode) +{ + op_illg (opcode); + return 4; +} +static uae_u32 REGPARAM2 op_unimpl_1 (uae_u32 opcode) +{ + if ((opcode & 0xf000) == 0xf000 || currprefs.cpu_model < 68060) + op_illg (opcode); + else + op_unimpl (opcode); + return 4; +} + +void build_cpufunctbl (void) +{ + int i, opcnt; + unsigned long opcode; + const struct cputbl *tbl = 0; + int lvl; + + switch (currprefs.cpu_model) + { + case 68040: + lvl = 4; + tbl = op_smalltbl_31_ff; + break; + case 68030: + lvl = 3; + tbl = op_smalltbl_32_ff; + break; + default: + changed_prefs.cpu_model = currprefs.cpu_model = 68030; + lvl = 3; + tbl = op_smalltbl_32_ff; + } + + if (tbl == 0) { + write_log ("no CPU emulation cores available CPU=%d!", currprefs.cpu_model); + DebugUI(); + } + + for (opcode = 0; opcode < 65536; opcode++) + cpufunctbl[opcode] = op_illg_1; + for (i = 0; tbl[i].handler != NULL; i++) { + opcode = tbl[i].opcode; + cpufunctbl[opcode] = tbl[i].handler; + } + + opcnt = 0; + for (opcode = 0; opcode < 65536; opcode++) { + cpuop_func *f; + + if (table68k[opcode].mnemo == i_ILLG) + continue; + if (table68k[opcode].clev > lvl) { + continue; + } + + if (table68k[opcode].handler != -1) { + int idx = table68k[opcode].handler; + f = cpufunctbl[idx]; + if (f == op_illg_1) + DebugUI(); + cpufunctbl[opcode] = f; + opcnt++; + } + } + write_log ("Building CPU, %d opcodes (%d %d)\n", + opcnt, lvl, currprefs.cpu_compatible ? 1 : 0); + write_log ("CPU=%d, MMU=%d, FPU=%d ($%02x), JIT%s=%d, realtime=%d\n", + currprefs.cpu_model, currprefs.mmu_model, + currprefs.fpu_model, currprefs.fpu_revision, + currprefs.cachesize ? (currprefs.compfpu ? "=CPU/FPU" : "=CPU") : "", + currprefs.cachesize, ConfigureParams.System.bRealtime); + set_cpu_caches (0); + if (currprefs.mmu_model) { + if (currprefs.cpu_model >= 68040) { + mmu_reset (); + mmu_set_tc (regs.tcr); + mmu_set_super (regs.s != 0); + } else { + mmu030_reset(1); + } + } +} + +static void prefs_changed_cpu (void) { + currprefs.cpu_model = changed_prefs.cpu_model; + currprefs.fpu_model = changed_prefs.fpu_model; + currprefs.fpu_revision = changed_prefs.fpu_revision; + currprefs.mmu_model = changed_prefs.mmu_model; + currprefs.cpu_compatible = changed_prefs.cpu_compatible; +} + +void check_prefs_changed_cpu (void) +{ + bool changed = 0; + + if (changed + || currprefs.cpu_model != changed_prefs.cpu_model + || currprefs.fpu_model != changed_prefs.fpu_model + || currprefs.fpu_revision != changed_prefs.fpu_revision + || currprefs.mmu_model != changed_prefs.mmu_model + || currprefs.cpu_compatible != changed_prefs.cpu_compatible) { + + prefs_changed_cpu (); + build_cpufunctbl (); + changed = 1; + } + + if (currprefs.cpu_idle != changed_prefs.cpu_idle) { + currprefs.cpu_idle = changed_prefs.cpu_idle; + } + if (changed) + set_special (SPCFLAG_MODE_CHANGE); + +} + +void init_m68k (void) +{ + int i; + + prefs_changed_cpu (); + + for (i = 0 ; i < 256 ; i++) { + int j; + for (j = 0 ; j < 8 ; j++) { + if (i & (1 << j)) break; + } + movem_index1[i] = j; + movem_index2[i] = 7-j; + movem_next[i] = i & (~(1 << j)); + } + + write_log ("Building CPU table for configuration: %d", currprefs.cpu_model); + regs.address_space_mask = 0xffffffff; + + if (currprefs.fpu_model > 0) + write_log ("/%d", currprefs.fpu_model); + if (currprefs.cpu_compatible) + write_log (" prefetch"); + write_log ("\n"); + + read_table68k (); + do_merges (); + + write_log ("%d CPU functions\n", nr_cpuop_funcs); + + build_cpufunctbl (); + set_x_funcs (); +} + +struct regstruct regs; +struct flag_struct regflags; + +#define get_word_debug(o) DBGMemory_ReadWord (o) +#define get_iword_debug(o) DBGMemory_ReadWord (o) +#define get_ilong_debug(o) DBGMemory_ReadLong (o) + +static uaecptr ShowEA (void *f, uaecptr pc, uae_u16 opcode, int reg, amodes mode, wordsizes size, TCHAR *buf, uae_u32 *eaddr, int safemode) +{ + uae_u16 dp; + uae_s8 disp8; + uae_s16 disp16; + int r; + uae_u32 dispreg; + uaecptr addr = pc; + uae_s32 offset = 0; + TCHAR buffer[80]; + + switch (mode){ + case Dreg: + _stprintf (buffer, _T("D%d"), reg); + break; + case Areg: + _stprintf (buffer, _T("A%d"), reg); + break; + case Aind: + _stprintf (buffer, _T("(A%d)"), reg); + addr = regs.regs[reg + 8]; + break; + case Aipi: + _stprintf (buffer, _T("(A%d)+"), reg); + addr = regs.regs[reg + 8]; + break; + case Apdi: + _stprintf (buffer, _T("-(A%d)"), reg); + addr = regs.regs[reg + 8]; + break; + case Ad16: + { + TCHAR offtxt[80]; + disp16 = get_iword_debug (pc); pc += 2; + if (disp16 < 0) + _stprintf (offtxt, _T("-$%04x"), -disp16); + else + _stprintf (offtxt, _T("$%04x"), disp16); + addr = m68k_areg (regs, reg) + disp16; + _stprintf (buffer, _T("(A%d, %s) == $%08x"), reg, offtxt, addr); + } + break; + case Ad8r: + dp = get_iword_debug (pc); pc += 2; + disp8 = dp & 0xFF; + r = (dp & 0x7000) >> 12; + dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r); + if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); + dispreg <<= (dp >> 9) & 3; + + if (dp & 0x100) { + uae_s32 outer = 0, disp = 0; + uae_s32 base = m68k_areg (regs, reg); + TCHAR name[10]; + _stprintf (name, _T("A%d, "), reg); + if (dp & 0x80) { base = 0; name[0] = 0; } + if (dp & 0x40) dispreg = 0; + if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; } + if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; } + base += disp; + + if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; } + if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; } + + if (!(dp & 4)) base += dispreg; + if ((dp & 3) && !safemode) base = get_ilong_debug (base); + if (dp & 4) base += dispreg; + + addr = base + outer; + _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name, + dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', + 1 << ((dp >> 9) & 3), + disp, outer, addr); + } else { + addr = m68k_areg (regs, reg) + (uae_s32)((uae_s8)disp8) + dispreg; + _stprintf (buffer, _T("(A%d, %c%d.%c*%d, $%02x) == $%08x"), reg, + dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', + 1 << ((dp >> 9) & 3), disp8, addr); + } + break; + case PC16: + disp16 = get_iword_debug (pc); pc += 2; + addr += (uae_s16)disp16; + _stprintf (buffer, _T("(PC,$%04x) == $%08x"), disp16 & 0xffff, addr); + break; + case PC8r: + dp = get_iword_debug (pc); pc += 2; + disp8 = dp & 0xFF; + r = (dp & 0x7000) >> 12; + dispreg = dp & 0x8000 ? m68k_areg (regs, r) : m68k_dreg (regs, r); + if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg); + dispreg <<= (dp >> 9) & 3; + + if (dp & 0x100) { + uae_s32 outer = 0, disp = 0; + uae_s32 base = addr; + TCHAR name[10]; + _stprintf (name, _T("PC, ")); + if (dp & 0x80) { base = 0; name[0] = 0; } + if (dp & 0x40) dispreg = 0; + if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; } + if ((dp & 0x30) == 0x30) { disp = get_ilong_debug (pc); pc += 4; } + base += disp; + + if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_debug (pc); pc += 2; } + if ((dp & 0x3) == 0x3) { outer = get_ilong_debug (pc); pc += 4; } + + if (!(dp & 4)) base += dispreg; + if ((dp & 3) && !safemode) base = get_ilong_debug (base); + if (dp & 4) base += dispreg; + + addr = base + outer; + _stprintf (buffer, _T("(%s%c%d.%c*%d+%d)+%d == $%08x"), name, + dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W', + 1 << ((dp >> 9) & 3), + disp, outer, addr); + } else { + addr += (uae_s32)((uae_s8)disp8) + dispreg; + _stprintf (buffer, _T("(PC, %c%d.%c*%d, $%02x) == $%08x"), dp & 0x8000 ? 'A' : 'D', + (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3), + disp8, addr); + } + break; + case absw: + addr = (uae_s32)(uae_s16)get_iword_debug (pc); + _stprintf (buffer, _T("$%08x"), addr); + pc += 2; + break; + case absl: + addr = get_ilong_debug (pc); + _stprintf (buffer, _T("$%08x"), addr); + pc += 4; + break; + case imm: + switch (size){ + case sz_byte: + _stprintf (buffer, _T("#$%02x"), (get_iword_debug (pc) & 0xff)); + pc += 2; + break; + case sz_word: + _stprintf (buffer, _T("#$%04x"), (get_iword_debug (pc) & 0xffff)); + pc += 2; + break; + case sz_long: + _stprintf(buffer, _T("#$%08x"), (get_ilong_debug(pc))); + pc += 4; + break; + case sz_single: + { + fptype fp; + to_single(&fp, get_ilong_debug(pc)); + _stprintf(buffer, _T("#%s"), fp_print(&fp)); + pc += 4; + } + break; + case sz_double: + { + fptype fp; + to_double(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4)); + _stprintf(buffer, _T("#%s"), fp_print(&fp)); + pc += 8; + } + break; + case sz_extended: + { + fptype fp; + to_exten(&fp, get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8)); + _stprintf(buffer, _T("#%s"), fp_print(&fp)); + pc += 12; + break; + } + case sz_packed: + _stprintf(buffer, _T("#$%08x%08x%08x"), get_ilong_debug(pc), get_ilong_debug(pc + 4), get_ilong_debug(pc + 8)); + pc += 12; + break; + default: + break; + } + break; + case imm0: + offset = (uae_s32)(uae_s8)get_iword_debug (pc); + _stprintf (buffer, _T("#$%02x"), (uae_u32)(offset & 0xff)); + addr = pc + 2 + offset; + pc += 2; + break; + case imm1: + offset = (uae_s32)(uae_s16)get_iword_debug (pc); + buffer[0] = 0; + _stprintf (buffer, _T("#$%04x"), (uae_u32)(offset & 0xffff)); + addr = pc + offset; + pc += 2; + break; + case imm2: + offset = (uae_s32)get_ilong_debug (pc); + _stprintf (buffer, _T("#$%08x"), (uae_u32)offset); + addr = pc + offset; + pc += 4; + break; + case immi: + offset = (uae_s32)(uae_s8)(reg & 0xff); + _stprintf (buffer, _T("#$%08x"), (uae_u32)offset); + addr = pc + offset; + break; + default: + break; + } + if (buf == 0) + f_out (f, _T("%s"), buffer); + else + _tcscat (buf, buffer); + if (eaddr) + *eaddr = addr; + return pc; +} + +void REGPARAM2 MakeSR (void) +{ + regs.sr = ((regs.t1 << 15) | (regs.t0 << 14) + | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8) + | (GET_XFLG () << 4) | (GET_NFLG () << 3) + | (GET_ZFLG () << 2) | (GET_VFLG () << 1) + | GET_CFLG ()); +} + +void REGPARAM2 MakeFromSR (void) +{ + int oldm = regs.m; + int olds = regs.s; + + SET_XFLG ((regs.sr >> 4) & 1); + SET_NFLG ((regs.sr >> 3) & 1); + SET_ZFLG ((regs.sr >> 2) & 1); + SET_VFLG ((regs.sr >> 1) & 1); + SET_CFLG (regs.sr & 1); + if (regs.t1 == ((regs.sr >> 15) & 1) && + regs.t0 == ((regs.sr >> 14) & 1) && + regs.s == ((regs.sr >> 13) & 1) && + regs.m == ((regs.sr >> 12) & 1) && + regs.intmask == ((regs.sr >> 8) & 7)) + return; + regs.t1 = (regs.sr >> 15) & 1; + regs.t0 = (regs.sr >> 14) & 1; + regs.s = (regs.sr >> 13) & 1; + regs.m = (regs.sr >> 12) & 1; + regs.intmask = (regs.sr >> 8) & 7; + if (currprefs.cpu_model >= 68020) { + if (olds != regs.s) { + if (olds) { + if (oldm) + regs.msp = m68k_areg (regs, 7); + else + regs.isp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.usp; + } else { + regs.usp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp; + } + } else if (olds && oldm != regs.m) { + if (oldm) { + regs.msp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.isp; + } else { + regs.isp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.msp; + } + } + } else { + regs.t0 = regs.m = 0; + if (olds != regs.s) { + if (olds) { + regs.isp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.usp; + } else { + regs.usp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.isp; + } + } + } + if (currprefs.mmu_model) + mmu_set_super (regs.s != 0); + + doint (); + if (regs.t1 || regs.t0) + set_special (SPCFLAG_TRACE); + else + /* Keep SPCFLAG_DOTRACE, we still want a trace exception for + SR-modifying instructions (including STOP). */ + unset_special (SPCFLAG_TRACE); +} + +static void exception_check_trace (int nr) +{ + unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE); + if (regs.t1 && !regs.t0) { + /* trace stays pending if exception is div by zero, chk, + * trapv or trap #x + */ + if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47)) + set_special (SPCFLAG_DOTRACE); + } + regs.t1 = regs.t0 = 0; +} + +static void exception_debug (int nr) +{ +#ifdef DEBUGGER + if (!exception_debugging) + return; + printf ("Exception %d, PC=%08X\n", nr, M68K_GETPC); + DebugUI(); +#endif +} + +void cpu_halt (int e) +{ + write_log("HALT!"); + DebugUI(); +} + +static void Exception_build_stack_frame (uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format) +{ + int i; + +#if 0 + if (nr < 24 || nr > 31) { // do not print debugging for interrupts + write_log(_T("Building exception stack frame (format %X)\n"), format); + } +#endif + + switch (format) { + case 0x0: // four word stack frame + case 0x1: // throwaway four word stack frame + break; + case 0x2: // six word stack frame + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), oldpc); + break; + case 0x3: // floating point post-instruction stack frame (68040) + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.fp_ea); + break; + case 0x7: // access error stack frame (68040) + + for (i = 3; i >= 0; i--) { + // WB1D/PD0,PD1,PD2,PD3 + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mmu040_move16[i]); + } + + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), 0); // WB1A + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), 0); // WB2D + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.wb2_address); // WB2A + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.wb3_data); // WB3D + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // WB3A + + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // FA + + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), regs.wb2_status); + regs.wb2_status = 0; + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), regs.wb3_status); + regs.wb3_status = 0; + + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), ssw); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.mmu_effective_addr); + break; + case 0x9: // coprocessor mid-instruction stack frame (68020, 68030) + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.fp_ea); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.fp_opword); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), oldpc); + break; + case 0x8: // bus and address error stack frame (68010) + write_log(_T("Exception stack frame format %X not implemented\n"), format); + return; + case 0x4: // floating point unimplemented stack frame (68LC040, 68EC040) + // or 68060 bus access fault stack frame + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), ssw); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), oldpc); + break; + case 0xB: // long bus cycle fault stack frame (68020, 68030) + // We always use B frame because it is easier to emulate, + // our PC always points at start of instruction but A frame assumes + // it is + 2 and handling this properly is not easy. + // Store state information to internal register space + for (i = 0; i < mmu030_idx + 1; i++) { + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mmu030_ad[i].val); + } + while (i < 9) { + uae_u32 v = 0; + m68k_areg (regs, 7) -= 4; + // mmu030_idx is always small enough if instruction is FMOVEM. + if (mmu030_state[1] & MMU030_STATEFLAG1_FMOVEM) { + if (i == 7) + v = mmu030_fmovem_store[0]; + else if (i == 8) + v = mmu030_fmovem_store[1]; + } + x_put_long (m68k_areg (regs, 7), v); + i++; + } + // version & internal information (We store index here) + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), mmu030_idx); + // 3* internal registers + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), mmu030_state[2]); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), mmu030_state[1]); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), mmu030_state[0]); + // data input buffer = fault address + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); + // 2xinternal + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); + // stage b address + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mm030_stageb_address); + // 2xinternal + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mmu030_disp_store[1]); + /* fall through */ + case 0xA: // short bus cycle fault stack frame (68020, 68030) + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mmu030_disp_store[0]); + m68k_areg (regs, 7) -= 4; + // Data output buffer = value that was going to be written + x_put_long (m68k_areg (regs, 7), (mmu030_state[1] & MMU030_STATEFLAG1_MOVEM1) ? mmu030_data_buffer : mmu030_ad[mmu030_idx].val); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), mmu030_opcode); // Internal register (opcode storage) + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), regs.mmu_fault_addr); // data cycle fault address + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage B + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); // Instr. pipe stage C + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), ssw); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), 0); // Internal register + break; + default: + write_log(_T("Unknown exception stack frame format: %X\n"), format); + return; + } + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), (format << 12) | (nr * 4)); + m68k_areg (regs, 7) -= 4; + x_put_long (m68k_areg (regs, 7), currpc); + m68k_areg (regs, 7) -= 2; + x_put_word (m68k_areg (regs, 7), regs.sr); +} + + +// 68030 MMU +static void Exception_mmu030 (int nr, uaecptr oldpc) +{ + uae_u32 currpc = m68k_getpc (), newpc; + + exception_debug (nr); + MakeSR (); + + if (!regs.s) { + regs.usp = m68k_areg (regs, 7); + m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp; + regs.s = 1; + mmu_set_super (1); + } + +#if 0 + if (nr < 24 || nr > 31) { // do not print debugging for interrupts + write_log (_T("Exception_mmu030: Exception %i: %08x %08x %08x\n"), + nr, currpc, oldpc, regs.mmu_fault_addr); + } +#endif + +#if 0 + write_log (_T("Exception %d -> %08x\n", nr, newpc)); +#endif + + + newpc = x_get_long (regs.vbr + 4 * nr); + + if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */ + Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0); + MakeSR(); /* this sets supervisor bit in status reg */ + regs.m = 0; /* clear the M bit (but frame 0x1 uses sr with M bit set) */ + regs.msp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.isp; + Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1); + } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9 || nr == 56) { + Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x2); + } else if (nr == 2) { + Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0xB); + } else if (nr == 3) { + regs.mmu_fault_addr = last_fault_for_exception_3; + mmu030_state[0] = mmu030_state[1] = 0; + mmu030_data_buffer = 0; + Exception_build_stack_frame (last_fault_for_exception_3, currpc, MMU030_SSW_RW | MMU030_SSW_SIZE_W | (regs.s ? 6 : 2), nr, 0xA); + } else if (nr >= 48 && nr < 55) { + if (regs.fpu_exp_pre) { + Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0); + } else { /* mid-instruction */ + Exception_build_stack_frame(regs.fpiar, currpc, 0, nr, 0x9); + } + } else { + Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x0); + } + + if (newpc & 1) { + if (nr == 2 || nr == 3) + cpu_halt (2); + else + exception3_read(regs.ir, newpc); + return; + } + m68k_setpci (newpc); + exception_check_trace (nr); +} + + +// 68040 MMU +static void Exception_mmu (int nr, uaecptr oldpc) +{ + uae_u32 currpc = m68k_getpc (), newpc; + + exception_debug (nr); + MakeSR (); + + if (!regs.s) { + regs.usp = m68k_areg (regs, 7); + if (currprefs.cpu_model >= 68020 && currprefs.cpu_model < 68060) { + m68k_areg (regs, 7) = regs.m ? regs.msp : regs.isp; + } else { + m68k_areg (regs, 7) = regs.isp; + } + regs.s = 1; + mmu_set_super (1); + } + + newpc = x_get_long (regs.vbr + 4 * nr); +#if 0 + write_log (_T("Exception %d: %08x -> %08x\n"), nr, currpc, newpc); +#endif + + if (nr == 2) { // bus error + //write_log (_T("Exception_mmu %08x %08x %08x\n"), currpc, oldpc, regs.mmu_fault_addr); + if (currprefs.mmu_model == 68040) + Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x7); + else + Exception_build_stack_frame(regs.mmu_fault_addr, currpc, regs.mmu_fslw, nr, 0x4); + } else if (nr == 3) { // address error + Exception_build_stack_frame(last_fault_for_exception_3, currpc, 0, nr, 0x2); + write_log (_T("Exception %d (%x) at %x!\n"), nr, last_fault_for_exception_3, currpc); + } else if (nr == 5 || nr == 6 || nr == 7 || nr == 9) { + Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x2); + } else if (regs.m && nr >= 24 && nr < 32) { /* M + Interrupt */ + Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0); + MakeSR(); /* this sets supervisor bit in status reg */ + regs.m = 0; /* clear the M bit (but frame 0x1 uses sr with M bit set) */ + regs.msp = m68k_areg (regs, 7); + m68k_areg (regs, 7) = regs.isp; + Exception_build_stack_frame (oldpc, currpc, regs.mmu_ssw, nr, 0x1); + } else if (nr == 60 || nr == 61) { + Exception_build_stack_frame(oldpc, regs.instruction_pc, regs.mmu_ssw, nr, 0x0); + } else if (nr >= 48 && nr <= 55) { + if (regs.fpu_exp_pre) { + if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real + Exception_build_stack_frame(regs.fp_ea, regs.instruction_pc, 0, nr, 0x2); + } else { + Exception_build_stack_frame(oldpc, regs.instruction_pc, 0, nr, 0x0); + } + } else { /* post-instruction */ + if (currprefs.cpu_model == 68060 && nr == 55 && regs.fp_unimp_pend == 2) { // packed decimal real + Exception_build_stack_frame(regs.fp_ea, currpc, 0, nr, 0x2); + } else { + Exception_build_stack_frame(oldpc, currpc, 0, nr, 0x3); + } + } + } else if (nr == 11 && regs.fp_unimp_ins) { + regs.fp_unimp_ins = false; + if ((currprefs.cpu_model == 68060 && (currprefs.fpu_model == 0 || (regs.pcr & 2))) || + (currprefs.cpu_model == 68040 && currprefs.fpu_model == 0)) { + Exception_build_stack_frame(regs.fp_ea, currpc, regs.instruction_pc, nr, 0x4); + } else { + Exception_build_stack_frame(regs.fp_ea, currpc, regs.mmu_ssw, nr, 0x2); + } + } else { + Exception_build_stack_frame(oldpc, currpc, regs.mmu_ssw, nr, 0x0); + } + + if (newpc & 1) { + if (nr == 2 || nr == 3) + cpu_halt (2); + else + exception3_read (regs.ir, newpc); + return; + } + m68k_setpci (newpc); + exception_check_trace (nr); +} + + +/* Handle exceptions. */ +static void ExceptionX (int nr, uaecptr address) +{ + if (currprefs.cpu_model == 68030) + Exception_mmu030 (nr, m68k_getpc ()); + else + Exception_mmu (nr, m68k_getpc ()); +} + +void REGPARAM2 Exception (int nr) +{ + ExceptionX (nr, -1); +} +void REGPARAM2 ExceptionL (int nr, uaecptr address) +{ + ExceptionX (nr, address); +} + +static void do_interrupt (int nr, int Pending) +{ + regs.stopped = 0; + unset_special (SPCFLAG_STOP); + assert (nr < 8 && nr >= 0); + + /* On Hatari, only video ints are using SPCFLAG_INT (see m68000.c) */ + Exception (nr + 24); + + regs.intmask = nr; + doint (); + + set_special (SPCFLAG_INT); +} + + +void m68k_reset (int hardreset) +{ + regs.spcflags &= (SPCFLAG_MODE_CHANGE | SPCFLAG_BRK); + regs.ipl = regs.ipl_pin = 0; + regs.s = 1; + regs.m = 0; + regs.stopped = 0; + regs.t1 = 0; + regs.t0 = 0; + SET_ZFLG (0); + SET_XFLG (0); + SET_CFLG (0); + SET_VFLG (0); + SET_NFLG (0); + regs.intmask = 7; + regs.vbr = regs.sfc = regs.dfc = 0; + regs.irc = 0xffff; + + m68k_areg (regs, 7) = get_long (0); + m68k_setpc (get_long (4)); + + fpu_reset (); + + regs.caar = regs.cacr = 0; + regs.itt0 = regs.itt1 = regs.dtt0 = regs.dtt1 = 0; + regs.tcr = regs.mmusr = regs.urp = regs.srp = regs.buscr = 0; + + mmufixup[0].reg = -1; + mmufixup[1].reg = -1; + if (currprefs.mmu_model) { + if (currprefs.cpu_model >= 68040) { + mmu_reset (); + mmu_set_tc (regs.tcr); + mmu_set_super (regs.s != 0); + } + else { + mmu030_reset(hardreset); + } + } + + regs.pcr = 0; +} + +void REGPARAM2 op_unimpl (uae_u16 opcode) +{ + static int warned; + if (warned < 20) { + write_log (_T("68060 unimplemented opcode %04X, PC=%08x\n"), opcode, regs.instruction_pc); + warned++; + } + ExceptionL (61, regs.instruction_pc); +} + +uae_u32 REGPARAM2 op_illg (uae_u32 opcode) +{ + uaecptr pc = m68k_getpc (); + static int warned; + + if (warned < 20) { + write_log ("Illegal instruction: %04x at %08X\n", opcode, pc); + warned++; + } + + if ((opcode & 0xF000)==0xA000) + Exception (10); + else + if ((opcode & 0xF000)==0xF000) + Exception (11); + else + Exception (4); + return 4; +} + +#ifdef CPUEMU_0 + +// 68030 (68851) MMU instructions only +bool mmu_op30 (uaecptr pc, uae_u32 opcode, uae_u16 extra, uaecptr extraa) +{ + bool fline = false; + + if (extra & 0x8000) { + fline = mmu_op30_ptest (pc, opcode, extra, extraa); + } else if ((extra&0xE000)==0x2000 && (extra & 0x1C00)) { + fline = mmu_op30_pflush (pc, opcode, extra, extraa); + } else if ((extra&0xE000)==0x2000 && !(extra & 0x1C00)) { + fline = mmu_op30_pload (pc, opcode, extra, extraa); + } else { + fline = mmu_op30_pmove (pc, opcode, extra, extraa); + } + + if (fline) { + m68k_setpc(pc); + op_illg(opcode); + } + return fline; +} + +void mmu_op (uae_u32 opcode, uae_u32 extra) +{ + if (currprefs.cpu_model) { + mmu_op_real (opcode, extra); + return; + } +#if MMUOP_DEBUG > 1 + write_log ("mmu_op %04X PC=%08X\n", opcode, m68k_getpc ()); +#endif + if ((opcode & 0xFE0) == 0x0500) { + /* PFLUSH */ + regs.mmusr = 0; +#if MMUOP_DEBUG > 0 + write_log ("PFLUSH\n"); +#endif + return; + } else if ((opcode & 0x0FD8) == 0x548) { + if (currprefs.cpu_model < 68060) { /* PTEST not in 68060 */ + /* PTEST */ +#if MMUOP_DEBUG > 0 + write_log ("PTEST\n"); +#endif + return; + } + } +#if MMUOP_DEBUG > 0 + write_log ("Unknown MMU OP %04X\n", opcode); +#endif + m68k_setpc (m68k_getpc () - 2); + op_illg (opcode); +} + +#endif + +static uaecptr last_trace_ad = 0; + +static void do_trace (void) +{ + if (regs.t0 && currprefs.cpu_model >= 68020) { + uae_u16 opcode; + /* should also include TRAP, CHK, SR modification FPcc */ + /* probably never used so why bother */ + /* We can afford this to be inefficient... */ + m68k_setpc (m68k_getpc ()); + opcode = x_get_word (regs.pc); + if (opcode == 0x4e73 /* RTE */ + || opcode == 0x4e74 /* RTD */ + || opcode == 0x4e75 /* RTS */ + || opcode == 0x4e77 /* RTR */ + || opcode == 0x4e76 /* TRAPV */ + || (opcode & 0xffc0) == 0x4e80 /* JSR */ + || (opcode & 0xffc0) == 0x4ec0 /* JMP */ + || (opcode & 0xff00) == 0x6100 /* BSR */ + || ((opcode & 0xf000) == 0x6000 /* Bcc */ + && cctrue ((opcode >> 8) & 0xf)) + || ((opcode & 0xf0f0) == 0x5050 /* DBcc */ + && !cctrue ((opcode >> 8) & 0xf) + && (uae_s16)m68k_dreg (regs, opcode & 7) != 0)) + { + last_trace_ad = m68k_getpc (); + unset_special (SPCFLAG_TRACE); + set_special (SPCFLAG_DOTRACE); + } + } else if (regs.t1) { + last_trace_ad = m68k_getpc (); + unset_special (SPCFLAG_TRACE); + set_special (SPCFLAG_DOTRACE); + } +} + +void doint (void) +{ + if (currprefs.cpu_compatible) + set_special (SPCFLAG_INT); + else + set_special (SPCFLAG_DOINT); +} + +#define IDLETIME (currprefs.cpu_idle * sleep_resolution / 700) + +/* + * Handle special flags + */ + +static int do_specialties (int cycles) +{ + if (regs.spcflags & SPCFLAG_DOTRACE) + Exception (9); + + /* Handle the STOP instruction */ + if ( regs.spcflags & SPCFLAG_STOP ) { + while (regs.spcflags & SPCFLAG_STOP) { + + /* Take care of quit event if needed */ + if (regs.spcflags & SPCFLAG_BRK) + return 1; + + M68000_AddCycles(cpu_cycles); + + /* It is possible one or more ints happen at the same time */ + /* We must process them during the same cpu cycle until the special INT flag is set */ + while (PendingInterrupt.time <=0 && PendingInterrupt.pFunction) { + /* 1st, we call the interrupt handler */ + CALL_VAR(PendingInterrupt.pFunction); + + if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) { + unset_special (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE); + // SPCFLAG_BRK breaks STOP condition, need to prefetch + m68k_resumestopped (); + return 1; + } + + if (currprefs.cpu_idle && ((regs.spcflags & SPCFLAG_STOP)) == SPCFLAG_STOP) { + /* sleep 1ms if STOP-instruction is executed */ + if (1) { + static int sleepcnt, lvpos; + if (vpos != lvpos) { + sleepcnt--; + lvpos = vpos; + if (sleepcnt < 0) { + /*sleepcnt = IDLETIME / 2; */ /* Laurent : badly removed for now */ + host_sleep_ms(1); + } + } + } + } + } + } + } + + if (regs.spcflags & SPCFLAG_TRACE) + do_trace (); + + if (regs.spcflags & SPCFLAG_DOINT) { + unset_special (SPCFLAG_DOINT); + set_special (SPCFLAG_INT); + } + + if (regs.spcflags & SPCFLAG_DEBUGGER) + DebugCpu_Check(); + + if ((regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE))) { + unset_special(SPCFLAG_MODE_CHANGE); + return 1; + } + + return 0; +} + +#ifndef CPUEMU_0 + +#else + +static int lastRegsS = 0; + +// Previous MMU 68030 +static void m68k_run_mmu030 (void) +{ + uae_u16 opcode; + uaecptr pc; + struct flag_struct f; + f.cznv = 0; + f.x = 0; + int intr = 0; + int lastintr = 0; + mmu030_opcode_stageb = -1; +retry: + TRY (prb) { + for (;;) { + int cnt; +insretry: + pc = regs.instruction_pc = m68k_getpc (); + f.cznv = regflags.cznv; + f.x = regflags.x; + + mmu030_state[0] = mmu030_state[1] = mmu030_state[2] = 0; + mmu030_opcode = -1; + if (mmu030_opcode_stageb < 0) { + opcode = get_iword_mmu030 (0); + } else { + opcode = mmu030_opcode_stageb; + mmu030_opcode_stageb = -1; + } + + mmu030_opcode = opcode; + mmu030_ad[0].done = false; + + Uint64 beforeCycles = nCyclesMainCounter; + cnt = 50; + for (;;) { + opcode = mmu030_opcode; + mmu030_idx = 0; + mmu030_retry = false; + cpu_cycles = (*cpufunctbl[opcode])(opcode); + cnt--; // so that we don't get in infinite loop if things go horribly wrong + if (!mmu030_retry) + break; + if (cnt < 0) { + cpu_halt (9); + break; + } + if (mmu030_retry && mmu030_opcode == -1) + goto insretry; // urgh + } + + mmu030_opcode = -1; + + M68000_AddCycles(cpu_cycles); + cpu_cycles = nCyclesMainCounter - beforeCycles; + + DSP_Run(cpu_cycles); + i860_Run(cpu_cycles); + + /* We can have several interrupts at the same time before the next CPU instruction */ + /* We must check for pending interrupt and call do_specialties_interrupt() only */ + /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ + /* and prevent exiting the STOP state when calling do_specialties() after. */ + /* For performance, we first test PendingInterruptCount, then regs.spcflags */ + while ( ( PendingInterrupt.time <= 0 ) && ( PendingInterrupt.pFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { + CALL_VAR(PendingInterrupt.pFunction); /* call the interrupt handler */ + } + + /* Previous: for now we poll the interrupt pins with every instruction. + * TODO: only do this when an actual interrupt is active to not + * unneccessarily slow down emulation. + */ + intr = intlev (); + if (intr>regs.intmask || (intr==7 && intr>lastintr)) + do_interrupt (intr, false); + lastintr = intr; + + if(lastRegsS != regs.s) { + host_realtime(!(regs.s)); + lastRegsS = regs.s; + } + + if (regs.spcflags & ~SPCFLAG_INT) { + if (do_specialties (cpu_cycles)) + return; + } + } + } CATCH (prb) { + + regflags.cznv = f.cznv; + regflags.x = f.x; + + m68k_setpci (regs.instruction_pc); + + if (mmufixup[0].reg >= 0) { + m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; + mmufixup[0].reg = -1; + } + if (mmufixup[1].reg >= 0) { + m68k_areg (regs, mmufixup[1].reg) = mmufixup[1].value; + mmufixup[1].reg = -1; + } + + TRY (prb2) { + Exception (prb); + } CATCH (prb2) { + write_log("[FATAL] double fault\n"); + m68k_reset (1); // auto-reset CPU + //cpu_halt (1); + return; + } ENDTRY + } ENDTRY + goto retry; +} + +/* Aranym MMU 68040 */ +static void m68k_run_mmu040 (void) +{ + uae_u16 opcode; + struct flag_struct f; + f.cznv = 0; + f.x = 0; + uaecptr pc; + int intr = 0; + int lastintr = 0; + + for (;;) { + TRY (prb) { + for (;;) { + f.cznv = regflags.cznv; + f.x = regflags.x; + mmu_restart = true; + pc = regs.instruction_pc = m68k_getpc (); + + Uint64 beforeCycles = nCyclesMainCounter; + mmu_opcode = -1; + mmu_opcode = opcode = x_prefetch (0); + cpu_cycles = (*cpufunctbl[opcode])(opcode); + M68000_AddCycles(cpu_cycles); + + cpu_cycles = nCyclesMainCounter - beforeCycles; + + DSP_Run(cpu_cycles); + i860_Run(cpu_cycles); + + /* We can have several interrupts at the same time before the next CPU instruction */ + /* We must check for pending interrupt and call do_specialties_interrupt() only */ + /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */ + /* and prevent exiting the STOP state when calling do_specialties() after. */ + /* For performance, we first test PendingInterruptCount, then regs.spcflags */ + while ( ( PendingInterrupt.time <= 0 ) && ( PendingInterrupt.pFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) ) { + CALL_VAR(PendingInterrupt.pFunction); /* call the interrupt handler */ + } + + /* Previous: for now we poll the interrupt pins with every instruction. + * TODO: only do this when an actual interrupt is active to not + * unneccessarily slow down emulation. + */ + intr = intlev (); + if (intr>regs.intmask || (intr==7 && intr>lastintr)) + do_interrupt (intr, false); + lastintr = intr; + + if(lastRegsS != regs.s) { + host_realtime(!(regs.s)); + lastRegsS = regs.s; + } + + if (regs.spcflags & ~SPCFLAG_INT) { + if (do_specialties (cpu_cycles)) + return; + } + } // end of for(;;) + } CATCH (prb) { + + if (mmu_restart) { + /* restore state if instruction restart */ + regflags.cznv = f.cznv; + regflags.x = f.x; + m68k_setpci (regs.instruction_pc); + } + + if (mmufixup[0].reg >= 0) { + m68k_areg (regs, mmufixup[0].reg) = mmufixup[0].value; + mmufixup[0].reg = -1; + } + + TRY (prb2) { + Exception (prb); + } CATCH (prb2) { + write_log("[FATAL] double fault\n"); + m68k_reset (1); // auto-reset CPU + //cpu_halt (1); + return; + } ENDTRY + + } ENDTRY + } +} + +#endif /* CPUEMU_0 */ + +int in_m68k_go = 0; + +#if 0 +static void exception2_handle (uaecptr addr, uaecptr fault) +{ + last_addr_for_exception_3 = addr; + last_fault_for_exception_3 = fault; + last_writeaccess_for_exception_3 = 0; + last_instructionaccess_for_exception_3 = 0; + Exception (2); +} +#endif + +void m68k_go (int may_quit) +{ + int hardboot = 1; + + if (in_m68k_go || !may_quit) { + write_log ("Bug! m68k_go is not reentrant.\n"); + DebugUI(); + } + + in_m68k_go++; + for (;;) { + void (*run_func)(void); + + if (regs.spcflags & SPCFLAG_BRK) { + unset_special(SPCFLAG_BRK); + break; + } + + quit_program = 0; + hardboot = 0; + +#ifdef DEBUGGER + if (debugging) + debug (); +#endif + + set_x_funcs (); + run_func=currprefs.cpu_model == 68040 ? m68k_run_mmu040 : m68k_run_mmu030; + run_func (); + } + in_m68k_go--; +} + + +#if 1 +TCHAR* buf_out (TCHAR *buffer, int *bufsize, const TCHAR *format, ...) +{ + va_list parms; + + if (buffer == NULL) + { + return NULL; + } + + va_start (parms, format); + vsnprintf (buffer, (*bufsize) - 1, format, parms); + va_end (parms); + *bufsize -= _tcslen (buffer); + + return buffer + _tcslen (buffer); +} +#endif + +static const TCHAR *ccnames[] = +{ + _T("T "),_T("F "),_T("HI"),_T("LS"),_T("CC"),_T("CS"),_T("NE"),_T("EQ"), + _T("VC"),_T("VS"),_T("PL"),_T("MI"),_T("GE"),_T("LT"),_T("GT"),_T("LE") +}; +static const TCHAR *fpccnames[] = +{ + _T("F"), + _T("EQ"), + _T("OGT"), + _T("OGE"), + _T("OLT"), + _T("OLE"), + _T("OGL"), + _T("OR"), + _T("UN"), + _T("UEQ"), + _T("UGT"), + _T("UGE"), + _T("ULT"), + _T("ULE"), + _T("NE"), + _T("T"), + _T("SF"), + _T("SEQ"), + _T("GT"), + _T("GE"), + _T("LT"), + _T("LE"), + _T("GL"), + _T("GLE"), + _T("NGLE"), + _T("NGL"), + _T("NLE"), + _T("NLT"), + _T("NGE"), + _T("NGT"), + _T("SNE"), + _T("ST") +}; +static const TCHAR *fpuopcodes[] = +{ + _T("FMOVE"), + _T("FINT"), + _T("FSINH"), + _T("FINTRZ"), + _T("FSQRT"), + NULL, + _T("FLOGNP1"), + NULL, + _T("FETOXM1"), + _T("FTANH"), + _T("FATAN"), + NULL, + _T("FASIN"), + _T("FATANH"), + _T("FSIN"), + _T("FTAN"), + _T("FETOX"), // 0x10 + _T("FTWOTOX"), + _T("FTENTOX"), + NULL, + _T("FLOGN"), + _T("FLOG10"), + _T("FLOG2"), + NULL, + _T("FABS"), + _T("FCOSH"), + _T("FNEG"), + NULL, + _T("FACOS"), + _T("FCOS"), + _T("FGETEXP"), + _T("FGETMAN"), + _T("FDIV"), // 0x20 + _T("FMOD"), + _T("FADD"), + _T("FMUL"), + _T("FSGLDIV"), + _T("FREM"), + _T("FSCALE"), + _T("FSGLMUL"), + _T("FSUB"), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + _T("FSINCOS"), // 0x30 + _T("FSINCOS"), + _T("FSINCOS"), + _T("FSINCOS"), + _T("FSINCOS"), + _T("FSINCOS"), + _T("FSINCOS"), + _T("FSINCOS"), + _T("FCMP"), + NULL, + _T("FTST"), + NULL, + NULL, + NULL, + NULL, + NULL +}; + +static const TCHAR *movemregs[] = +{ + _T("D0"), + _T("D1"), + _T("D2"), + _T("D3"), + _T("D4"), + _T("D5"), + _T("D6"), + _T("D7"), + _T("A0"), + _T("A1"), + _T("A2"), + _T("A3"), + _T("A4"), + _T("A5"), + _T("A6"), + _T("A7"), + _T("FP0"), + _T("FP1"), + _T("FP2"), + _T("FP3"), + _T("FP4"), + _T("FP5"), + _T("FP6"), + _T("FP7"), + _T("FPIAR"), + _T("FPSR"), + _T("FPCR") +}; + +static void addmovemreg (TCHAR *out, int *prevreg, int *lastreg, int *first, int reg, int fpmode) +{ + TCHAR *p = out + _tcslen (out); + if (*prevreg < 0) { + *prevreg = reg; + *lastreg = reg; + return; + } + if (reg < 0 || fpmode == 2 || (*prevreg) + 1 != reg || (reg & 8) != ((*prevreg & 8))) { + _stprintf (p, _T("%s%s"), (*first) ? _T("") : _T("/"), movemregs[*lastreg]); + p = p + _tcslen (p); + if (*lastreg != *prevreg) { + if ((*lastreg) + 2 == reg) { + _stprintf(p, _T("/%s"), movemregs[*prevreg]); + } else if ((*lastreg) != (*prevreg)) { + _stprintf(p, _T("-%s"), movemregs[*prevreg]); + } + } + *lastreg = reg; + *first = 0; + } + *prevreg = reg; +} + +static void movemout (TCHAR *out, uae_u16 mask, int mode, int fpmode) +{ + unsigned int dmask, amask; + int prevreg = -1, lastreg = -1, first = 1; + int i; + + if (mode == Apdi && !fpmode) { + uae_u8 dmask2; + uae_u8 amask2; + + amask2 = mask & 0xff; + dmask2 = (mask >> 8) & 0xff; + dmask = 0; + amask = 0; + for (i = 0; i < 8; i++) { + if (dmask2 & (1 << i)) + dmask |= 1 << (7 - i); + if (amask2 & (1 << i)) + amask |= 1 << (7 - i); + } + } else { + dmask = mask & 0xff; + amask = (mask >> 8) & 0xff; + if (fpmode == 1 && mode != Apdi) { + uae_u8 dmask2 = dmask; + dmask = 0; + for (i = 0; i < 8; i++) { + if (dmask2 & (1 << i)) + dmask |= 1 << (7 - i); + } + } + } + if (fpmode) { + while (dmask) { addmovemreg(out, &prevreg, &lastreg, &first, movem_index1[dmask] + (fpmode == 2 ? 24 : 16), fpmode); dmask = movem_next[dmask]; } + } else { + while (dmask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[dmask], fpmode); dmask = movem_next[dmask]; } + while (amask) { addmovemreg (out, &prevreg, &lastreg, &first, movem_index1[amask] + 8, fpmode); amask = movem_next[amask]; } + } + addmovemreg(out, &prevreg, &lastreg, &first, -1, fpmode); +} + +static const TCHAR *fpsizes[] = { + _T("L"), + _T("S"), + _T("X"), + _T("P"), + _T("W"), + _T("D"), + _T("B"), + _T("P") +}; +static const int fpsizeconv[] = { + sz_long, + sz_single, + sz_extended, + sz_packed, + sz_word, + sz_double, + sz_byte, + sz_packed +}; + +static void disasm_size (TCHAR *instrname, struct instr *dp) +{ + if (dp->unsized) { + _tcscat(instrname, _T(" ")); + return; + } + switch (dp->size) + { + case sz_byte: + _tcscat (instrname, _T(".B ")); + break; + case sz_word: + _tcscat (instrname, _T(".W ")); + break; + case sz_long: + _tcscat (instrname, _T(".L ")); + break; + default: + _tcscat (instrname, _T(" ")); + break; + } +} + +void m68k_disasm_2 (TCHAR *buf, int bufsize, uaecptr pc, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr, int safemode) +{ + uae_u32 seaddr2; + uae_u32 deaddr2; + + if (buf) + memset (buf, 0, bufsize * sizeof (TCHAR)); + if (!table68k) + return; + while (cnt-- > 0) { + TCHAR instrname[100], *ccpt; + int i; + uae_u32 opcode; + uae_u16 extra; + struct mnemolookup *lookup; + struct instr *dp; + uaecptr oldpc; + uaecptr m68kpc_illg = 0; + bool illegal = false; + + seaddr2 = deaddr2 = 0; + oldpc = pc; + opcode = get_word_debug (pc); + extra = get_word_debug (pc + 2); + if (cpufunctbl[opcode] == op_illg_1 || cpufunctbl[opcode] == op_unimpl_1) { + m68kpc_illg = pc + 2; + illegal = true; + } + + dp = table68k + opcode; + if (dp->mnemo == i_ILLG) { + illegal = false; + opcode = 0x4AFC; + dp = table68k + opcode; + } + for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++) + ; + + buf = buf_out (buf, &bufsize, _T("%08X "), pc); + + pc += 2; + + if (lookup->friendlyname) + _tcscpy (instrname, lookup->friendlyname); + else + _tcscpy (instrname, lookup->name); + ccpt = _tcsstr (instrname, _T("cc")); + if (ccpt != 0) { + if ((opcode & 0xf000) == 0xf000) + _tcscpy (ccpt, fpccnames[extra & 0x1f]); + else + _tcsncpy (ccpt, ccnames[dp->cc], 2); + } + disasm_size (instrname, dp); + + if (lookup->mnemo == i_MOVEC2 || lookup->mnemo == i_MOVE2C) { + uae_u16 imm = extra; + uae_u16 creg = imm & 0x0fff; + uae_u16 r = imm >> 12; + TCHAR regs[16]; + const TCHAR *cname = _T("?"); + int i; + for (i = 0; m2cregs[i].regname; i++) { + if (m2cregs[i].regno == creg) + break; + } + _stprintf (regs, _T("%c%d"), r >= 8 ? 'A' : 'D', r >= 8 ? r - 8 : r); + if (m2cregs[i].regname) + cname = m2cregs[i].regname; + if (lookup->mnemo == i_MOVE2C) { + _tcscat (instrname, regs); + _tcscat (instrname, _T(",")); + _tcscat (instrname, cname); + } else { + _tcscat (instrname, cname); + _tcscat (instrname, _T(",")); + _tcscat (instrname, regs); + } + pc += 2; + } else if (lookup->mnemo == i_MVMEL) { + uae_u16 mask = extra; + pc += 2; + pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); + _tcscat (instrname, _T(",")); + movemout (instrname, mask, dp->dmode, 0); + } else if (lookup->mnemo == i_MVMLE) { + uae_u16 mask = extra; + pc += 2; + movemout(instrname, mask, dp->dmode, 0); + _tcscat(instrname, _T(",")); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); + } else if (lookup->mnemo == i_DIVL || lookup->mnemo == i_MULL) { + TCHAR *p; + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); + extra = get_word_debug(pc); + pc += 2; + p = instrname + _tcslen(instrname); + if (extra & 0x0400) + _stprintf(p, _T(",D%d:D%d"), extra & 7, (extra >> 12) & 7); + else + _stprintf(p, _T(",D%d"), (extra >> 12) & 7); + } else if (lookup->mnemo == i_MOVES) { + TCHAR *p; + pc += 2; + if (!(extra & 0x1000)) { + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); + p = instrname + _tcslen(instrname); + _stprintf(p, _T(",%c%d"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7); + } else { + p = instrname + _tcslen(instrname); + _stprintf(p, _T("%c%d,"), (extra & 0x8000) ? 'A' : 'D', (extra >> 12) & 7); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); + } + } else if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || + lookup->mnemo == i_BFCHG || lookup->mnemo == i_BFCLR || + lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS || + lookup->mnemo == i_BFSET || lookup->mnemo == i_BFTST) { + TCHAR *p; + int reg = -1; + + pc += 2; + p = instrname + _tcslen(instrname); + if (lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU || lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFINS) + reg = (extra >> 12) & 7; + if (lookup->mnemo == i_BFINS) + _stprintf(p, _T("D%d,"), reg); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &seaddr2, safemode); + _tcscat(instrname, _T(" {")); + p = instrname + _tcslen(instrname); + if (extra & 0x0800) + _stprintf(p, _T("D%d"), (extra >> 6) & 7); + else + _stprintf(p, _T("%d"), (extra >> 6) & 31); + _tcscat(instrname, _T(":")); + p = instrname + _tcslen(instrname); + if (extra & 0x0020) + _stprintf(p, _T("D%d"), extra & 7); + else + _stprintf(p, _T("%d"), extra & 31); + _tcscat(instrname, _T("}")); + p = instrname + _tcslen(instrname); + if (lookup->mnemo == i_BFFFO || lookup->mnemo == i_BFEXTS || lookup->mnemo == i_BFEXTU) + _stprintf(p, _T(",D%d"), reg); + } else if (lookup->mnemo == i_CPUSHA || lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || + lookup->mnemo == i_CINVA || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) { + if ((opcode & 0xc0) == 0xc0) + _tcscat(instrname, _T("BC")); + else if (opcode & 0x80) + _tcscat(instrname, _T("IC")); + else if (opcode & 0x40) + _tcscat(instrname, _T("DC")); + else + _tcscat(instrname, _T("?")); + if (lookup->mnemo == i_CPUSHL || lookup->mnemo == i_CPUSHP || lookup->mnemo == i_CINVL || lookup->mnemo == i_CINVP) { + TCHAR *p = instrname + _tcslen(instrname); + _stprintf(p, _T(",(A%d)"), opcode & 7); + } + } else if (lookup->mnemo == i_FPP) { + TCHAR *p; + int ins = extra & 0x3f; + int size = (extra >> 10) & 7; + + pc += 2; + if ((extra & 0xfc00) == 0x5c00) { // FMOVECR (=i_FPP with source specifier = 7) + fptype fp; + if (fpu_get_constant(&fp, extra & 0x3f)) + _stprintf(instrname, _T("FMOVECR.X #%s,FP%d"), fp_print(&fp), (extra >> 7) & 7); + else + _stprintf(instrname, _T("FMOVECR.X #?,FP%d"), (extra >> 7) & 7); + } else if ((extra & 0x8000) == 0x8000) { // FMOVEM + int dr = (extra >> 13) & 1; + int mode; + int dreg = (extra >> 4) & 7; + int regmask, fpmode; + + if (extra & 0x4000) { + mode = (extra >> 11) & 3; + regmask = extra & 0xff; // FMOVEM FPx + fpmode = 1; + _tcscpy(instrname, _T("FMOVEM.X ")); + } else { + mode = 0; + regmask = (extra >> 10) & 7; // FMOVEM control + fpmode = 2; + _tcscpy(instrname, _T("FMOVEM.L ")); + if (regmask == 1 || regmask == 2 || regmask == 4) + _tcscpy(instrname, _T("FMOVE.L ")); + } + p = instrname + _tcslen(instrname); + if (dr) { + if (mode & 1) + _stprintf(instrname, _T("D%d"), dreg); + else + movemout(instrname, regmask, dp->dmode, fpmode); + _tcscat(instrname, _T(",")); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); + } else { + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, deaddr, safemode); + _tcscat(instrname, _T(",")); + p = instrname + _tcslen(instrname); + if (mode & 1) + _stprintf(p, _T("D%d"), dreg); + else + movemout(p, regmask, dp->dmode, fpmode); + } + } else { + if (fpuopcodes[ins]) + _tcscpy(instrname, fpuopcodes[ins]); + else + _tcscpy(instrname, _T("F?")); + + if ((extra & 0xe000) == 0x6000) { // FMOVE to memory + int kfactor = extra & 0x7f; + _tcscpy(instrname, _T("FMOVE.")); + _tcscat(instrname, fpsizes[size]); + _tcscat(instrname, _T(" ")); + p = instrname + _tcslen(instrname); + _stprintf(p, _T("FP%d,"), (extra >> 7) & 7); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &deaddr2, safemode); + p = instrname + _tcslen(instrname); + if (size == 7) { + _stprintf(p, _T(" {D%d}"), (kfactor >> 4)); + } else if (kfactor) { + if (kfactor & 0x40) + kfactor |= ~0x3f; + _stprintf(p, _T(" {%d}"), kfactor); + } + } else { + if (extra & 0x4000) { // source is EA + _tcscat(instrname, _T(".")); + _tcscat(instrname, fpsizes[size]); + _tcscat(instrname, _T(" ")); + pc = ShowEA(0, pc, opcode, dp->dreg, dp->dmode, fpsizeconv[size], instrname, &seaddr2, safemode); + } else { // source is FPx + p = instrname + _tcslen(instrname); + _stprintf(p, _T(".X FP%d"), (extra >> 10) & 7); + } + p = instrname + _tcslen(instrname); + if ((extra & 0x4000) || (((extra >> 7) & 7) != ((extra >> 10) & 7))) + _stprintf(p, _T(",FP%d"), (extra >> 7) & 7); + if (ins >= 0x30 && ins < 0x38) { // FSINCOS + p = instrname + _tcslen(instrname); + _stprintf(p, _T(",FP%d"), extra & 7); + } + } + } + } else if ((opcode & 0xf000) == 0xa000) { + _tcscpy(instrname, _T("A-LINE")); + } else { + if (dp->suse) { + pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, &seaddr2, safemode); + } + if (dp->suse && dp->duse) + _tcscat (instrname, _T(",")); + if (dp->duse) { + pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, &deaddr2, safemode); + } + } + + for (i = 0; i < (int)(pc - oldpc) / 2 && i < 5; i++) { + buf = buf_out (buf, &bufsize, _T("%04x "), get_word_debug (oldpc + i * 2)); + } + while (i++ < 5) + buf = buf_out (buf, &bufsize, _T(" ")); + + if (illegal) + buf = buf_out (buf, &bufsize, _T("[ ")); + buf = buf_out (buf, &bufsize, instrname); + if (illegal) + buf = buf_out (buf, &bufsize, _T(" ]")); + + if (ccpt != 0) { + uaecptr addr2 = deaddr2 ? deaddr2 : seaddr2; + if (deaddr) + *deaddr = pc; + if ((opcode & 0xf000) == 0xf000) { + if (fpp_cond(dp->cc)) { + buf = buf_out(buf, &bufsize, _T(" == $%08x (T)"), addr2); + } else { + buf = buf_out(buf, &bufsize, _T(" == $%08x (F)"), addr2); + } + } else { + if (cctrue (dp->cc)) { + buf = buf_out (buf, &bufsize, _T(" == $%08x (T)"), addr2); + } else { + buf = buf_out (buf, &bufsize, _T(" == $%08x (F)"), addr2); + } + } + } else if ((opcode & 0xff00) == 0x6100) { /* BSR */ + if (deaddr) + *deaddr = pc; + buf = buf_out (buf, &bufsize, _T(" == $%08x"), seaddr2); + } + buf = buf_out (buf, &bufsize, _T("\n")); + + if (illegal) + pc = m68kpc_illg; + } + if (nextpc) + *nextpc = pc; + if (seaddr) + *seaddr = seaddr2; + if (deaddr) + *deaddr = deaddr2; +} + +void m68k_disasm_ea (uaecptr addr, uaecptr *nextpc, int cnt, uae_u32 *seaddr, uae_u32 *deaddr) +{ + TCHAR *buf; + + buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt); + if (!buf) + return; + m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, seaddr, deaddr, 1); + xfree (buf); +} +void m68k_disasm (uaecptr addr, uaecptr *nextpc, int cnt) +{ + TCHAR *buf; + + buf = xmalloc (TCHAR, (MAX_LINEWIDTH + 1) * cnt); + if (!buf) + return; + m68k_disasm_2 (buf, (MAX_LINEWIDTH + 1) * cnt, addr, nextpc, cnt, NULL, NULL, 0); + printf (_T("%s"), buf); + xfree (buf); +} + +/************************************************************* +Disasm the m68kcode at the given address into instrname +and instrcode +*************************************************************/ +void sm68k_disasm (TCHAR *instrname, TCHAR *instrcode, uaecptr addr, uaecptr *nextpc) +{ + TCHAR *ccpt; + uae_u32 opcode; + struct mnemolookup *lookup; + struct instr *dp; + uaecptr pc, oldpc; + + pc = oldpc = addr; + opcode = get_word_debug (pc); + if (cpufunctbl[opcode] == op_illg_1) { + opcode = 0x4AFC; + } + dp = table68k + opcode; + for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++); + + pc += 2; + + _tcscpy (instrname, lookup->name); + ccpt = _tcsstr (instrname, _T("cc")); + if (ccpt != 0) { + _tcsncpy (ccpt, ccnames[dp->cc], 2); + } + switch (dp->size){ + case sz_byte: _tcscat (instrname, _T(".B ")); break; + case sz_word: _tcscat (instrname, _T(".W ")); break; + case sz_long: _tcscat (instrname, _T(".L ")); break; + default: _tcscat (instrname, _T(" ")); break; + } + + if (dp->suse) { + pc = ShowEA (0, pc, opcode, dp->sreg, dp->smode, dp->size, instrname, NULL, 0); + } + if (dp->suse && dp->duse) + _tcscat (instrname, _T(",")); + if (dp->duse) { + pc = ShowEA (0, pc, opcode, dp->dreg, dp->dmode, dp->size, instrname, NULL, 0); + } + if (instrcode) + { + int i; + for (i = 0; i < (int)(pc - oldpc) / 2; i++) + { + _stprintf (instrcode, _T("%04x "), get_iword_debug (oldpc + i * 2)); + instrcode += _tcslen (instrcode); + } + } + if (nextpc) + *nextpc = pc; +} + +struct cpum2c m2cregs[] = { + { 0, "SFC" }, + { 1, "DFC" }, + { 2, "CACR" }, + { 3, "TC" }, + { 4, "ITT0" }, + { 5, "ITT1" }, + { 6, "DTT0" }, + { 7, "DTT1" }, + { 8, "BUSC" }, + { 0x800, "USP" }, + { 0x801, "VBR" }, + { 0x802, "CAAR" }, + { 0x803, "MSP" }, + { 0x804, "ISP" }, + { 0x805, "MMUS" }, + { 0x806, "URP" }, + { 0x807, "SRP" }, + { 0x808, "PCR" }, + { -1, NULL } +}; + +void m68k_dumpstate_2 (uaecptr pc, uaecptr *nextpc) +{ + int i, j; + + for (i = 0; i < 8; i++){ + printf (_T(" D%d %08X "), i, m68k_dreg (regs, i)); + if ((i & 3) == 3) printf (_T("\n")); + } + for (i = 0; i < 8; i++){ + printf (_T(" A%d %08X "), i, m68k_areg (regs, i)); + if ((i & 3) == 3) printf (_T("\n")); + } + if (regs.s == 0) + regs.usp = m68k_areg (regs, 7); + if (regs.s && regs.m) + regs.msp = m68k_areg (regs, 7); + if (regs.s && regs.m == 0) + regs.isp = m68k_areg (regs, 7); + j = 2; + printf (_T("USP %08X ISP %08X "), regs.usp, regs.isp); + for (i = 0; m2cregs[i].regno>= 0; i++) { + if (!movec_illg (m2cregs[i].regno)) { + if (!_tcscmp (m2cregs[i].regname, _T("USP")) || !_tcscmp (m2cregs[i].regname, _T("ISP"))) + continue; + if (j > 0 && (j % 4) == 0) + printf (_T("\n")); + printf (_T("%-4s %08X "), m2cregs[i].regname, val_move2c (m2cregs[i].regno)); + j++; + } + } + if (j > 0) + printf (_T("\n")); + printf (_T("T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d STP=%d\n"), + regs.t1, regs.t0, regs.s, regs.m, + GET_XFLG (), GET_NFLG (), GET_ZFLG (), + GET_VFLG (), GET_CFLG (), + regs.intmask, regs.stopped); +#ifdef FPUEMU + if (currprefs.fpu_model) { + uae_u32 fpsr; + for (i = 0; i < 8; i++){ + printf (_T("FP%d: %s "), i, fp_print(®s.fp[i])); + if ((i & 3) == 3) + printf (_T("\n")); + } + fpsr = fpp_get_fpsr (); + printf (_T("FPSR: %08X FPCR: %04x FPIAR: %08x N=%d Z=%d I=%d NAN=%d\n"), + fpsr, regs.fpcr, regs.fpiar, + (fpsr & 0x8000000) != 0, + (fpsr & 0x4000000) != 0, + (fpsr & 0x2000000) != 0, + (fpsr & 0x1000000) != 0); + } +#endif + if (currprefs.mmu_model == 68030) { + printf (_T("SRP: %llX CRP: %llX\n"), srp_030, crp_030); + printf (_T("TT0: %08X TT1: %08X TC: %08X\n"), tt0_030, tt1_030, tc_030); + } + if (currprefs.cpu_compatible && currprefs.cpu_model == 68000) { + struct instr *dp; + struct mnemolookup *lookup1, *lookup2; + dp = table68k + regs.irc; + for (lookup1 = lookuptab; lookup1->mnemo != dp->mnemo; lookup1++); + dp = table68k + regs.ir; + for (lookup2 = lookuptab; lookup2->mnemo != dp->mnemo; lookup2++); + printf (_T("Prefetch %04x (%s) %04x (%s) Chip latch %08X\n"), regs.irc, lookup1->name, regs.ir, lookup2->name, regs.chipset_latch_rw); + } + + if (pc != 0xffffffff) { + m68k_disasm (pc, nextpc, 1); + if (nextpc) + printf (_T("Next PC: %08x\n"), *nextpc); + } +} +void m68k_dumpstate (uaecptr *nextpc) +{ + m68k_dumpstate_2 (m68k_getpc (), nextpc); +} + +static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, bool plus2) +{ + if (currprefs.cpu_model >= 68040) + addr &= ~1; + if (currprefs.cpu_model >= 68020) { + if (pc == 0xffffffff) + last_addr_for_exception_3 = regs.instruction_pc; + else + last_addr_for_exception_3 = pc; + } else if (pc == 0xffffffff) { + last_addr_for_exception_3 = m68k_getpc (); + if (plus2) + last_addr_for_exception_3 += 2; + } else { + last_addr_for_exception_3 = pc; + } + last_fault_for_exception_3 = addr; + last_op_for_exception_3 = opcode; + last_writeaccess_for_exception_3 = writeaccess; + last_instructionaccess_for_exception_3 = instructionaccess; + Exception (3); +} + +void exception3_read(uae_u32 opcode, uaecptr addr) +{ + exception3f (opcode, addr, false, 0, false, 0xffffffff, false); +} +void exception3i (uae_u32 opcode, uaecptr addr) +{ + exception3f (opcode, addr, 0, 1, false, 0xffffffff, true); +} +void exception3b (uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc) +{ + exception3f (opcode, addr, w, i, false, pc, true); +} + +void exception2 (uaecptr addr, bool read, int size, uae_u32 fc) +{ + if (currprefs.mmu_model == 68030) { + uae_u32 flags = size == 1 ? MMU030_SSW_SIZE_B : (size == 2 ? MMU030_SSW_SIZE_W : MMU030_SSW_SIZE_L); + mmu030_page_fault (addr, read, flags, fc); + } else { + mmu_bus_error (addr, 0, fc, read == false, size, true); + } +} + +void cpureset (void) { + uaecptr pc; + uaecptr ksboot = 0xf80002 - 2; /* -2 = RESET hasn't increased PC yet */ + uae_u16 ins; + + if (currprefs.cpu_compatible) { + return; + } + + pc = m68k_getpc (); + /* panic, RAM is going to disappear under PC */ + ins = get_word (pc + 2); + if ((ins & ~7) == 0x4ed0) { + int reg = ins & 7; + uae_u32 addr = m68k_areg (regs, reg); + write_log ("reset/jmp (ax) combination emulated -> %x\n", addr); + if (addr < 0x80000) + addr += 0xf80000; + m68k_setpc (addr - 2); + return; + } + write_log ("M68K RESET PC=%x, rebooting..\n", pc); + m68k_setpc (ksboot); +} + + +void m68k_setstopped (void) +{ + regs.stopped = 1; + /* A traced STOP instruction drops through immediately without + actually stopping. */ + if ((regs.spcflags & SPCFLAG_DOTRACE) == 0) + set_special (SPCFLAG_STOP); + else + m68k_resumestopped (); +} + +void m68k_resumestopped (void) +{ + if (!regs.stopped) + return; + regs.stopped = 0; + unset_special (SPCFLAG_STOP); +}