Totally unusable threaded CPU emulation.
for(i = 0; i < 5; i++) {
printf("{%d,%d}%s", flaguse[i], flagset[i], i == 4 ? "" : ",");
}
- printf("},%2d,_T(\"%s\"),%2d,%2d,%2d,%2d}", sduse, opstrp, head, tail, clocks, fetchmode);
+ printf("},0x%02x,_T(\"%s\"),%2d,%2d,%2d,%2d}", sduse, opstrp, head, tail, clocks, fetchmode);
}
printf("};\nint n_defs68k = %d;\n", no_insns);
return 0;
cfgfile_write_bool (f, _T("cpu_24bit_addressing"), p->address_space_24);
/* do not reorder end */
cfgfile_dwrite_bool(f, _T("cpu_reset_pause"), p->reset_delay);
+ cfgfile_dwrite_bool(f, _T("cpu_threaded"), p->cpu_thread);
if (p->ppc_mode)
cfgfile_write_str(f, _T("ppc_implementation"), ppc_implementations[p->ppc_implementation]);
|| cfgfile_yesno (option, value, _T("ntsc"), &p->ntscmode)
|| cfgfile_yesno (option, value, _T("sana2"), &p->sana2)
|| cfgfile_yesno (option, value, _T("genlock"), &p->genlock)
- || cfgfile_yesno (option, value, _T("cpu_compatible"), &p->cpu_compatible)
+ || cfgfile_yesno(option, value, _T("cpu_compatible"), &p->cpu_compatible)
+ || cfgfile_yesno(option, value, _T("cpu_threaded"), &p->cpu_thread)
|| cfgfile_yesno(option, value, _T("cpu_24bit_addressing"), &p->address_space_24)
|| cfgfile_yesno(option, value, _T("cpu_reset_pause"), &p->reset_delay)
|| cfgfile_yesno(option, value, _T("parallel_on_demand"), &p->parallel_demand)
p->prtname[0] = 0;
p->sername[0] = 0;
+ p->cpu_thread = false;
+
p->fpu_model = 0;
p->cpu_model = 68000;
p->m68k_speed_throttle = 0;
static void cia_wait_pre (int cianummask)
{
- if (currprefs.cachesize)
+ if (currprefs.cachesize || currprefs.cpu_thread)
return;
#ifdef WITH_PPC
if (ppc_state)
if (ppc_state)
return;
#endif
+ if (currprefs.cpu_thread)
+ return;
if (currprefs.cachesize) {
do_cycles (8 * CYCLE_UNIT /2);
} else {
port_get_custom (1, out);
}
#endif
- if (currprefs.m68k_speed < 0 && !currprefs.cpu_cycle_exact) {
+ if (!currprefs.cpu_thread && currprefs.m68k_speed < 0 && !currprefs.cpu_cycle_exact) {
static int sleeps_remaining;
if (is_last_line ()) {
sleeps_remaining = (165 - currprefs.cpu_idle) / 6;
}
}
}
- } else {
+ } else if (!currprefs.cpu_thread) {
if (vpos + 1 < maxvpos + lof_store && (vpos == maxvpos_display * 1 / 3 || vpos == maxvpos_display * 2 / 3)) {
vsyncmintime += vsynctimeperline;
if (!vsync_isdone () && !currprefs.turbo_emulation) {
static int generate_stbl;
static int mmufixupcnt;
static int mmufixupstate;
-static int mmudisp020cnt;
+static int disp020cnt;
static bool candormw;
static bool genastore_done;
static char rmw_varname[100];
static const char *srcbrmw, *srcwrmw, *srclrmw;
static const char *dstbrmw, *dstwrmw, *dstlrmw;
static const char *prefetch_long, *prefetch_word;
-static const char *prefetch_long_buffer, *prefetch_word_buffer;
static const char *srcli, *srcwi, *srcbi, *nextl, *nextw;
static const char *srcld, *dstld;
static const char *srcwd, *dstwd;
static char endlabelstr[80];
static int endlabelno = 0;
static int need_endlabel;
+static int genamode_cnt;
static int n_braces, limit_braces;
static int m68k_pc_offset, m68k_pc_offset_old;
+static int m68k_pc_total;
+static int branch_inst;
static int insn_n_cycles, insn_n_cycles020;
static int ir2irc;
add_mmu040_movem (movem);
if (using_ce020) {
if (flags & GF_NOREFILL)
- printf("\t%s = %s (%d);\n", name, prefetch_long_buffer, r);
+ printf("\t%s = %s (%d);\n", name, prefetch_long, r);
else
printf("\t%s = %s (%d);\n", name, prefetch_long, r);
count_read += 2;
if (using_ce020) {
if (flags & GF_NOREFILL)
- sprintf(buffer, "%s (%d)", prefetch_word_buffer, r);
+ sprintf(buffer, "%s (%d)", prefetch_word, r);
else
sprintf(buffer, "%s (%d)", prefetch_word, r);
count_read++;
if (using_ce020 || using_prefetch_020) {
if (flags & GF_NOREFILL)
- sprintf(buffer, "(uae_u8)%s (%d)", prefetch_word_buffer, r);
+ sprintf(buffer, "(uae_u8)%s (%d)", prefetch_word, r);
else
sprintf(buffer, "(uae_u8)%s (%d)", prefetch_word, r);
count_read++;
if (m68k_pc_offset == 0)
return;
incpc ("%d", m68k_pc_offset);
+ m68k_pc_total += m68k_pc_offset;
+ m68k_pc_offset = 0;
+}
+
+static void clear_m68k_offset(void)
+{
+ m68k_pc_total += m68k_pc_offset;
m68k_pc_offset = 0;
}
rmw = true;
}
+ genamode_cnt++;
+
start_brace ();
switch (mode) {
start_brace ();
/* This would ordinarily be done in gen_nextiword, which we bypass. */
insn_n_cycles += 4;
- printf ("\t%sa = %s (m68k_areg (regs, %s), %d);\n", name, disp020, reg, mmudisp020cnt++);
+ printf ("\t%sa = %s (m68k_areg (regs, %s), %d);\n", name, disp020, reg, disp020cnt++);
} else {
if (!(flags & GF_AD8R)) {
addcycles000 (2);
/* This would ordinarily be done in gen_nextiword, which we bypass. */
insn_n_cycles += 4;
printf ("\ttmppc = %s;\n", getpc);
- printf ("\t%sa = %s (tmppc, %d);\n", name, disp020, mmudisp020cnt++);
+ printf ("\t%sa = %s (tmppc, %d);\n", name, disp020, disp020cnt++);
} else {
printf ("\ttmppc = %s + %d;\n", getpc, m68k_pc_offset);
if (!(flags & GF_PC8R)) {
{
insn_n_cycles = using_prefetch ? 0 : 4;
insn_n_cycles020 = 0;
+ genamode_cnt = 0;
+ m68k_pc_total = 0;
+ branch_inst = 0;
+
ir2irc = 0;
mmufixupcnt = 0;
mmufixupstate = 0;
- mmudisp020cnt = 0;
+ disp020cnt = 0;
candormw = false;
genastore_done = false;
rmw_varname[0] = 0;
got_ea_ce020 = false;
prefetch_long = NULL;
- prefetch_word_buffer = NULL;
- prefetch_long_buffer = NULL;
srcli = NULL;
srcbi = NULL;
disp000 = "get_disp_ea_000";
disp020 = "x_get_disp_ea_ce020";
prefetch_word = "get_word_ce020_prefetch";
prefetch_long = "get_long_ce020_prefetch";
- prefetch_word_buffer = "get_word_ce020_prefetch_buffer";
- prefetch_long_buffer = "get_long_ce020_prefetch_buffer";
srcli = "x_get_ilong";
srcwi = "x_get_iword";
srcbi = "x_get_ibyte";
disp020 = "x_get_disp_ea_ce030";
prefetch_long = "get_long_ce030_prefetch";
prefetch_word = "get_word_ce030_prefetch";
- prefetch_word_buffer = "get_word_ce030_prefetch_buffer";
- prefetch_long_buffer = "get_long_ce030_prefetch_buffer";
srcli = "x_get_ilong";
srcwi = "x_get_iword";
srcbi = "x_get_ibyte";
disp020 = "x_get_disp_ea_020";
prefetch_word = "get_word_020_prefetch";
prefetch_long = "get_long_020_prefetch";
- prefetch_word_buffer = "get_word_020_prefetch_buffer";
- prefetch_long_buffer = "get_long_020_prefetch_buffer";
srcli = "x_get_ilong";
srcwi = "x_get_iword";
srcbi = "x_get_ibyte";
dstwlrmw = dstw;
dstllrmw = dstl;
}
- if (!prefetch_word_buffer)
- prefetch_word_buffer = prefetch_word;
- if (!prefetch_long_buffer)
- prefetch_long_buffer = prefetch_long;
}
start_brace ();
m68k_pc_offset = 2;
+
switch (curi->plev) {
case 0: /* not privileged */
break;
sync_m68k_pc ();
printf ("\tException (src + 32);\n");
did_prefetch = 1;
- m68k_pc_offset = 0;
+ branch_inst = 1;
+ clear_m68k_offset();
break;
case i_MVR2USP:
genamode (curi, curi->smode, "srcreg", curi->size, "src", 1, 0, 0);
addcycles000 (128);
if (using_prefetch) {
printf ("\t%s (2);\n", prefetch_word);
- m68k_pc_offset = 0;
+ clear_m68k_offset();
}
break;
case i_NOP:
need_endlabel = 1;
}
/* PC is set and prefetch filled. */
- m68k_pc_offset = 0;
+ clear_m68k_offset();
tail_ce020_done = true;
fill_prefetch_full ();
+ branch_inst = 1;
break;
case i_RTD:
addop_ce020 (curi, 0);
printf ("\t}\n");
setpc ("pc");
/* PC is set and prefetch filled. */
- m68k_pc_offset = 0;
+ clear_m68k_offset();
tail_ce020_done = true;
fill_prefetch_full ();
need_endlabel = 1;
+ branch_inst = 1;
break;
case i_LINK:
// ce confirmed
printf ("\t\tgoto %s;\n", endlabelstr);
printf ("\t}\n");
count_read += 2;
- m68k_pc_offset = 0;
+ clear_m68k_offset();
fill_prefetch_full ();
need_endlabel = 1;
+ branch_inst = 1;
break;
case i_TRAPV:
sync_m68k_pc ();
printf ("\t\texception3i (0x%04X, faultpc);\n", opcode);
printf ("\t\tgoto %s;\n", endlabelstr);
printf ("\t}\n");
- m68k_pc_offset = 0;
+ clear_m68k_offset();
fill_prefetch_full ();
need_endlabel = 1;
tail_ce020_done = true;
printf ("\t%s (m68k_areg (regs, 7) - 4, oldpc);\n", dstl);
printf ("\tm68k_areg (regs, 7) -= 4;\n");
setpc ("srca");
- m68k_pc_offset = 0;
+ clear_m68k_offset();
} else {
if (curi->smode == Ad16 || curi->smode == absw || curi->smode == PC16)
addcycles000 (2);
printf ("\toldpc += 2;\n");
}
setpc ("srca");
- m68k_pc_offset = 0;
+ clear_m68k_offset();
fill_prefetch_1 (0);
printf ("\tm68k_areg (regs, 7) -= 4;\n");
if (using_ce || using_prefetch) {
count_write += 2;
fill_prefetch_full_020 ();
fill_prefetch_next ();
+ branch_inst = 1;
break;
case i_JMP:
no_prefetch_ce020 = true;
if (curi->smode == Ad8r || curi->smode == PC8r)
addcycles000 (6);
setpc ("srca");
- m68k_pc_offset = 0;
+ clear_m68k_offset();
fill_prefetch_full ();
+ branch_inst = 1;
break;
case i_BSR:
// .b/.w = idle cycle, store high, store low, 2xprefetch
printf ("\tm68k_do_bsr (%s + %d, s);\n", getpc, m68k_pc_offset);
}
count_write += 2;
- m68k_pc_offset = 0;
+ clear_m68k_offset();
fill_prefetch_full ();
+ branch_inst = 1;
break;
case i_Bcc:
tail_ce020_done = true;
fill_prefetch_full_000 ();
}
insn_n_cycles = curi->size == sz_byte ? 8 : 12;
+ if (curi->cc == 0)
+ branch_inst = 1;
bccl_not68020:
break;
case i_LEA:
printf ("\t}\n");
pop_ins_cnt();
setpc ("oldpc + %d", m68k_pc_offset);
- m68k_pc_offset = 0;
+ clear_m68k_offset();
get_prefetch_020_0 ();
fill_prefetch_full_000 ();
insn_n_cycles = 12;
return out;
}
+struct cputbl_tmp
+{
+ uae_s16 length;
+ uae_u16 disp020;
+ uae_u16 branch;
+};
+static struct cputbl_tmp cputbltmp[65536];
+
static void generate_one_opcode (int rp, const char *extra)
{
int idx;
if (opcode_next_clev[rp] != cpu_level) {
char *name = ua (lookuptab[idx].name);
if (generate_stbl)
- fprintf (stblfile, "{ %sCPUFUNC(op_%04x_%d%s), %d }, /* %s */\n",
+ fprintf (stblfile, "{ %sCPUFUNC(op_%04x_%d%s), 0x%04x, %d, %d, %d }, /* %s */\n",
(using_ce || using_ce020) ? "(cpuop_func*)" : "",
opcode, opcode_last_postfix[rp],
- extra, opcode, name);
+ extra, opcode,
+ cputbltmp[opcode].length, cputbltmp[opcode].disp020, cputbltmp[opcode].branch, name);
xfree (name);
return;
}
opcode_next_clev[rp] = next_cpu_level;
opcode_last_postfix[rp] = postfix;
+ if ((opcode & 0xf000) == 0xf000)
+ m68k_pc_total = -1;
+ cputbltmp[opcode].length = m68k_pc_total;
+ cputbltmp[opcode].disp020 = disp020cnt;
+ cputbltmp[opcode].branch = branch_inst;
+
if (generate_stbl) {
char *name = ua (lookuptab[idx].name);
if (i68000)
fprintf (stblfile, "#ifndef CPUEMU_68000_ONLY\n");
- fprintf (stblfile, "{ %sCPUFUNC(op_%04x_%d%s), %d }, /* %s */\n",
+ fprintf (stblfile, "{ %sCPUFUNC(op_%04x_%d%s), 0x%04x, %d, %d, %d }, /* %s */\n",
(using_ce || using_ce020) ? "(cpuop_func*)" : "",
- opcode, postfix, extra, opcode, name);
+ opcode, postfix, extra, opcode,
+ cputbltmp[opcode].length, cputbltmp[opcode].disp020, cputbltmp[opcode].branch, name);
if (i68000)
fprintf (stblfile, "#endif\n");
xfree (name);
}
extern uae_u32 get_word_ce020_prefetch(int);
-extern uae_u32 get_word_ce020_prefetch_buffer(int);
STATIC_INLINE uae_u32 get_long_ce020_prefetch (int o)
{
return v;
}
-STATIC_INLINE uae_u32 get_long_ce020_prefetch_buffer(int o)
-{
- uae_u32 v;
- uae_u16 tmp;
- v = get_word_ce020_prefetch_buffer(o) << 16;
- tmp = regs.db;
- v |= get_word_ce020_prefetch_buffer(o + 2);
- regs.db = tmp;
- return v;
-}
-
STATIC_INLINE uae_u32 next_iword_020ce (void)
{
uae_u32 r = get_word_ce020_prefetch (0);
#ifdef CPUEMU_22
extern uae_u32 get_word_ce030_prefetch(int);
-extern uae_u32 get_word_ce030_prefetch_buffer(int);
STATIC_INLINE void put_long_ce030 (uaecptr addr, uae_u32 v)
{
return v;
}
-STATIC_INLINE uae_u32 get_long_ce030_prefetch_buffer(int o)
-{
- uae_u32 v;
- v = get_word_ce030_prefetch_buffer(o) << 16;
- v |= get_word_ce030_prefetch_buffer(o + 2);
- return v;
-}
-
STATIC_INLINE uae_u32 next_iword_030ce (void)
{
uae_u32 r = get_word_ce030_prefetch (0);
#define put_mem_bank(addr, b, realstart) do { \
(mem_banks[bankindex(addr)] = (b)); \
if ((b)->baseaddr) \
- baseaddr[bankindex(addr)] = (b)->baseaddr - (realstart); \
+ baseaddr[bankindex(addr)] = (b)->baseaddr - (realstart); \
else \
- baseaddr[bankindex(addr)] = (uae_u8*)(((uae_u8*)b)+1); \
+ baseaddr[bankindex(addr)] = (uae_u8*)(((uae_u8*)b)+1); \
} while (0)
#else
#define put_mem_bank(addr, b, realstart) \
struct cputbl {
cpuop_func *handler;
uae_u16 opcode;
+ uae_s16 length;
+ uae_u16 disp020;
+ uae_u16 branch;
};
#ifdef JIT
uae_u32 instruction_pc;
uae_u16 irc, ir, db;
- uae_u32 spcflags;
+ volatile uae_u32 spcflags;
uae_u32 last_prefetch;
uae_u32 chipset_latch_rw;
uae_u32 chipset_latch_read;
uae_u32 prefetch020addr;
uae_u32 cacheholdingdata020;
uae_u32 cacheholdingaddr020;
+ int pipeline_pos;
+ bool pipeline_next;
+ int pipeline_stop;
int ce020memcycles;
int ce020extracycles;
bool ce020memcycle_data;
extern int m68k_pc_indirect;
STATIC_INLINE void set_special (uae_u32 x)
{
+#ifdef WITH_THREADED_CPU
+#ifdef _WIN32
+ _InterlockedOr((volatile long*)®s.spcflags, x);
+#else
+ regs.spcflags |= x;
+#endif
+#else
regs.spcflags |= x;
+#endif
cycles_do_special ();
}
STATIC_INLINE void unset_special (uae_u32 x)
{
+#ifdef WITH_THREADED_CPU
+#ifdef _WIN32
+ _InterlockedAnd((volatile long*)®s.spcflags, ~x);
+#else
regs.spcflags &= ~x;
+#endif
+#else
+ regs.spcflags &= ~x;
+#endif
}
#define m68k_dreg(r,num) ((r).regs[(num)])
#define CPU_HALT_PCI_CONFLICT 8
#define CPU_HALT_CPU_STUCK 9
-
+void cpu_semaphore_get(void);
+void cpu_semaphore_release(void);
int ppc_mode;
TCHAR ppc_model[32];
bool cpu_compatible;
+ bool cpu_thread;
bool int_no_unimplemented;
bool fpu_no_unimplemented;
bool address_space_24;
extern void real_main (int, TCHAR **);
extern void usage (void);
extern void sleep_millis (int ms);
-extern void sleep_millis_main (int ms);
-extern void sleep_millis_busy (int ms);
+extern void sleep_millis_main(int ms);
+extern void sleep_millis_amiga(int ms);
extern int sleep_resolution;
#define UAE_QUIT 1
break;
}
+ if (p->cpu_thread && (p->cpu_compatible || p->ppc_mode || p->cpu_cycle_exact || p->cpu_model < 68020)) {
+ p->cpu_thread = false;
+ error_log(_T("Threaded CPU mode is not compatible with PPC emulation, More compatible or Cycle Exact modes. CPU type must be 68020 or higher."));
+ }
+
// 1 = "automatic" PPC config
if (p->ppc_mode == 1) {
cpuboard_setboard(p, BOARD_CYBERSTORM, BOARD_CYBERSTORM_SUB_PPC);
map_banks (bank, start, size, realsize);
}
+#ifdef WITH_THREADED_CPU
+
+struct addrbank_thread {
+ addrbank *orig;
+ addrbank ab;
+};
+
+#define MAX_THREAD_BANKS 200
+static addrbank_thread *thread_banks[MAX_THREAD_BANKS];
+static addrbank *thread_mem_banks[MEMORY_BANKS];
+static int thread_banks_used;
+
+static void REGPARAM2 threadcpu_lput(uaecptr addr, uae_u32 l)
+{
+ cpu_semaphore_get();
+ thread_mem_banks[bankindex(addr)]->lput(addr, l);
+ cpu_semaphore_release();
+}
+
+static void REGPARAM2 threadcpu_wput(uaecptr addr, uae_u32 w)
+{
+ cpu_semaphore_get();
+ thread_mem_banks[bankindex(addr)]->wput(addr, w);
+ cpu_semaphore_release();
+}
+
+static void REGPARAM2 threadcpu_bput(uaecptr addr, uae_u32 b)
+{
+ cpu_semaphore_get();
+ thread_mem_banks[bankindex(addr)]->bput(addr, b);
+ cpu_semaphore_release();
+}
+static uae_u32 REGPARAM2 threadcpu_lget(uaecptr addr)
+{
+ cpu_semaphore_get();
+ uae_u32 v = thread_mem_banks[bankindex(addr)]->lget(addr);
+ cpu_semaphore_release();
+ return v;
+}
+static uae_u32 REGPARAM2 threadcpu_wget(uaecptr addr)
+{
+ cpu_semaphore_get();
+ uae_u32 v = thread_mem_banks[bankindex(addr)]->wget(addr);
+ cpu_semaphore_release();
+ return v;
+}
+uae_u32 REGPARAM2 threadcpu_bget(uaecptr addr)
+{
+ cpu_semaphore_get();
+ uae_u32 v = thread_mem_banks[bankindex(addr)]->bget(addr);
+ cpu_semaphore_release();
+ return v;
+}
+
+static addrbank *get_bank_cpu_thread(addrbank *bank)
+{
+ if (bank->flags & ABFLAG_THREADSAFE)
+ return bank;
+ if (bank == &dummy_bank)
+ return bank;
+
+ for (int i = 0; i < thread_banks_used; i++) {
+ if (thread_banks[i]->orig == bank) {
+ return &thread_banks[i]->ab;
+ }
+ }
+ struct addrbank_thread *at = thread_banks[thread_banks_used];
+ if (!at)
+ at = xcalloc(addrbank_thread, 1);
+ thread_banks[thread_banks_used++] = at;
+ at->orig = bank;
+ memcpy(&at->ab, bank, sizeof addrbank);
+ addrbank *tb = &at->ab;
+ tb->lget = threadcpu_lget;
+ tb->wget = threadcpu_wget;
+ tb->bget = threadcpu_bget;
+ tb->lput = threadcpu_lput;
+ tb->wput = threadcpu_wput;
+ tb->bput = threadcpu_bput;
+ // wgeti/lgeti should always point to real RAM
+ return tb;
+}
+#endif
+
static void map_banks2 (addrbank *bank, int start, int size, int realsize, int quick)
{
int bnr, old;
unsigned long int hioffs = 0, endhioffs = 0x100;
uae_u32 realstart = start;
+ addrbank *orig_bank = NULL;
+
+#ifdef WITH_THREADED_CPU
+ if (currprefs.cpu_thread) {
+ addrbank *b = bank;
+ bank = get_bank_cpu_thread(bank);
+ if (b != bank)
+ orig_bank = b;
+ }
+#endif
if (quick <= 0)
old = debug_bankchange (-1);
#endif
}
put_mem_bank (bnr << 16, bank, realstart << 16);
+#ifdef WITH_THREADED_CPU
+ if (currprefs.cpu_thread) {
+ if (orig_bank)
+ put_mem_bank(bnr << 16, orig_bank, realstart << 16);
+ thread_mem_banks[bnr] = orig_bank;
+ }
+#endif
real_left--;
}
if (quick <= 0)
#endif
}
put_mem_bank ((bnr + hioffs) << 16, bank, realstart << 16);
+#ifdef WITH_THREADED_CPU
+ if (currprefs.cpu_thread) {
+ if (orig_bank)
+ put_mem_bank((bnr + hioffs) << 16, bank, realstart << 16);
+ thread_mem_banks[bnr + hioffs] = orig_bank;
+ }
+#endif
real_left--;
}
}
#define EXCEPTION3_DEBUGGER 0
#define CPUTRACE_DEBUG 0
+#define MORE_ACCURATE_68020_PIPELINE 1
+
#include "sysconfig.h"
#include "sysdeps.h"
#include "statusline.h"
#include "uae/ppc.h"
#include "cpuboard.h"
+#include "threaddep/thread.h"
#ifdef JIT
#include "jit/compemu.h"
#include <signal.h>
cpuop_func *cpufunctbl[65536];
+struct cputbl_data
+{
+ uae_s16 length;
+ uae_u16 disp020;
+ uae_u16 branch;
+};
+static struct cputbl_data cpudatatbl[65536];
+
struct mmufixup mmufixup[2];
#define COUNT_INSTRS 0
for (i = 0; tbl[i].handler != NULL; i++) {
opcode = tbl[i].opcode;
cpufunctbl[opcode] = tbl[i].handler;
+ cpudatatbl[opcode].length = tbl[i].length;
+ cpudatatbl[opcode].disp020 = tbl[i].disp020;
+ cpudatatbl[opcode].branch = tbl[i].branch;
}
/* 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)
+ if ((tbl[i].opcode & 0xfe00) == 0xf200) {
cpufunctbl[tbl[i].opcode] = tbl[i].handler;
+ cpudatatbl[tbl[i].opcode].length = tbl[i].length;
+ cpudatatbl[tbl[i].opcode].disp020 = tbl[i].disp020;
+ cpudatatbl[tbl[i].opcode].branch = tbl[i].branch;
+ }
}
}
if (f == op_illg_1)
abort ();
cpufunctbl[opcode] = f;
+ memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof cputbl_data);
opcnt++;
}
}
void cpu_sleep_millis(int ms)
{
+#ifdef WITH_THREADED_CPU
+ cpu_semaphore_release();
+#endif
#ifdef WITH_PPC
int state = ppc_state;
if (state)
if (state)
uae_ppc_spinlock_get();
#endif
+#ifdef WITH_THREADED_CPU
+ cpu_semaphore_get();
+#endif
}
#define PPC_HALTLOOP_SCANLINES 25
}
#endif
+#ifdef WITH_THREADED_CPU
+static volatile int cpu_thread_active;
+
+#define SPINLOCK_DEBUG 0
+static volatile int m68k_spinlock_cnt;
+static volatile long m68k_spinlock_waiting;
+#ifdef _WIN32
+#define CRITICAL_SECTION_SPIN_COUNT 5000
+static CRITICAL_SECTION m68k_cs1;
+static bool m68k_cs_initialized;
+static DWORD m68k_cs_owner;
+#else
+#include <glib.h>
+static GMutex mutex;
+#endif
+
+static int do_specialties_thread(void)
+{
+ if (regs.spcflags & SPCFLAG_MODE_CHANGE)
+ return 1;
+
+ if (regs.spcflags & SPCFLAG_CHECK) {
+ if (regs.halted) {
+ if (haltloop())
+ return 1;
+ }
+ if (m68k_reset_delay) {
+ int vsynccnt = 60;
+ int vsyncstate = -1;
+ while (vsynccnt > 0) {
+ int vp = vpos;
+ while (vp == vpos) {
+ sleep_millis(1);
+ }
+ vsynccnt--;
+ }
+ }
+ m68k_reset_delay = 0;
+ unset_special(SPCFLAG_CHECK);
+ }
+
+#ifdef JIT
+ unset_special(SPCFLAG_END_COMPILE); /* has done its job */
+#endif
+
+ if (regs.spcflags & SPCFLAG_DOTRACE)
+ Exception(9);
+
+ if (regs.spcflags & SPCFLAG_TRAP) {
+ unset_special(SPCFLAG_TRAP);
+ Exception(3);
+ }
+ bool first = true;
+ while ((regs.spcflags & SPCFLAG_STOP) && !(regs.spcflags & SPCFLAG_BRK)) {
+ 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);
+ }
+
+ if (regs.spcflags & SPCFLAG_MODE_CHANGE) {
+ m68k_resumestopped();
+ return 1;
+ }
+ }
+
+ if (regs.spcflags & SPCFLAG_TRACE)
+ do_trace();
+
+ 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);
+ }
+
+ if (regs.spcflags & SPCFLAG_DOINT) {
+ unset_special(SPCFLAG_DOINT);
+ set_special(SPCFLAG_INT);
+ }
+
+ if (regs.spcflags & SPCFLAG_BRK) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void cpu_semaphore_get(void)
+{
+ if (!currprefs.cpu_thread)
+ return;
+ DWORD tid = GetCurrentThreadId();
+
+ if (tid == m68k_cs_owner) {
+ m68k_spinlock_cnt++;
+ return;
+ }
+
+#ifdef _WIN32
+ _InterlockedIncrement(&m68k_spinlock_waiting);
+ EnterCriticalSection(&m68k_cs1);
+ _InterlockedDecrement(&m68k_spinlock_waiting);
+ m68k_cs_owner = tid;
+ m68k_spinlock_cnt++;
+#else
+ g_mutex_lock(&mutex); // FIXME
+#endif
+}
+void cpu_semaphore_release(void)
+{
+ if (!currprefs.cpu_thread)
+ return;
+#ifdef _WIN32
+ m68k_spinlock_cnt--;
+ if (m68k_spinlock_cnt == 0) {
+ m68k_cs_owner = 0;
+ LeaveCriticalSection(&m68k_cs1);
+ }
+#else
+ g_mutex_unlock(&mutex); // FIXME
+#endif
+}
+
+static void init_cpu_thread(void)
+{
+ if (!currprefs.cpu_thread)
+ return;
+#ifdef _WIN32
+ if (m68k_cs_initialized) {
+ DeleteCriticalSection(&m68k_cs1);
+ }
+ InitializeCriticalSectionAndSpinCount(&m68k_cs1, CRITICAL_SECTION_SPIN_COUNT);
+#endif
+}
+
+static void run_cpu_thread(void *(*f)(void *))
+{
+ cpu_thread_active = 0;
+#if SPINLOCK_DEBUG
+ m68k_spinlock_cnt = 0;
+#endif
+ m68k_cs_initialized = true;
+ if (uae_start_thread(_T("cpu"), f, NULL, NULL)) {
+ while (!cpu_thread_active) {
+ sleep_millis(1);
+ }
+ while (!(regs.spcflags & SPCFLAG_MODE_CHANGE)) {
+
+ cpu_semaphore_get();
+ frame_time_t c = read_processor_time();
+ while (cpu_thread_active) {
+ int vsynctimeperline = vsynctimebase / (maxvpos_display + 1);
+
+ int vp = vpos;
+ while ((int)read_processor_time() - (int)c > -vsynctimebase / 10) {
+ if (vp != vpos) {
+ vp = vpos;
+ if (vpos + 1 == maxvpos + lof_store) {
+ c = read_processor_time();
+ }
+ c += vsynctimeperline;
+ }
+ cycles_do_special();
+ do_cycles(maxhpos / 2 * CYCLE_UNIT);
+ if (regs.spcflags & SPCFLAG_COPPER) {
+ do_copper();
+ }
+ check_uae_int_request();
+ int w = m68k_spinlock_waiting;
+ if (w) {
+ cpu_semaphore_release();
+ while (m68k_spinlock_waiting == w);
+ cpu_semaphore_get();
+ }
+ }
+ cpu_semaphore_release();
+ sleep_millis(1);
+ cpu_semaphore_get();
+ while ((int)read_processor_time() - (int)c < 0) {
+ check_uae_int_request();
+ int w = m68k_spinlock_waiting;
+ if (w) {
+ cpu_semaphore_release();
+ while (m68k_spinlock_waiting == w);
+ cpu_semaphore_get();
+ }
+ }
+ }
+ cpu_semaphore_release();
+
+ unset_special(SPCFLAG_BRK);
+#ifdef DEBUGGER
+ if (debugging) {
+ debug();
+ }
+#endif
+ }
+ }
+}
+#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* ;-) */
+ if (!currprefs.cpu_thread) {
+ /* What did you expect this to do? */
+ do_cycles (0);
+ /* I bet you didn't expect *that* ;-) */
+ }
}
void exec_nostats (void)
}
cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
cpu_cycles = adjust_cycles (cpu_cycles);
- do_cycles (cpu_cycles);
+
+ if (!currprefs.cpu_thread) {
+ do_cycles (cpu_cycles);
#ifdef WITH_PPC
- if (ppc_state)
- ppc_interrupt(intlev());
+ if (ppc_state)
+ ppc_interrupt(intlev());
#endif
+ }
if (end_block(r->opcode) || r->spcflags || uae_int_requested || uaenet_int_requested)
return; /* We will deal with the spcflags in the caller */
pc_hist[blocklen].location = (uae_u16*)r->pc_p;
cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode);
- cpu_cycles = adjust_cycles (cpu_cycles);
- do_cycles (cpu_cycles);
+ cpu_cycles = adjust_cycles(cpu_cycles);
+ if (!currprefs.cpu_thread) {
+ do_cycles (cpu_cycles);
+ }
total_cycles += cpu_cycles;
pc_hist[blocklen].specmem = special_mem;
blocklen++;
typedef void compiled_handler (void);
-static void m68k_run_jit (void)
+#ifdef WITH_THREADED_CPU
+static void *cpu_thread_run_jit(void *v)
{
+ cpu_thread_active = 1;
+ for (;;) {
+ ((compiled_handler*)(pushall_call_handler))();
+ /* Whenever we return from that, we should check spcflags */
+ if (regs.spcflags) {
+ if (do_specialties_thread()) {
+ break;
+ }
+ }
+ }
+ cpu_thread_active = 0;
+ return 0;
+}
+#endif
+
+static void m68k_run_jit(void)
+{
+#ifdef WITH_THREADED_CPU
+ if (currprefs.cpu_thread) {
+ run_cpu_thread(cpu_thread_run_jit);
+ return;
+ }
+#endif
+
for (;;) {
((compiled_handler*)(pushall_call_handler))();
/* Whenever we return from that, we should check spcflags */
#endif
-//static int used[65536];
+#ifdef WITH_THREADED_CPU
+static void *cpu_thread_run_2(void *v)
+{
+ bool exit = false;
+ struct regstruct *r = ®s;
+
+ cpu_thread_active = 1;
+ while (!exit) {
+ TRY(prb)
+ {
+ while (!exit) {
+ r->instruction_pc = m68k_getpc();
+
+ r->opcode = x_get_iword(0);
+
+ (*cpufunctbl[r->opcode])(r->opcode);
+
+ if (r->spcflags) {
+ if (do_specialties_thread())
+ exit = true;
+ }
+ }
+ } CATCH(prb)
+ {
+ bus_error();
+ if (r->spcflags) {
+ if (do_specialties_thread())
+ exit = true;
+ }
+ } ENDTRY
+ }
+ cpu_thread_active = 0;
+ return 0;
+}
+#endif
/* Same thing, but don't use prefetch to get opcode. */
static void m68k_run_2 (void)
{
-// static int done;
+#ifdef WITH_THREADED_CPU
+ if (currprefs.cpu_thread) {
+ run_cpu_thread(cpu_thread_run_2);
+ return;
+ }
+#endif
+
struct regstruct *r = ®s;
bool exit = false;
int hardboot = 1;
int startup = 1;
+#ifdef WITH_THREADED_CPU
+ init_cpu_thread();
+#endif
if (in_m68k_go || !may_quit) {
write_log (_T("Bug! m68k_go is not reentrant.\n"));
abort ();
regs.cacheholdingdata020 = data;
}
-uae_u32 get_word_ce020_prefetch (int o)
+#if MORE_ACCURATE_68020_PIPELINE
+static void pipeline_020(uae_u16 w, uaecptr pc)
{
- uae_u32 pc = m68k_getpc () + o;
- uae_u32 v;
+ if (regs.pipeline_pos < 0)
+ return;
+#if 0
+ if (regs.pipeline_pos > 2 && regs.pipeline_next) {
+ // disp 020+ second word
+ if (w & 0x100) {
+ if ((w & 0x30) == 0x20)
+ regs.pipeline_pos += 2;
+ if ((w & 0x30) == 0x30)
+ regs.pipeline_pos += 4;
+ if ((w & 0x3) == 0x2)
+ regs.pipeline_pos += 2;
+ if ((w & 0x3) == 0x3)
+ regs.pipeline_pos += 4;
+ }
+ regs.pipeline_next = false;
+ }
+#endif
+ if (regs.pipeline_pos > 2) {
+ regs.pipeline_pos -= 2;
+ return;
+ }
+ if (regs.pipeline_stop) {
+ regs.pipeline_stop = -1;
+ return;
+ }
+ regs.pipeline_pos = cpudatatbl[w].length;
+ regs.pipeline_next = false;
+#if 0
+ if (!regs.pipeline_pos) {
+ write_log(_T("Opcode %04x has no size PC=%08x!\n"), w, pc);
+ }
+#endif
+ if (cpudatatbl[w].disp020) {
+ // not supported yet
+ regs.pipeline_pos = -1;
+#if 0
+ regs.pipeline_next = true;
+ regs.pipeline_pos += 2;
+#endif
+ }
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
- regs.prefetch020[0] = regs.prefetch020[1];
- fill_icache020 (pc + 2 + 4, mem_access_delay_longi_read_ce020);
- regs.prefetch020[1] = regs.cacheholdingdata020;
- regs.db = regs.prefetch020[0] >> 16;
- } else {
- v = regs.prefetch020[0] >> 16;
- regs.db = regs.prefetch020[1] >> 16;
+ if (regs.pipeline_pos > 0 && cpudatatbl[w].branch) {
+ regs.pipeline_pos -= 1 * 2;
+ if (regs.pipeline_pos <= 0)
+ regs.pipeline_stop = -1;
+ else
+ regs.pipeline_stop = 1;
}
- do_cycles_ce020_internal (2);
- return v;
}
+#endif
-uae_u32 get_word_ce020_prefetch_buffer(int o)
+uae_u32 get_word_ce020_prefetch (int o)
{
- uae_u32 pc = m68k_getpc() + o;
+ uae_u32 pc = m68k_getpc () + o;
uae_u32 v;
if (pc & 2) {
v = regs.prefetch020[0] & 0xffff;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(regs.prefetch020[1], pc );
+#endif
regs.prefetch020[0] = regs.prefetch020[1];
- //fill_icache020(pc + 2 + 4, mem_access_delay_longi_read_ce020);
- //regs.prefetch020[1] = regs.cacheholdingdata020;
+ // branch instruction detected in pipeline: stop fetches until branch executed.
+ if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
+ fill_icache020 (pc + 2 + 4, mem_access_delay_longi_read_ce020);
+ regs.prefetch020[1] = regs.cacheholdingdata020;
+ }
regs.db = regs.prefetch020[0] >> 16;
} else {
v = regs.prefetch020[0] >> 16;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(regs.prefetch020[1] >> 16, pc);
+#endif
regs.db = regs.prefetch020[1] >> 16;
}
- do_cycles_ce020_internal(2);
+ do_cycles_ce020_internal (2);
return v;
}
if (pc & 2) {
v = regs.prefetch020[0] & 0xffff;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(regs.prefetch020[1], pc);
+#endif
regs.prefetch020[0] = regs.prefetch020[1];
- fill_icache020 (pc + 2 + 4, get_longi);
- regs.prefetch020[1] = regs.cacheholdingdata020;
+ if (!MORE_ACCURATE_68020_PIPELINE || regs.pipeline_stop >= 0) {
+ fill_icache020 (pc + 2 + 4, get_longi);
+ regs.prefetch020[1] = regs.cacheholdingdata020;
+ }
regs.db = regs.prefetch020[0] >> 16;
} else {
v = regs.prefetch020[0] >> 16;
+#if MORE_ACCURATE_68020_PIPELINE
+ pipeline_020(regs.prefetch020[1] >> 16, pc);
+#endif
regs.db = regs.prefetch020[0];
}
return v;
return v;
}
-uae_u32 get_word_ce030_prefetch_buffer(int o)
-{
- uae_u32 pc = m68k_getpc() + o;
- uae_u32 v;
-
- if (pc & 2) {
- v = regs.prefetch020[0] & 0xffff;
- regs.prefetch020[0] = regs.prefetch020[1];
- //fill_icache030(pc + 2 + 4);
- //regs.prefetch020[1] = regs.cacheholdingdata020;
- } else {
- v = regs.prefetch020[0] >> 16;
- }
- do_cycles_ce020_internal(2);
- return v;
-}
-
uae_u32 get_word_icache030(uaecptr addr)
{
fill_icache030(addr);
{
uaecptr pc = m68k_getpc ();
pc &= ~3;
+ regs.pipeline_pos = 0;
+ regs.pipeline_stop = 0;
+
fill_icache030 (pc);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
regs.prefetch020[0] = regs.cacheholdingdata020;
+
fill_icache030 (pc + 4);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
regs.prefetch020[1] = regs.cacheholdingdata020;
+
regs.irc = get_word_ce030_prefetch (0);
}
void fill_prefetch_020 (void)
{
uaecptr pc = m68k_getpc ();
- uae_u32 (*fetch)(uaecptr) = currprefs.cpu_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi;
+ uaecptr pc2 = pc;
pc &= ~3;
+ uae_u32 (*fetch)(uaecptr) = currprefs.cpu_cycle_exact ? mem_access_delay_longi_read_ce020 : get_longi;
+ regs.pipeline_pos = 0;
+ regs.pipeline_stop = 0;
+
fill_icache020 (pc, fetch);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
regs.prefetch020[0] = regs.cacheholdingdata020;
+
fill_icache020 (pc + 4, fetch);
if (currprefs.cpu_cycle_exact)
do_cycles_ce020_internal(2);
regs.prefetch020[1] = regs.cacheholdingdata020;
+
+#if MORE_ACCURATE_68020_PIPELINE
+ if (pc2 & 2) {
+ pipeline_020(regs.prefetch020[0], pc);
+ pipeline_020(regs.prefetch020[1] >> 16, pc);
+ } else {
+ pipeline_020(regs.prefetch020[0] >> 16, pc);
+ pipeline_020(regs.prefetch020[0], pc);
+ }
+#endif
+
if (currprefs.cpu_cycle_exact)
regs.irc = get_word_ce020_prefetch (0);
else
void fill_prefetch (void)
{
+ regs.pipeline_pos = 0;
if (currprefs.cachesize)
return;
+ if (!currprefs.cpu_compatible)
+ return;
if (currprefs.cpu_model >= 68040) {
if (currprefs.cpu_compatible || currprefs.cpu_cycle_exact) {
fill_icache040(m68k_getpc() + 16);
sleep_millis2 (ms, false);
}
+void sleep_millis_amiga(int ms)
+{
+#ifdef WITH_THREADED_CPU
+ cpu_semaphore_release();
+#endif
+ sleep_millis_main(ms);
+#ifdef WITH_THREADED_CPU
+ cpu_semaphore_get();
+#endif
+}
frame_time_t read_processor_time_qpf (void)
{