From b149d32824dc2a4a54129328a98ebe8cb6883c5f Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Tue, 31 Dec 2019 13:23:47 +0200 Subject: [PATCH] 68010 loop mode emulation. --- gencpu.cpp | 85 +++++++++++++++++++++++++++++++++++++++---- include/newcpu.h | 7 +++- include/readcpu.h | 1 + newcpu.cpp | 25 +++++++++++-- readcpu.cpp | 93 ++++++++++++++++++++++++++++++++--------------- 5 files changed, 168 insertions(+), 43 deletions(-) diff --git a/gencpu.cpp b/gencpu.cpp index d0583ba8..ef2807bd 100644 --- a/gencpu.cpp +++ b/gencpu.cpp @@ -102,6 +102,7 @@ static bool genastore_done; static char rmw_varname[100]; static struct instr *g_instr; static char g_srcname[100]; +static int loopmode; #define GENA_GETV_NO_FETCH 0 #define GENA_GETV_FETCH 1 @@ -1041,9 +1042,26 @@ static void dummy_prefetch (void) check_prefetch_bus_error(o, 0); } +static void loopmode_begin(void) +{ + if (loopmode) { + printf("\tif(!regs.loop_mode) {\n"); + printf("\t\tregs.ird = opcode;\n"); + } +} +static void loopmode_end(void) +{ + if (loopmode) { + printf("\t} else {\n"); + addcycles000(2); + printf("\t}\n"); + } +} + static void fill_prefetch_next_noopcodecopy(const char *format, ...) { if (using_prefetch) { + loopmode_begin(); irc2ir(); if (using_bus_error) { bus_error_code[0] = 0; @@ -1059,29 +1077,34 @@ static void fill_prefetch_next_noopcodecopy(const char *format, ...) if (using_bus_error) { copy_opcode(); } + loopmode_end(); } } static void fill_prefetch_next(void) { if (using_prefetch) { + loopmode_begin(); irc2ir(); if (using_bus_error) { copy_opcode(); } fill_prefetch_1(m68k_pc_offset + 2); + loopmode_end(); } } static void fill_prefetch_next_t(void) { if (using_prefetch) { + loopmode_begin(); irc2ir(); if (using_bus_error) { copy_opcode(); strcat(bus_error_code, "\t\tif (regs.t1) opcode |= 0x10000;\n"); } fill_prefetch_1(m68k_pc_offset + 2); + loopmode_end(); } } @@ -1089,6 +1112,7 @@ static void fill_prefetch_next_t(void) static void fill_prefetch_next_extra(const char *cond, const char *format, ...) { if (using_prefetch) { + loopmode_begin(); irc2ir(); if (using_bus_error) { if (cond) @@ -1103,6 +1127,7 @@ static void fill_prefetch_next_extra(const char *cond, const char *format, ...) } } fill_prefetch_1(m68k_pc_offset + 2); + loopmode_end(); } } @@ -1110,6 +1135,7 @@ static void fill_prefetch_next_extra(const char *cond, const char *format, ...) static void fill_prefetch_next_after(int copy, const char *format, ...) { if (using_prefetch) { + loopmode_begin(); irc2ir(); printf("\topcode |= 0x20000;\n"); bus_error_code[0] = 0; @@ -1128,6 +1154,7 @@ static void fill_prefetch_next_after(int copy, const char *format, ...) opcode_nextcopy = 1; } } + loopmode_end(); } } @@ -2737,6 +2764,9 @@ static void genamode2x (amodes mode, const char *reg, wordsizes size, const char if (mode == Apdi && g_instr->size == sz_word && g_instr->mnemo != i_CLR) { printf("\t\tm68k_areg(regs, %s) = %sa;\n", reg, name); } + if (mode == Apdi) { + ;// printf("\t\tregs.read_buffer = 0;\n"); + } } if (g_instr->mnemo == i_ADDX || g_instr->mnemo == i_SUBX) { @@ -3894,11 +3924,11 @@ static void resetvars (void) dstblrmw = NULL; dstwlrmw = NULL; dstllrmw = NULL; - getpc = "m68k_getpc ()"; + getpc = "m68k_getpc()"; if (using_indirect > 0) { // tracer - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; if (using_mmu == 68030) { // 68030 cache MMU / CE cache MMU disp020 = "get_disp_ea_020_mmu030c"; @@ -3926,7 +3956,7 @@ static void resetvars (void) srcwd = "get_word_mmu030c"; dstld = "put_long_mmu030c"; dstwd = "put_word_mmu030c"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else if (!using_ce020 && !using_prefetch_020 && !using_ce) { // generic + indirect disp020 = "x_get_disp_ea_020"; @@ -4102,7 +4132,7 @@ static void resetvars (void) srcwd = "get_word_mmu030"; dstld = "put_long_mmu030"; dstwd = "put_word_mmu030"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else if (using_mmu == 68040) { // 68040 MMU disp020 = "x_get_disp_ea_020"; @@ -4125,7 +4155,7 @@ static void resetvars (void) dstblrmw = "put_lrmw_byte_mmu040"; dstwlrmw = "put_lrmw_word_mmu040"; dstllrmw = "put_lrmw_long_mmu040"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else if (using_mmu) { // 68060 MMU disp020 = "x_get_disp_ea_020"; @@ -4155,7 +4185,7 @@ static void resetvars (void) dstbrmw = "put_rmw_byte_mmu060"; dstwrmw = "put_rmw_word_mmu060"; dstlrmw = "put_rmw_long_mmu060"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else if (using_ce) { // 68000 ce prefetch_word = "get_word_ce000_prefetch"; @@ -4167,7 +4197,7 @@ static void resetvars (void) srcb = "get_byte_ce000"; dstb = "put_byte_ce000"; do_cycles = "do_cycles_ce000"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else if (using_prefetch) { // 68000 prefetch prefetch_word = "get_word_000_prefetch"; @@ -4179,7 +4209,7 @@ static void resetvars (void) dstw = "put_word_000"; srcb = "get_byte_000"; dstb = "put_byte_000"; - getpc = "m68k_getpci ()"; + getpc = "m68k_getpci()"; } else { // generic + direct prefetch_long = "get_dilong"; @@ -4254,6 +4284,15 @@ static void gen_opcode (unsigned int opcode) bus_error_code2[0] = 0; opcode_nextcopy = 0; + loopmode = 0; + // 68010 loop mode available if + if (cpu_level == 1) { + loopmode = opcode_loop_mode(opcode); + if (curi->mnemo == i_DBcc || loopmode) { + next_level_000(); + } + } + // do not unnecessarily create useless mmuop030 // functions when CPU is not 68030 if (curi->mnemo == i_MMUOP030 && cpu_level != 3 && !cpu_generic) { @@ -6163,6 +6202,9 @@ bccl_not68020: genamodedual (curi, curi->smode, "srcreg", curi->size, "src", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0), curi->dmode, "dstreg", curi->size, "offs", 1, GF_AA | (cpu_level < 2 ? GF_NOREFILL : 0)); + if (cpu_level == 1) { + printf("\tregs.loop_mode = false;\n"); + } printf("\tuaecptr oldpc = %s;\n", getpc); addcycles000 (2); if (using_exception_3 && cpu_level >= 4) { @@ -6184,6 +6226,33 @@ bccl_not68020: write_return_cycles("\t\t", 0); printf("\t\t}\n"); } + // 68010 loop mode handling + if (cpu_level == 1) { + printf("\t\tif(offs == -4 && !regs.t1 && loop_mode_table[regs.ird]) {\n"); + printf("\t\t\tregs.loop_mode = true;\n"); + printf("\t\t\tsrc = m68k_dreg(regs, srcreg);\n"); + genastore("(src - 1)", curi->smode, "srcreg", curi->size, "src"); + addcycles000(2); + printf("\t\t\tif (src) {\n"); + if (using_ce) { + printf("\t\t\t\tloop_mode_table[regs.ird](regs.ird);\n"); + } else { + printf("\t\t\t\tcount_cycles += loop_mode_table[regs.ird](regs.ird);\n"); + } + setpc("oldpc"); + check_ipl(); + addcycles000(2); + returncycles("\t\t\t\t", 4); + printf("\t\t\t} else {\n"); + addcycles000(2); + printf("\t\t\t}\n"); + printf("\t\t\tregs.loop_mode = false;\n"); + setpc("oldpc + %d", m68k_pc_offset); + fill_prefetch_full_000_special(); + returncycles("\t\t\t", 6); + printf("\t\t}\n"); + } + printf("\t"); fill_prefetch_1(0); printf("\t"); diff --git a/include/newcpu.h b/include/newcpu.h index f47ab251..ff944826 100644 --- a/include/newcpu.h +++ b/include/newcpu.h @@ -85,6 +85,8 @@ struct comptbl { }; #endif +extern cpuop_func *loop_mode_table[]; + extern uae_u32 REGPARAM3 op_illg (uae_u32) REGPARAM; extern void REGPARAM3 op_unimpl (uae_u32) REGPARAM; @@ -176,13 +178,14 @@ struct regstruct uae_u32 instruction_pc_user_exception; uae_u32 trace_pc; - uae_u16 irc, ir, db; + uae_u16 irc, ir, ird, db; volatile uae_atomic spcflags; uae_u32 last_prefetch; uae_u32 chipset_latch_rw; uae_u32 chipset_latch_read; uae_u32 chipset_latch_write; uae_u16 write_buffer, read_buffer; + bool loop_mode; uaecptr usp, isp, msp; uae_u16 sr; @@ -270,7 +273,7 @@ struct cputracestruct { uae_u32 regs[16]; uae_u32 usp, isp, pc; - uae_u16 ir, irc, sr, opcode; + uae_u16 ir, irc, ird, sr, opcode; int intmask, stopped, state; uae_u32 msp, vbr; diff --git a/include/readcpu.h b/include/readcpu.h index cec52381..ed96393e 100644 --- a/include/readcpu.h +++ b/include/readcpu.h @@ -116,5 +116,6 @@ extern void read_table68k (void); extern void do_merges (void); extern int get_no_mismatches (void); extern int nr_cpuop_funcs; +extern bool opcode_loop_mode(uae_u16 opcode); #endif /* UAE_READCPU_H */ diff --git a/newcpu.cpp b/newcpu.cpp index 78d950a2..3501de41 100644 --- a/newcpu.cpp +++ b/newcpu.cpp @@ -111,6 +111,7 @@ int movem_index2[256]; int movem_next[256]; cpuop_func *cpufunctbl[65536]; +cpuop_func *loop_mode_table[65536]; struct cputbl_data { @@ -1831,7 +1832,7 @@ static void build_cpufunctbl (void) struct instr *table = &table68k[opcode]; if (table->mnemo == i_ILLG) - continue; + continue; /* unimplemented opcode? */ if (table->unimpclev > 0 && lvl >= table->unimpclev) { @@ -1874,6 +1875,11 @@ static void build_cpufunctbl (void) memcpy(&cpudatatbl[opcode], &cpudatatbl[idx], sizeof(struct cputbl_data)); opcnt++; } + + if (opcode_loop_mode(opcode)) { + loop_mode_table[opcode] = cpufunctbl[opcode]; + } + } write_log (_T("Building CPU, %d opcodes (%d %d %d)\n"), opcnt, lvl, @@ -3001,6 +3007,7 @@ static void ExceptionX (int nr, uaecptr address) { uaecptr pc = m68k_getpc(); regs.exception = nr; + regs.loop_mode = 0; if (cpu_tracer) { cputrace.state = nr; } @@ -4389,6 +4396,8 @@ static void m68k_run_1 (void) do_cycles (cpu_cycles); r->instruction_pc = m68k_getpc (); cpu_cycles = (*cpufunctbl[r->opcode])(r->opcode); + if (!regs.loop_mode) + regs.ird = regs.opcode; cpu_cycles = adjust_cycles (cpu_cycles); if (r->spcflags) { if (do_specialties (cpu_cycles)) @@ -4434,6 +4443,7 @@ static void m68k_run_1_ce (void) memcpy (&r->regs, &cputrace.regs, 16 * sizeof (uae_u32)); r->ir = cputrace.ir; r->irc = cputrace.irc; + r->ird = cputrace.ird; r->sr = cputrace.sr; r->usp = cputrace.usp; r->isp = cputrace.isp; @@ -4471,6 +4481,7 @@ static void m68k_run_1_ce (void) cputrace.opcode = r->opcode; cputrace.ir = r->ir; cputrace.irc = r->irc; + cputrace.ird = r->ird; cputrace.sr = r->sr; cputrace.usp = r->usp; cputrace.isp = r->isp; @@ -4497,6 +4508,8 @@ static void m68k_run_1_ce (void) r->instruction_pc = m68k_getpc (); (*cpufunctbl[r->opcode])(r->opcode); + if (!regs.loop_mode) + regs.ird = regs.opcode; wait_memory_cycles(); if (cpu_tracer) { cputrace.state = 0; @@ -6225,6 +6238,7 @@ uae_u8 *restore_cpu (uae_u8 *src) } else { regs.stopped = 0; } + regs.ird = l >> 16; if (model >= 68010) { regs.dfc = restore_u32 (); regs.sfc = restore_u32 (); @@ -6434,7 +6448,7 @@ uae_u8 *save_cpu_trace (int *len, uae_u8 *dstptr) else dstbak = dst = xmalloc (uae_u8, 10000); - save_u32 (2 | 4 | 16 | 32); + save_u32 (2 | 4 | 16 | 32 | 64); save_u16 (cputrace.opcode); for (int i = 0; i < 16; i++) save_u32 (cputrace.regs[i]); @@ -6489,6 +6503,8 @@ uae_u8 *save_cpu_trace (int *len, uae_u8 *dstptr) save_u16(cputrace.pipeline_stop); } + save_u16(cputrace.ird); + *len = dst - dstbak; cputrace.needendcycles = 1; return dstbak; @@ -6576,6 +6592,9 @@ uae_u8 *restore_cpu_trace (uae_u8 *src) cputrace.pipeline_r8[1] = restore_u16(); cputrace.pipeline_stop = restore_u16(); } + if (v & 64) { + cputrace.ird = restore_u16(); + } } } @@ -6671,7 +6690,7 @@ uae_u8 *save_cpu (int *len, uae_u8 *dstptr) 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 */ + save_u32 ((regs.stopped ? CPUMODE_HALT : 0) | (regs.ird << 16)); /* flags + ird */ if (model >= 68010) { save_u32 (regs.dfc); /* DFC */ save_u32 (regs.sfc); /* SFC */ diff --git a/readcpu.cpp b/readcpu.cpp index c7896a0c..00a26300 100644 --- a/readcpu.cpp +++ b/readcpu.cpp @@ -16,39 +16,39 @@ int nr_cpuop_funcs; struct mnemolookup lookuptab[] = { { i_ILLG, _T("ILLEGAL"), NULL, 0 }, - { i_OR, _T("OR"), NULL, 1 }, + { i_OR, _T("OR"), NULL, 1 | 2 }, { i_CHK, _T("CHK"), NULL, 0 }, { i_CHK2, _T("CHK2"), NULL, 0 }, - { i_AND, _T("AND"), NULL, 1 }, - { i_EOR, _T("EOR"), NULL, 1 }, + { i_AND, _T("AND"), NULL, 1 | 2 }, + { i_EOR, _T("EOR"), NULL, 1 | 2 }, { i_ORSR, _T("ORSR"), _T("OR"), 0 }, { i_ANDSR, _T("ANDSR"), _T("AND"), 0 }, { i_EORSR, _T("EORSR"), _T("EOR"), 0 }, - { i_SUB, _T("SUB"), NULL, 1 }, - { i_SUBA, _T("SUBA"), NULL, 1 }, - { i_SUBX, _T("SUBX"), NULL, 0 }, - { i_SBCD, _T("SBCD"), NULL, 0 }, - { i_ADD, _T("ADD"), NULL, 1 }, - { i_ADDA, _T("ADDA"), NULL, 1 }, - { i_ADDX, _T("ADDX"), NULL, 0 }, - { i_ABCD, _T("ABCD"), NULL, 0 }, - { i_NEG, _T("NEG"), NULL, 1 }, - { i_NEGX, _T("NEGX"), NULL, 1 }, - { i_NBCD, _T("NBCD"), NULL, 0 }, - { i_CLR, _T("CLR"), NULL, 1 }, - { i_NOT, _T("NOT"), NULL, 1 }, - { i_TST, _T("TST"), NULL, 1 }, + { i_SUB, _T("SUB"), NULL, 1 | 2 }, + { i_SUBA, _T("SUBA"), NULL, 1 | 2 }, + { i_SUBX, _T("SUBX"), NULL, 0 | 2 }, + { i_SBCD, _T("SBCD"), NULL, 0 | 2 }, + { i_ADD, _T("ADD"), NULL, 1 | 2 }, + { i_ADDA, _T("ADDA"), NULL, 1 | 2 }, + { i_ADDX, _T("ADDX"), NULL, 0 | 2 }, + { i_ABCD, _T("ABCD"), NULL, 0 | 2 }, + { i_NEG, _T("NEG"), NULL, 1 | 2 }, + { i_NEGX, _T("NEGX"), NULL, 1 | 2 }, + { i_NBCD, _T("NBCD"), NULL, 0 | 2 }, + { i_CLR, _T("CLR"), NULL, 1 | 2 }, + { i_NOT, _T("NOT"), NULL, 1 | 2 }, + { i_TST, _T("TST"), NULL, 1 | 2 }, { i_BTST, _T("BTST"), NULL, 1 }, { i_BCHG, _T("BCHG"), NULL, 1 }, { i_BCLR, _T("BCLR"), NULL, 1 }, { i_BSET, _T("BSET"), NULL, 1 }, - { i_CMP, _T("CMP"), NULL, 1 }, - { i_CMPM, _T("CMPM"), NULL, 1 }, - { i_CMPA, _T("CMPA"), NULL, 1 }, + { i_CMP, _T("CMP"), NULL, 1 | 2 }, + { i_CMPM, _T("CMPM"), NULL, 1 | 2 }, + { i_CMPA, _T("CMPA"), NULL, 1 | 2 }, { i_MVPRM, _T("MVPRM"), _T("MOVEP"), 0 }, { i_MVPMR, _T("MVPMR"), _T("MOVEP"), 0 }, - { i_MOVE, _T("MOVE"), NULL, 1 }, - { i_MOVEA, _T("MOVEA"), NULL, 1 }, + { i_MOVE, _T("MOVE"), NULL, 1 | 2 }, + { i_MOVEA, _T("MOVEA"), NULL, 1 | 2 }, { i_MVSR2, _T("MVSR2"), _T("MOVE"), 0 }, { i_MV2SR, _T("MV2SR"), _T("MOVE"), 0 }, { i_SWAP, _T("SWAP"), NULL, 0 }, @@ -89,14 +89,14 @@ struct mnemolookup lookuptab[] = { { i_ROR, _T("ROR"), NULL, 0 }, { i_ROXL, _T("ROXL"), NULL, 1 }, { i_ROXR, _T("ROXR"), NULL, 1 }, - { i_ASRW, _T("ASRW"), _T("ASR"), 1 }, - { i_ASLW, _T("ASLW"), _T("ASL"), 1 }, - { i_LSRW, _T("LSRW"), _T("LSR"), 1 }, - { i_LSLW, _T("LSLW"), _T("LSL"), 1 }, - { i_ROLW, _T("ROLW"), _T("ROL"), 1 }, - { i_RORW, _T("RORW"), _T("ROR"), 1 }, - { i_ROXLW, _T("ROXLW"), _T("ROXL"), 1 }, - { i_ROXRW, _T("ROXRW"), _T("ROXR"), 1 }, + { i_ASRW, _T("ASRW"), _T("ASR"), 1 | 2 }, + { i_ASLW, _T("ASLW"), _T("ASL"), 1 | 2 }, + { i_LSRW, _T("LSRW"), _T("LSR"), 1 | 2 }, + { i_LSLW, _T("LSLW"), _T("LSL"), 1 | 2 }, + { i_ROLW, _T("ROLW"), _T("ROL"), 1 | 2 }, + { i_RORW, _T("RORW"), _T("ROR"), 1 | 2 }, + { i_ROXLW, _T("ROXLW"), _T("ROXL"), 1 | 2 }, + { i_ROXRW, _T("ROXRW"), _T("ROXR"), 1 | 2 }, { i_MOVE2C, _T("MOVE2C"), _T("MOVEC"), 0 }, { i_MOVEC2, _T("MOVEC2"), _T("MOVEC"), 0 }, @@ -882,3 +882,36 @@ int get_no_mismatches (void) { return imismatch; } + +static int isreg(amodes mode) +{ + if (mode == Dreg || mode == Areg) + return 1; + return 0; +} + +bool opcode_loop_mode(uae_u16 opcode) +{ + instr *c = &table68k[opcode]; + bool loopmode = false; + int i; + for (i = 0; lookuptab[i].name[0]; i++) { + if (c->mnemo == lookuptab[i].mnemo) + break; + } + if (lookuptab[i].flags & 2) { + // Source is Dn,An,(An),(An)+,-(An) + // Destination is Dn,An,(An),(An)+,-(An) + // Both source and destination must not be Dn or An. + // RMW instruction must not be Dn or An + if (((isreg(c->smode) || c->smode == Aind || c->smode == Apdi || c->smode == Aipi)) && + ((!c->duse && !isreg(c->smode)) || (c->duse && (isreg(c->dmode) || c->dmode == Aind || c->dmode == Apdi || c->dmode == Aipi))) && + (!c->duse || (isreg(c->smode) && !isreg(c->dmode)) || (!isreg(c->smode) && isreg(c->dmode)) || (!isreg(c->smode) && !isreg(c->dmode)))) { + loopmode = true; + } + if (c->mnemo == i_MOVE && isreg(c->dmode)) { + loopmode = false; + } + } + return loopmode; +} -- 2.47.3