CPU improvements

Merged from TomB
This commit is contained in:
Dimitris Panokostas 2020-06-29 08:25:47 +02:00
parent 8e3ae80c69
commit 4789eea572
17 changed files with 44870 additions and 10786 deletions

View file

@ -205,9 +205,9 @@ struct instr_def defs68k[] = {
/* RTR */
{0x4E77, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,0,0,0,{{1,0},{1,0},{1,0},{1,0},{1,0}}, 3, 0,_T("RTR"), 1, 0,12, 0},
/* MOVEC2 */
{0x4E7A, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,1,0,2,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 16,_T("MOVEC2 #1"), 6, 0, 6, 0},
{0x4E7A, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,1,0,0,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 16,_T("MOVEC2 #1"), 6, 0, 6, 0},
/* MOVE2C */
{0x4E7B, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,1,0,2,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 16,_T("MOVE2C #1"), 6, 0, 6, 0},
{0x4E7B, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,1,0,0,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 16,_T("MOVE2C #1"), 6, 0, 6, 0},
/* JSR.L */
{0x4E80, 6,{11,11,11,12,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFC0,0,0,0,{{4,6},{4,6},{4,6},{4,6},{4,6}}, 2, 128,_T("JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd]"), 0, 0, 4, 5},
/* CHK.L */
@ -455,11 +455,5 @@ struct instr_def defs68k[] = {
/* MOVE16 */
{0xF600, 6,{11,11,11,12,12,12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFC0,4,0,0,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 0, 18,_T("MOVE16 s[Aind],Al"), 0, 0, 0, 0},
/* MOVE16 */
{0xF600, 6,{13,13,13,14,14,14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFC0,4,0,0,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 0, 18,_T("MOVE16 Al,d[Aipi-Aind]"), 0, 0, 0, 0},
/* LPSTOP */
{0xF800, 0,{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFFF,5,0,2,{{3,5},{3,5},{3,5},{3,5},{3,5}}, 4, 16,_T("LPSTOP #1"), 0, 0, 0, 0},
/* PLPAW */
{0xF588, 3,{15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFF8,5,0,2,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 0,_T("PLPAW Ara"), 0, 0, 0, 0},
/* PLPAR */
{0xF5C8, 3,{15,15,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFF8,5,0,2,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 4, 0,_T("PLPAR Ara"), 0, 0, 0, 0}};
int n_defs68k = 230;
{0xF600, 6,{13,13,13,14,14,14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},0xFFC0,4,0,0,{{1,1},{1,1},{1,1},{1,1},{1,1}}, 0, 18,_T("MOVE16 Al,d[Aipi-Aind]"), 0, 0, 0, 0}};
int n_defs68k = 227;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -922,7 +922,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
break;
case 6: // (d8,An,Xn)+
ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg));
break;
case 7:
switch (reg)
@ -938,7 +938,7 @@ static int get_fp_value (uae_u32 opcode, uae_u16 extra, fpdata *src, uaecptr old
ad += (uae_s32) (uae_s16) x_cp_next_iword ();
break;
case 3: // (d8,PC,Xn)+
ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
ad = x_cp_get_disp_ea_020 (m68k_getpc ());
break;
case 4: // #imm
doext = 1;
@ -1092,7 +1092,7 @@ static int put_fp_value (fpdata *value, uae_u32 opcode, uae_u16 extra, uaecptr o
ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
break;
case 6: // (d8,An,Xn)+
ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg));
break;
case 7:
switch (reg)
@ -1198,7 +1198,7 @@ static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
*ad = m68k_areg (regs, reg) + (uae_s32) (uae_s16) x_cp_next_iword ();
break;
case 6: // (d8,An,Xn)+
*ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg), 0);
*ad = x_cp_get_disp_ea_020 (m68k_areg (regs, reg));
break;
case 7:
switch (reg)
@ -1214,7 +1214,7 @@ static int get_fp_ad (uae_u32 opcode, uae_u32 * ad)
*ad += (uae_s32) (uae_s16) x_cp_next_iword ();
break;
case 3: // (d8,PC,Xn)+
*ad = x_cp_get_disp_ea_020 (m68k_getpc (), 0);
*ad = x_cp_get_disp_ea_020 (m68k_getpc ());
break;
default:
return 0;
@ -1324,6 +1324,12 @@ static void maybe_idle_state (void)
regs.fpu_state = 1;
}
static void trace_t0_68040(void)
{
if (regs.t0 && currprefs.cpu_model == 68040)
check_t0_trace();
}
void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
{
uaecptr pc = m68k_getpc ();
@ -1357,6 +1363,8 @@ void fpuop_dbcc (uae_u32 opcode, uae_u16 extra)
regs.fp_branch = true;
}
}
// 68040 FDBCC: T0 always
trace_t0_68040();
}
void fpuop_scc (uae_u32 opcode, uae_u16 extra)
@ -1541,6 +1549,8 @@ void fpuop_save (uae_u32 opcode)
x_cp_put_long(ad, fsave_data.et[2]); // ETM
ad += 4;
}
// 68040 FSAVE: T0 always
trace_t0_68040();
} else { /* 68881/68882 */
uae_u32 biu_flags = 0x540effff;
int frame_size = currprefs.fpu_model == 68882 ? 0x3c : 0x1c;
@ -2165,6 +2175,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
m68k_areg (regs, opcode & 7) = ad;
if ((opcode & 0x38) == 0x20)
m68k_areg (regs, opcode & 7) = ad;
trace_t0_68040();
} else {
/* FMOVEM Memory->Control Register */
uae_u32 ad;
@ -2254,6 +2265,7 @@ static void fpuop_arithmetic2 (uae_u32 opcode, uae_u16 extra)
if (extra & 0x2000) {
/* FMOVEM FPP->Memory */
ad = fmovem2mem (ad, list, incr, regdir);
trace_t0_68040();
} else {
/* FMOVEM Memory->FPP */
ad = fmovem2fpp (ad, list, incr, regdir);

10
src/include/cpummu030.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef UAE_CPUMMU030_H
#define UAE_CPUMMU030_H
#include "uae/types.h"
#include "mmu_common.h"
#define MAX_MMU030_ACCESS 9
#endif /* UAE_CPUMMU030_H */

File diff suppressed because it is too large Load diff

View file

@ -2,34 +2,26 @@
#define UAE_MMU_COMMON_H
#include "uae/types.h"
#include "uae/likely.h"
#ifdef __cplusplus
struct m68k_exception {
struct m68k_exception
{
int prb;
m68k_exception (int exc) : prb (exc) {}
operator int() { return prb; }
explicit m68k_exception(int exc) : prb(exc)
{
}
explicit operator int() const { return prb; }
};
#define TRY(var) try
#define CATCH(var) catch(m68k_exception var)
#define THROW(n) throw m68k_exception(n)
#define ENDTRY
#else
/* we are in plain C, just use a stack of long jumps */
#include <setjmp.h>
extern jmp_buf __exbuf;
extern int __exvalue;
#define TRY(DUMMY) __exvalue=setjmp(__exbuf); \
if (__exvalue==0) { __pushtry(&__exbuf);
#define CATCH(x) __poptry(); } else {m68k_exception x=__exvalue;
#define ENDTRY __poptry();}
#define THROW(x) if (__is_catched()) {longjmp(__exbuf,x);}
jmp_buf* __poptry(void);
void __pushtry(jmp_buf *j);
int __is_catched(void);
typedef int m68k_exception;
#endif
/* special status word (access error stack frame) */
/* 68030 */
#define MMU030_SSW_RW 0x0040
#define MMU030_SSW_SIZE_W 0x0020
#endif /* UAE_MMU_COMMON_H */

View file

@ -132,6 +132,7 @@ struct regstruct
uae_u16 irc, ir, db;
volatile uae_atomic spcflags;
uae_u16 write_buffer, read_buffer;
uaecptr usp, isp, msp;
uae_u16 sr;
@ -142,6 +143,7 @@ struct regstruct
flagtype x;
flagtype stopped;
int halted;
int exception;
int intmask;
uae_u32 vbr, sfc, dfc;
@ -154,6 +156,7 @@ struct regstruct
uae_u32 fpcr, fpsr, fpiar;
uae_u32 fpu_state;
uae_u32 fpu_exp_state;
uae_u16 fp_opword;
uaecptr fp_ea;
uae_u32 fp_exp_pend, fp_unimp_pend;
bool fpu_exp_pre;
@ -164,6 +167,7 @@ struct regstruct
uae_u32 cacr, caar;
uae_u32 itt0, itt1, dtt0, dtt1;
uae_u32 tcr, mmusr, urp, srp, buscr;
uae_u32 mmu_fault_addr;
uae_u32 pcr;
uae_u32 address_space_mask;
@ -233,7 +237,7 @@ extern void (*x_put_long)(uaecptr addr, uae_u32 v);
#define x_cp_next_iword() next_diword()
#define x_cp_next_ilong() next_dilong()
#define x_cp_get_disp_ea_020(base,idx) _get_disp_ea_020(base)
#define x_cp_get_disp_ea_020(base) _get_disp_ea_020(base)
/* direct (regs.pc_p) access */
@ -325,20 +329,6 @@ STATIC_INLINE void m68k_incpci(int o)
regs.pc += o;
}
STATIC_INLINE void m68k_do_bsri(uaecptr oldpc, uae_s32 offset)
{
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), oldpc);
m68k_incpci(offset);
}
STATIC_INLINE void m68k_do_rtsi(void)
{
uae_u32 newpc = x_get_long(m68k_areg(regs, 7));
m68k_setpci(newpc);
m68k_areg(regs, 7) += 4;
}
/* common access */
STATIC_INLINE void m68k_incpc_normal(int o)
@ -370,7 +360,7 @@ extern void m68k_setstopped(void);
extern void m68k_resumestopped(void);
extern void m68k_cancel_idle(void);
#define get_disp_ea_020(base,idx) _get_disp_ea_020(base)
#define get_disp_ea_020(base) _get_disp_ea_020(base)
extern uae_u32 REGPARAM3 _get_disp_ea_020(uae_u32 base) REGPARAM;
extern uae_u32 REGPARAM3 get_bitfield(uae_u32 src, uae_u32 bdata[2], uae_s32 offset, int width) REGPARAM;
@ -389,17 +379,17 @@ extern void doint(void);
extern void dump_counts(void);
extern int m68k_move2c(int, uae_u32*);
extern int m68k_movec2(int, uae_u32*);
extern void m68k_divl(uae_u32, uae_u32, uae_u16);
extern void m68k_mull(uae_u32, uae_u32, uae_u16);
extern bool m68k_divl (uae_u32, uae_u32, uae_u16);
extern bool m68k_mull (uae_u32, uae_u32, uae_u16);
extern void init_m68k(void);
extern void m68k_go(int);
extern int getDivu68kCycles(uae_u32 dividend, uae_u16 divisor);
extern int getDivs68kCycles(uae_s32 dividend, uae_s16 divisor);
extern void divbyzero_special(bool issigned, uae_s32 dst);
extern void setdivuoverflowflags(uae_u32 dividend, uae_u16 divisor);
extern void setdivsoverflowflags(uae_s32 dividend, uae_s16 divisor);
extern void setdivuflags(uae_u32 dividend, uae_u16 divisor);
extern void setdivsflags(uae_s32 dividend, uae_s16 divisor);
extern void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size);
extern void setchk2undefinedflags(uae_u32 lower, uae_u32 upper, uae_u32 val, int size);
extern void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size);
extern void protect_roms(bool);
extern void unprotect_maprom(void);
extern bool is_hardreset(void);
@ -409,6 +399,9 @@ extern void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 s
extern void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcode, uaecptr fault_addr,
uaecptr pc);
extern uae_u32 exception_pc(int nr);
extern void cpu_restore_fixup(void);
extern bool privileged_copro_instruction(uae_u16 opcode);
extern bool generates_group1_exception(uae_u16 opcode);
void ccr_68000_long_move_ae_LZN(uae_s32 src);
void ccr_68000_long_move_ae_LN(uae_s32 src);
@ -443,11 +436,12 @@ extern void fpuop_save(uae_u32);
extern void fpuop_restore(uae_u32);
extern void fpu_reset(void);
extern void exception3_read(uae_u32 opcode, uaecptr addr);
extern void exception3_write(uae_u32 opcode, uaecptr addr);
extern void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc);
extern void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc);
extern void exception3i(uae_u32 opcode, uaecptr addr);
extern void exception3b(uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc);
extern void exception2(uaecptr addr, bool read, int size, uae_u32 fc);
extern void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc);
extern void cpureset(void);
extern void cpu_halt(int id);
extern int cpu_sleep_millis(int ms);

View file

@ -35,7 +35,7 @@ ENUMDECL {
i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16,
i_MMUOP030, i_PFLUSHN, i_PFLUSH, i_PFLUSHAN, i_PFLUSHA,
i_PLPAR, i_PLPAW, i_PTESTR, i_PTESTW,
i_LPSTOP,
i_LPSTOP, i_HALT, i_PULSE,
MAX_OPCODE_FAMILY
} ENUMNAME (instrmnem);
@ -110,7 +110,7 @@ extern struct instr {
unsigned int cc:4;
unsigned int plev:2;
unsigned int size:2;
unsigned int unsized:1;
unsigned int unsized:1;
unsigned int smode:5;
unsigned int stype:3;
unsigned int dmode:5;

View file

@ -44,7 +44,11 @@ typedef uae_u32 uintptr;
#define TAGMASK 0x0000ffff
#define TAGSIZE (TAGMASK+1)
#define MAXRUN 1024
#define cacheline(x) (((uintptr)x)&TAGMASK)
#if defined(CPU_AARCH64)
#define cacheline(x) (((uae_u64)x)&TAGMASK)
#else
#define cacheline(x) (((uae_u32)x)&TAGMASK)
#endif
extern uae_u8* start_pc_p;
extern uae_u32 start_pc;
@ -360,7 +364,7 @@ typedef struct blockinfo_t {
#define BI_COMPILING 5
#define BI_FINALIZING 6
#if defined(CPU_arm) && !defined(ARMV6T2)
#if defined(CPU_arm) && !defined(ARMV6T2) && !defined(CPU_AARCH64)
const int POPALLSPACE_SIZE = 2048; /* That should be enough space */
#else
const int POPALLSPACE_SIZE = 512; /* That should be enough space */

View file

@ -40,8 +40,12 @@ static uaecptr last_addr_for_exception_3;
static uaecptr last_fault_for_exception_3;
/* read (0) or write (1) access */
static bool last_writeaccess_for_exception_3;
/* instruction (1) or data (0) access */
static bool last_instructionaccess_for_exception_3;
/* size */
static bool last_size_for_exception_3;
/* FC */
static int last_fc_for_exception_3;
/* Data (1) or instruction fetch (0) */
static int last_di_for_exception_3;
/* not instruction */
static bool last_notinstruction_for_exception_3;
/* set when writing exception stack frame */
@ -81,7 +85,7 @@ static uae_u16 fake_mmusr_030;
int cpu_last_stop_vpos, cpu_stopped_lines;
#if COUNT_INSTRS
static uae_u32 instrcount[65536];
static unsigned long instrcount[65536];
static uae_u16 opcodenums[65536];
static int compfn (const void *el1, const void *el2)
@ -100,7 +104,7 @@ static TCHAR *icountfilename (void)
void dump_counts (void)
{
FILE *f = fopen (icountfilename (), "w");
uae_u32 total;
unsigned long total;
int i;
write_log (_T("Writing instruction count file...\n"));
@ -112,7 +116,7 @@ void dump_counts (void)
fprintf (f, "Total: %lu\n", total);
for (i=0; i < 65536; i++) {
uae_u32 cnt = instrcount[opcodenums[i]];
unsigned long cnt = instrcount[opcodenums[i]];
struct instr *dp;
struct mnemolookup *lookup;
if (!cnt)
@ -284,7 +288,7 @@ static const struct cputbl* cputbls[5][3] =
static void build_cpufunctbl(void)
{
int i;
uae_u32 opcode;
unsigned long opcode;
const struct cputbl* tbl = nullptr;
int lvl, mode;
@ -653,7 +657,7 @@ void REGPARAM2 MakeSR(void)
| GET_CFLG());
}
STATIC_INLINE void MakeFromSR_x(int t0trace)
static void MakeFromSR_x(int t0trace)
{
int oldm = regs.m;
int olds = regs.s;
@ -760,8 +764,7 @@ void REGPARAM2 MakeFromSR(void)
static void exception_check_trace(int nr)
{
unset_special(SPCFLAG_TRACE | SPCFLAG_DOTRACE);
if (regs.t1 && !regs.t0)
{
if (regs.t1) {
/* trace stays pending if exception is div by zero, chk,
* trapv or trap #x
*/
@ -876,7 +879,7 @@ static void add_approximate_exception_cycles(int nr)
static void exception3_notinstruction(uae_u32 opcode, uaecptr addr);
void Exception(int nr)
static void Exception_normal (int nr)
{
uae_u32 newpc;
uae_u32 currpc = m68k_getpc();
@ -887,11 +890,6 @@ void Exception(int nr)
interrupt = nr >= 24 && nr < 24 + 8;
#ifdef JIT
if (currprefs.cachesize)
regs.instruction_pc = m68k_getpc();
#endif
if (interrupt && currprefs.cpu_model <= 68010)
vector_nr = iack_cycle(nr);
@ -984,25 +982,27 @@ void Exception(int nr)
else if (currprefs.cpu_model >= 68020)
{
// 68020/030 odd PC address error (partially implemented only)
uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
ssw |= last_writeaccess_for_exception_3 ? 0 : 0x40;
ssw |= 0x20;
Exception_build_stack_frame(oldpc, currpc, ssw, nr, 0x0a);
// annoyingly this generates frame B, not A.
uae_u16 ssw = (sv ? 4 : 0) | last_fc_for_exception_3;
ssw |= MMU030_SSW_RW | MMU030_SSW_SIZE_W;
regs.mmu_fault_addr = last_fault_for_exception_3;
Exception_build_stack_frame(last_fault_for_exception_3, currpc, ssw, nr, 0x0b);
used_exception_build_stack_frame = true;
}
else
{
// 68010 address error (partially implemented only)
uae_u16 ssw = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
ssw |= last_writeaccess_for_exception_3 ? 0 : 0x100;
ssw |= last_instructionaccess_for_exception_3 ? 0 : 0x2000;
} else {
// 68010 bus/address error (partially implemented only)
uae_u16 ssw = (sv ? 4 : 0) | last_fc_for_exception_3;
ssw |= last_di_for_exception_3 ? 0x0000 : 0x2000; // IF
ssw |= (!last_writeaccess_for_exception_3 && last_di_for_exception_3) ? 0x1000 : 0x000; // DF
ssw |= (last_op_for_exception_3 & 0x10000) ? 0x0400 : 0x0000; // HB
ssw |= last_size_for_exception_3 == 0 ? 0x0200 : 0x0000; // BY
ssw |= last_writeaccess_for_exception_3 ? 0x0000 : 0x0100; // RW
if (last_op_for_exception_3 & 0x20000)
ssw &= 0x00ff;
regs.mmu_fault_addr = last_addr_for_exception_3;
Exception_build_stack_frame(oldpc, currpc, ssw, nr, 0x08);
used_exception_build_stack_frame = true;
}
}
else if (regs.m && interrupt)
{
/* M + Interrupt */
} else if (regs.m && interrupt) { /* M + Interrupt */
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), vector_nr * 4);
m68k_areg(regs, 7) -= 4;
@ -1025,19 +1025,13 @@ void Exception(int nr)
else
{
nextpc = m68k_getpc();
if (nr == 2 || nr == 3)
{
// 68000 bus error/address error
uae_u16 mode = (sv ? 4 : 0) | (last_instructionaccess_for_exception_3 ? 2 : 1);
if (nr == 2 || nr == 3) {
// 68000 bus/address error
uae_u16 mode = (sv ? 4 : 0) | last_fc_for_exception_3;
mode |= last_writeaccess_for_exception_3 ? 0 : 16;
mode |= last_notinstruction_for_exception_3 ? 8 : 0;
uae_u16 statusormask = (last_op_for_exception_3 >> 16) & 0xff;
uae_u16 statusandmask = (last_op_for_exception_3 >> 24) & 0xff;
mode |= statusormask;
mode &= ~statusandmask;
exception_in_exception = -1;
Exception_build_68000_address_error_stack_frame(mode, last_op_for_exception_3, last_fault_for_exception_3,
last_addr_for_exception_3);
Exception_build_68000_address_error_stack_frame(mode, last_op_for_exception_3, last_fault_for_exception_3, last_addr_for_exception_3);
goto kludge_me_do;
}
}
@ -1069,16 +1063,38 @@ kludge_me_do:
exception_check_trace(nr);
}
// address = format $2 stack frame address field
static void ExceptionX (int nr)
{
regs.exception = nr;
#ifdef JIT
if (currprefs.cachesize)
regs.instruction_pc = m68k_getpc ();
#endif
{
Exception_normal(nr);
}
regs.exception = 0;
}
void REGPARAM2 Exception_cpu(int nr)
{
bool t0 = currprefs.cpu_model >= 68020 && regs.t0;
Exception(nr);
// check T0 trace
if (t0)
{
bool t0 = currprefs.cpu_model >= 68020 && regs.t0 && !regs.t1;
ExceptionX (nr);
// Check T0 trace
// RTE format error ignores T0 trace
if (nr != 14) {
if (t0) {
activate_trace();
}
}
}
void REGPARAM2 Exception (int nr)
{
ExceptionX (nr);
}
static void bus_error(void)
{
@ -1114,6 +1130,13 @@ void NMI(void)
do_interrupt(7);
}
static void maybe_disable_fpu(void)
{
if (!currprefs.fpu_model) {
regs.pcr |= 2;
}
}
static void m68k_reset_sr(void)
{
SET_XFLG((regs.sr >> 4) & 1);
@ -1147,13 +1170,13 @@ static void m68k_reset(bool hardreset)
regs.spcflags = 0;
#ifdef SAVESTATE
if (isrestore())
{
if (isrestore ()) {
m68k_reset_sr();
m68k_setpc_normal(regs.pc);
return;
} else {
set_special(SPCFLAG_CHECK);
}
set_special(SPCFLAG_CHECK);
#endif
regs.s = 1;
v = get_long(4);
@ -1255,9 +1278,13 @@ uae_u32 REGPARAM2 op_illg(uae_u32 opcode)
}
#endif
if ((opcode & 0xF000) == 0xF000)
{
if ((opcode & 0xF000) == 0xF000) {
// Missing MMU or FPU cpSAVE/cpRESTORE privilege check
if (privileged_copro_instruction(opcode)) {
Exception(8);
} else {
Exception(0xB);
}
return 4;
}
if ((opcode & 0xF000) == 0xA000)
@ -1535,8 +1562,7 @@ void mmu_op(uae_u32 opcode, uae_u32 extra)
static void do_trace(void)
{
if (regs.t0 && currprefs.cpu_model >= 68020)
{
if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) {
// this is obsolete
return;
}
@ -1574,8 +1600,7 @@ static void check_uae_int_request(void)
int cpu_sleep_millis(int ms)
{
const auto ret = sleep_millis_main(ms);
return ret;
return sleep_millis_main(ms);
}
static bool haltloop(void)
@ -1637,6 +1662,7 @@ static int do_specialties(int cycles)
/* exit from HRTMon? */
if (hrtmon_flag == ACTION_REPLAY_ACTIVE && !isinhrt)
hrtmon_hide();
/* HRTMon breakpoint? (not via IRQ7) */
if (hrtmon_flag == ACTION_REPLAY_ACTIVATE)
hrtmon_enter();
}
@ -2356,8 +2382,7 @@ uae_u8* save_cpu(int* len, uae_u8* dstptr)
#endif /* SAVESTATE */
static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction,
uaecptr pc, bool plus2)
static void exception3f (uae_u32 opcode, uaecptr addr, bool writeaccess, bool instructionaccess, bool notinstruction, uaecptr pc, int size, bool plus2, int fc)
{
if (currprefs.cpu_model >= 68040)
addr &= ~1;
@ -2381,49 +2406,81 @@ static void exception3f(uae_u32 opcode, uaecptr addr, bool writeaccess, bool ins
last_fault_for_exception_3 = addr;
last_op_for_exception_3 = opcode;
last_writeaccess_for_exception_3 = writeaccess;
last_instructionaccess_for_exception_3 = instructionaccess;
last_fc_for_exception_3 = fc >= 0 ? fc : (instructionaccess ? 2 : 1);
last_notinstruction_for_exception_3 = notinstruction;
last_size_for_exception_3 = size;
Exception(3);
}
static void exception3_notinstruction(uae_u32 opcode, uaecptr addr)
{
exception3f(opcode, addr, true, false, true, 0xffffffff, false);
exception3f (opcode, addr, true, false, true, 0xffffffff, 1, false, -1);
}
void exception3_read(uae_u32 opcode, uaecptr addr)
void exception3_read(uae_u32 opcode, uaecptr addr, int size, int fc)
{
exception3f(opcode, addr, false, false, false, 0xffffffff, false);
bool ni = false;
if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
if (generates_group1_exception(regs.ir) && !(opcode & 0x20000)) {
ni = true;
fc = -1;
}
if (opcode & 0x10000)
ni = true;
opcode = regs.ir;
}
void exception3_write(uae_u32 opcode, uaecptr addr)
exception3f (opcode, addr, false, 0, ni, 0xffffffff, size, false, fc);
}
void exception3_write(uae_u32 opcode, uaecptr addr, int size, uae_u32 val, int fc)
{
exception3f(opcode, addr, true, false, false, 0xffffffff, false);
bool ni = false;
if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
if (generates_group1_exception(regs.ir) && !(opcode & 0x20000)) {
ni = true;
fc = -1;
}
if (opcode & 0x10000)
ni = true;
opcode = regs.ir;
}
exception3f (opcode, addr, true, 0, ni, 0xffffffff, size, false, fc);
regs.write_buffer = val;
}
void exception3i(uae_u32 opcode, uaecptr addr)
{
exception3f(opcode, addr, false, true, false, 0xffffffff, true);
exception3f (opcode, addr, 0, 1, false, 0xffffffff, 1, true, -1);
}
void exception3b(uae_u32 opcode, uaecptr addr, bool w, bool i, uaecptr pc)
{
exception3f(opcode, addr, w, i, false, pc, true);
exception3f (opcode, addr, w, i, false, pc, 1, true, -1);
}
void exception2_setup(uaecptr addr, bool read, int size, uae_u32 fc)
{
uae_u32 opcode = last_op_for_exception_3;
last_addr_for_exception_3 = m68k_getpc();
last_fault_for_exception_3 = addr;
last_writeaccess_for_exception_3 = read == 0;
last_instructionaccess_for_exception_3 = (fc & 1) == 0;
last_fc_for_exception_3 = fc;
last_op_for_exception_3 = regs.opcode;
last_notinstruction_for_exception_3 = exception_in_exception != 0;
last_size_for_exception_3 = size;
last_di_for_exception_3 = 1;
if (currprefs.cpu_model == 68000 && currprefs.cpu_compatible) {
if (generates_group1_exception(regs.ir) && !(opcode & 0x20000)) {
last_notinstruction_for_exception_3 = true;
fc = -1;
}
if (opcode & 0x10000)
last_notinstruction_for_exception_3 = true;
if (!(opcode & 0x20000))
last_op_for_exception_3 = regs.ir;
}
}
void exception2(uaecptr addr, bool read, int size, uae_u32 fc)
{
exception2_setup(addr, read, size, fc);
exception2_setup(addr, read, size == 1 ? 0 : (size == 2 ? 1 : 2), fc);
THROW(2);
}
@ -2435,6 +2492,7 @@ void cpureset(void)
uae_u16 ins;
addrbank* ab;
maybe_disable_fpu();
set_special(SPCFLAG_CHECK);
send_internalevent(INTERNALEVENT_CPURESET);
if (currprefs.cpu_compatible && currprefs.cpu_model <= 68020)
@ -2495,8 +2553,7 @@ void m68k_resumestopped(void)
void check_t0_trace(void)
{
if (regs.t0 && currprefs.cpu_model >= 68020)
{
if (regs.t0 && !regs.t1 && currprefs.cpu_model >= 68020) {
unset_special(SPCFLAG_TRACE);
set_special(SPCFLAG_DOTRACE);
}

View file

@ -3,6 +3,7 @@
#include "options.h"
#include "memory.h"
#include "newcpu.h"
#include "cpummu030.h"
int get_cpu_model(void)
{
@ -42,9 +43,17 @@ static int movec_illg (int regno)
int m68k_move2c (int regno, uae_u32 *regp)
{
if (movec_illg (regno)) {
if (!regs.s) {
Exception(8);
return 0;
}
op_illg (0x4E7B);
return 0;
} else {
if (!regs.s) {
Exception(8);
return 0;
}
switch (regno) {
case 0: regs.sfc = *regp & 7; break;
case 1: regs.dfc = *regp & 7; break;
@ -61,18 +70,15 @@ int m68k_move2c (int regno, uae_u32 *regp)
set_cpu_caches(false);
}
break;
/* 68040/060 only */
/* 68040 only */
case 3:
regs.tcr = *regp & 0xc000;
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;
@ -81,9 +87,9 @@ int m68k_move2c (int regno, uae_u32 *regp)
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 stores all bits, 68060 zeroes low 9 bits */
case 0x806: regs.urp = *regp; break;
case 0x807: regs.srp = *regp; break;
/* 68040 stores all bits */
case 0x806: regs.urp = *regp & 0xffffffff; break;
case 0x807: regs.srp = *regp & 0xffffffff; break;
default:
op_illg (0x4E7B);
return 0;
@ -95,9 +101,17 @@ int m68k_move2c (int regno, uae_u32 *regp)
int m68k_movec2 (int regno, uae_u32 *regp)
{
if (movec_illg (regno)) {
if (!regs.s) {
Exception(8);
return 0;
}
op_illg (0x4E7A);
return 0;
} else {
if (!regs.s) {
Exception(8);
return 0;
}
switch (regno) {
case 0: *regp = regs.sfc; break;
case 1: *regp = regs.dfc; break;
@ -229,7 +243,6 @@ uae_u32 REGPARAM2 _get_disp_ea_020 (uae_u32 base)
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;
@ -396,7 +409,7 @@ int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor)
*
* 68000 Signed: NVC=0 Z=1. Unsigned: VC=0 N=(dst>>16)<0 Z=(dst>>16)==0
* 68020 and 68030: Signed: Z=1 NC=0. V=? (sometimes random!) Unsigned: V=1, N=(dst>>16)<0 Z=(dst>>16)==0, C=0.
* 68040/68060 C=0.
* 68040 C=0.
*
*/
void divbyzero_special (bool issigned, uae_s32 dst)
@ -413,7 +426,7 @@ void divbyzero_special (bool issigned, uae_s32 dst)
SET_ZFLG(1);
SET_VFLG (1);
}
} else if (currprefs.cpu_model >= 68040) {
} else if (currprefs.cpu_model == 68040) {
SET_CFLG (0);
} else {
// 68000/010
@ -432,47 +445,58 @@ void divbyzero_special (bool issigned, uae_s32 dst)
/* DIVU overflow
*
* 68000: V=1 N=1
* 68020: V=1 N=X
* 68040: V=1
* 68060: V=1
* 68000: V=1, N=1, C=0, Z=0
* 68010: V=1, N=divisor<0x8000, C=0, Z=divided upper word == 0xffff and divisor == 0xffff
* 68020: V=1, C=0, Z=0, N=X
* 68040: V=1, C=0, NZ not modified.
*
* X) N is set if original 32-bit destination value is negative.
*
*/
void setdivuoverflowflags(uae_u32 dividend, uae_u16 divisor)
void setdivuflags(uae_u32 dividend, uae_u16 divisor)
{
if (currprefs.cpu_model >= 68040) {
if (currprefs.cpu_model == 68040) {
SET_VFLG(1);
SET_CFLG(0);
} else if (currprefs.cpu_model >= 68020) {
SET_VFLG(1);
if ((uae_s32)dividend < 0)
SET_NFLG(1);
} else if (currprefs.cpu_model == 68010) {
SET_VFLG(1);
SET_NFLG(divisor < 0x8000);
// can anyone explain this?
SET_ZFLG((dividend >> 16) == 0xffff && divisor == 0xffff);
SET_CFLG(0);
} else {
// 68000
SET_VFLG(1);
SET_NFLG(1);
SET_ZFLG(0);
SET_CFLG(0);
}
}
/*
* DIVS overflow
*
* 68000: V = 1 N = 1
* 68020: V = 1 ZN = X
* 68040: V = 1
* 68060: V = 1
* 68000: V=1, C=0, N=1, Z=0
* 68020: V=1, C=0, ZN = X
* 68040: V=1, C=0. NZ not modified.
*
* X) if absolute overflow(Check getDivs68kCycles for details) : Z = 0, N = 0
* if not absolute overflow : N is set if internal result BYTE is negative, Z is set if it is zero!
*
*/
void setdivsoverflowflags(uae_s32 dividend, uae_s16 divisor)
void setdivsflags(uae_s32 dividend, uae_s16 divisor)
{
if (currprefs.cpu_model >= 68040) {
if (currprefs.cpu_model == 68040) {
SET_VFLG(1);
SET_CFLG(0);
} else if (currprefs.cpu_model >= 68020) {
CLEAR_CZNV();
SET_VFLG(1);
// absolute overflow?
if (((uae_u32)abs(dividend) >> 16) >= (uae_u16)abs(divisor))
@ -482,23 +506,30 @@ void setdivsoverflowflags(uae_s32 dividend, uae_s16 divisor)
SET_ZFLG(1);
if ((uae_s8)aquot < 0)
SET_NFLG(1);
} else if (currprefs.cpu_model == 68010) {
CLEAR_CZNV();
SET_VFLG(1);
SET_NFLG(1);
} else {
// 68000
CLEAR_CZNV();
SET_VFLG(1);
SET_NFLG(1);
}
}
/*
* CHK.W undefined flags
* CHK undefined flags
*
* 68000: CV=0. Z: dst==0. N: dst < 0. !N: dst > src.
* 68020: Z: dst==0. N: dst < 0. V: src-dst overflow. C: if dst < 0: (dst > src || src >= 0), if dst > src: (src >= 0).
* 68040: C=0. C=1 if exception and (dst < 0 && src >= 0) || (src >= 0 && dst >= src) || (dst < 0 && src < dst)
*
*/
void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size)
{
CLEAR_CZNV();
if (currprefs.cpu_model < 68020) {
CLEAR_CZNV();
if (dst == 0)
SET_ZFLG(1);
if (dst < 0)
@ -506,6 +537,7 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size)
else if (dst > src)
SET_NFLG(0);
} else if (currprefs.cpu_model == 68020 || currprefs.cpu_model == 68030) {
CLEAR_CZNV();
if (dst == 0)
SET_ZFLG(1);
SET_NFLG(dst < 0);
@ -529,72 +561,200 @@ void setchkundefinedflags(uae_s32 src, uae_s32 dst, int size)
SET_CFLG(src >= 0);
}
}
} else if (currprefs.cpu_model == 68040) {
SET_CFLG(0);
if (dst < 0 || dst > src) {
if (dst < 0 && src >= 0) {
SET_CFLG(1);
} else if (src >= 0 && dst >= src) {
SET_CFLG(1);
} else if (dst < 0 && src < dst) {
SET_CFLG(1);
}
}
SET_NFLG(dst < 0);
}
}
void setchk2undefinedflags(uae_u32 lower, uae_u32 upper, uae_u32 val, int size)
/*
* CHK2/CMP2 undefined flags
*
* 68020-68030: See below..
* 68040: NV not modified.
*
*/
// This is the complex one.
// Someone else can attempt to simplify this..
void setchk2undefinedflags(uae_s32 lower, uae_s32 upper, uae_s32 val, int size)
{
uae_u32 nmask;
if (size == sz_byte)
nmask = 0x80;
else if (size == sz_word)
nmask = 0x8000;
else
nmask = 0x80000000;
if (currprefs.cpu_model == 68040) {
return;
}
SET_NFLG(0);
if ((upper & nmask) && val > upper) {
SET_NFLG(1);
} else if (!(upper & nmask) && val > upper && val < nmask) {
SET_NFLG(1);
} else if (val < lower) {
SET_NFLG(1);
}
SET_VFLG(0);
}
#if !defined (uae_s64)
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 (val == lower || val == upper)
return;
if (div <= src_hi) {
return 1;
if (lower < 0 && upper >= 0) {
if (val < lower) {
SET_NFLG(1);
}
if (val >= 0 && val < upper) {
SET_NFLG(1);
}
if (val >= 0 && lower - val >= 0) {
SET_VFLG(1);
SET_NFLG(0);
if (val > upper) {
SET_NFLG(1);
}
}
} else if (lower >= 0 && upper < 0) {
if (val >= 0) {
SET_NFLG(1);
}
if (val > upper) {
SET_NFLG(1);
}
if (val > lower && upper - val >= 0) {
SET_VFLG(1);
SET_NFLG(0);
}
} else if (lower >= 0 && upper >= 0 && lower > upper) {
if (val > upper && val < lower) {
SET_NFLG(1);
}
if (val < 0 && lower - val < 0) {
SET_VFLG(1);
}
if (val < 0 && lower - val >= 0) {
SET_NFLG(1);
}
} else if (lower >= 0 && upper >= 0 && lower <= upper) {
if (val >= 0 && val < lower) {
SET_NFLG(1);
}
if (val > upper) {
SET_NFLG(1);
}
if (val < 0 && upper - val < 0) {
SET_VFLG(1);
SET_NFLG(1);
}
} else if (lower < 0 && upper < 0 && lower > upper) {
if (val >= 0) {
SET_NFLG(1);
}
if (val > upper && val < lower) {
SET_NFLG(1);
}
if (val >= 0 && val - lower < 0) {
SET_NFLG(0);
SET_VFLG(1);
}
} else if (lower < 0 && upper < 0 && lower <= upper) {
if (val < lower) {
SET_NFLG(1);
}
if (val < 0 && val > upper) {
SET_NFLG(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;
if (val >= 0 && val - lower < 0) {
SET_NFLG(1);
SET_VFLG(1);
}
}
*quot = q;
*rem = src_hi;
return 0;
}
#endif
static void divl_overflow(void)
static void divsl_overflow(uae_u16 extra, uae_s64 a, uae_s32 divider)
{
if (currprefs.cpu_model >= 68040) {
SET_VFLG(1);
SET_CFLG(0);
} else {
uae_s32 a32 = (uae_s32)a;
bool neg64 = a < 0;
bool neg32 = a32 < 0;
SET_VFLG(1);
if (extra & 0x0400) {
// this is still missing condition where Z is set
// without none of input parameters being zero.
uae_s32 ahigh = a >> 32;
if (ahigh == 0) {
SET_ZFLG(1);
SET_NFLG(0);
} else if (ahigh < 0 && divider < 0 && ahigh > divider) {
SET_ZFLG(0);
SET_NFLG(0);
} else {
if (a32 == 0) {
SET_ZFLG(1);
SET_NFLG(0);
} else {
SET_ZFLG(0);
SET_NFLG(neg32 ^ neg64);
}
}
} else {
if (a32 == 0) {
SET_ZFLG(1);
SET_NFLG(0);
} else {
SET_NFLG(neg32);
SET_ZFLG(0);
}
}
SET_CFLG(0);
}
}
static void divul_overflow(uae_u16 extra, uae_s64 a)
{
if (currprefs.cpu_model >= 68040) {
SET_VFLG(1);
SET_CFLG(0);
} else {
uae_s32 a32 = (uae_s32)a;
bool neg32 = a32 < 0;
SET_VFLG(1);
SET_NFLG(neg32);
SET_ZFLG(a32 == 0);
SET_CFLG(0);
}
}
static void divsl_divbyzero(uae_u16 extra, uae_s64 a)
{
if (currprefs.cpu_model >= 68040) {
SET_CFLG(0);
} else {
SET_NFLG(0);
SET_ZFLG(1);
SET_CFLG(0);
}
Exception_cpu(5);
}
static void divul_divbyzero(uae_u16 extra, uae_s64 a)
{
if (currprefs.cpu_model >= 68040) {
SET_CFLG(0);
} else {
uae_s32 a32 = (uae_s32)a;
bool neg32 = a32 < 0;
SET_NFLG(neg32);
SET_ZFLG(a32 == 0);
SET_VFLG(1);
SET_NFLG(1);
SET_CFLG(0);
SET_ZFLG(0);
}
Exception_cpu(5);
}
void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra)
bool m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra)
{
// Done in caller
//if (src == 0) {
// Exception_cpu (5);
// return;
//}
#if defined(uae_s64)
if (extra & 0x800) {
/* signed variant */
uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
@ -605,15 +765,20 @@ void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra)
a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32;
}
if (src == 0) {
divsl_divbyzero(extra, a);
return false;
}
if ((uae_u64)a == 0x8000000000000000UL && src == ~0u) {
divl_overflow();
divsl_overflow(extra, a, src);
} else {
rem = a % (uae_s64)(uae_s32)src;
quot = a / (uae_s64)(uae_s32)src;
if ((quot & UVAL64(0xffffffff80000000)) != 0
&& (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
{
divl_overflow();
divsl_overflow(extra, a, src);
} else {
if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem;
SET_VFLG (0);
@ -633,10 +798,16 @@ void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra)
a &= 0xffffffffu;
a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32;
}
if (src == 0) {
divul_divbyzero(extra, a);
return false;
}
rem = a % (uae_u64)src;
quot = a / (uae_u64)src;
if (quot > 0xffffffffu) {
divl_overflow();
divul_overflow(extra, a);
} else {
SET_VFLG (0);
SET_CFLG (0);
@ -646,85 +817,11 @@ void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra)
m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)quot;
}
}
#else
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, &quot, &rem) ||
(sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
divl_overflow();
} 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, &quot, &rem)) {
divl_overflow();
} 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
return true;
}
#if !defined (uae_s64)
STATIC_INLINE void mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo)
bool m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
{
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;
}
#endif
void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
{
#if defined(uae_s64)
if (extra & 0x800) {
/* signed */
uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
@ -734,8 +831,15 @@ void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
SET_CFLG (0);
if (extra & 0x400) {
// 32 * 32 = 64
// 68040 is different.
if (currprefs.cpu_model >= 68040) {
m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
} else {
// 020/030
m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
}
SET_ZFLG (a == 0);
SET_NFLG (a < 0);
} else {
@ -757,8 +861,15 @@ void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
SET_CFLG (0);
if (extra & 0x400) {
// 32 * 32 = 64
// 68040 is different.
if (currprefs.cpu_model >= 68040) {
m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
} else {
// 020/030
m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
m68k_dreg(regs, extra & 7) = (uae_u32)(a >> 32);
}
SET_ZFLG (a == 0);
SET_NFLG (((uae_s64)a) < 0);
} else {
@ -772,60 +883,7 @@ void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
SET_NFLG(b < 0);
}
}
#else
if (extra & 0x800) {
/* signed */
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);
if (extra & 0x400) {
m68k_dreg(regs, extra & 7) = dst_hi;
SET_ZFLG (dst_hi == 0 && dst_lo == 0);
SET_NFLG (((uae_s32)dst_hi) < 0);
} else {
if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0) && ((dst_hi & 0xffffffff) != 0xffffffff || (dst_lo & 0x80000000) != 0x80000000)) {
SET_VFLG (1);
}
SET_ZFLG(dst_lo == 0);
SET_NFLG(((uae_s32)dst_lo) < 0);
}
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);
if (extra & 0x400) {
m68k_dreg(regs, extra & 7) = dst_hi;
SET_ZFLG (dst_hi == 0 && dst_lo == 0);
SET_NFLG (((uae_s32)dst_hi) < 0);
} else {
if (dst_hi != 0) {
SET_VFLG (1);
}
SET_ZFLG(dst_lo == 0);
SET_NFLG(((uae_s32)dst_lo) < 0);
}
m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
}
#endif
return true;
}
uae_u32 exception_pc(int nr)
@ -838,6 +896,8 @@ uae_u32 exception_pc(int nr)
void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int nr, int format)
{
int i;
switch (format) {
case 0x0: // four word stack frame
case 0x1: // throwaway four word stack frame
@ -856,30 +916,113 @@ void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int
m68k_areg (regs, 7) -= 4;
x_put_long (m68k_areg (regs, 7), oldpc);
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), 0);
}
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), 0); // WB2A
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0); // 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), 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) -= 4;
x_put_long(m68k_areg(regs, 7), 0);
break;
case 0x8: // address error (68010)
for (int i = 0; i < 15; i++) {
{
uae_u16 in = regs.read_buffer;
uae_u16 out = regs.write_buffer;
for (i = 0; i < 15; i++) {
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); // version
x_put_word(m68k_areg(regs, 7), 0x0000); // version (probably bits 12 to 15 only because other bits change)
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), regs.opcode); // instruction input buffer
x_put_word(m68k_areg(regs, 7), regs.irc); // instruction input buffer
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), 0); // unused
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), 0); // data input buffer
x_put_word(m68k_areg(regs, 7), in); // data input buffer
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), 0); // unused
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), 0); // data output buffer
x_put_word(m68k_areg(regs, 7), out); // data output buffer
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), 0); // unused
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0); // fault addr
x_put_long(m68k_areg(regs, 7), regs.mmu_fault_addr); // fault addr
m68k_areg(regs, 7) -= 2;
x_put_word(m68k_areg(regs, 7), ssw); // ssw
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 0xB: // long bus cycle fault stack frame (68020, 68030)
// Store state information to internal register space
for (i = 0; i < 1; i++) {
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0);
}
while (i < MAX_MMU030_ACCESS) {
uae_u32 v = 0;
m68k_areg(regs, 7) -= 4;
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), 0);
// 3* internal registers
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);
// 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) -= 4;
x_put_long(m68k_areg(regs, 7), 0);
}
// stage b address
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0);
// 2xinternal
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0);
/* fall through */
case 0xA:
// short bus cycle fault stack frame (68020, 68030)
// used when instruction's last write causes bus fault
@ -889,9 +1032,13 @@ void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int
// Data output buffer = value that was going to be written
x_put_long(m68k_areg(regs, 7), 0);
m68k_areg(regs, 7) -= 4;
if (format == 0xb) {
x_put_long(m68k_areg(regs, 7), 0); // Internal register (opcode storage)
} else {
x_put_long(m68k_areg(regs, 7), regs.irc); // Internal register (opcode storage)
}
m68k_areg(regs, 7) -= 4;
x_put_long(m68k_areg(regs, 7), 0); // data cycle fault address
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;
@ -899,7 +1046,7 @@ void Exception_build_stack_frame(uae_u32 oldpc, uae_u32 currpc, uae_u32 ssw, int
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); // = mmu030_state[1]);
x_put_word(m68k_areg(regs, 7), 0);
break;
default:
write_log(_T("Unknown exception stack frame format: %X\n"), format);
@ -952,7 +1099,15 @@ void Exception_build_68000_address_error_stack_frame(uae_u16 mode, uae_u16 opcod
x_put_long(m68k_areg(regs, 7) + 10, pc);
}
// Low word: Z and N
void cpu_restore_fixup(void)
{
if (mmufixup[0].reg >= 0) {
m68k_areg(regs, mmufixup[0].reg) = mmufixup[0].value;
mmufixup[0].reg = -1;
}
}
// Low word: Clear + Z and N
void ccr_68000_long_move_ae_LZN(uae_s32 src)
{
CLEAR_CZNV();
@ -961,7 +1116,7 @@ void ccr_68000_long_move_ae_LZN(uae_s32 src)
SET_NFLG(vsrc < 0);
}
// Low word: N only
// Low word: Clear + N only
void ccr_68000_long_move_ae_LN(uae_s32 src)
{
CLEAR_CZNV();
@ -997,3 +1152,46 @@ void ccr_68000_word_move_ae_normal(uae_s16 src)
SET_ZFLG(src == 0);
SET_NFLG(src < 0);
}
// Change F-line to privilege violation if missing co-pro
bool privileged_copro_instruction(uae_u16 opcode)
{
if (currprefs.cpu_model >= 68020 && !regs.s) {
int reg = opcode & 7;
int mode = (opcode >> 3) & 7;
int id = (opcode >> 9) & 7;
// cpSAVE and cpRESTORE: privilege violation if user mode.
if ((opcode & 0xf1c0) == 0xf100) {
// cpSAVE
if (mode == 2 || (mode >= 4 && mode <= 6) || (mode == 7 && (reg == 0 || reg == 1))) {
if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040)
return true;
}
} else if ((opcode & 0xf1c0) == 0xf140) {
// cpRESTORE
if (mode == 2 || mode == 3 || (mode >= 5 && mode <= 6) || (mode == 7 && reg <= 3)) {
if ((currprefs.cpu_model >= 68040 && id > 0) || currprefs.cpu_model < 68040)
return true;
}
}
}
return false;
}
bool generates_group1_exception(uae_u16 opcode)
{
struct instr *table = &table68k[opcode];
// illegal/a-line/f-line?
if (table->mnemo == i_ILLG)
return true;
// privilege violation?
if (!regs.s) {
if (table->plev == 1 && currprefs.cpu_model > 68000)
return true;
if (table->plev == 2)
return true;
if (table->plev == 3 && table->size == sz_word)
return true;
}
return false;
}

View file

@ -101,6 +101,7 @@ struct mnemolookup lookuptab[] = {
{ i_CAS2, _T("CAS2") },
{ i_MULL, _T("MULL") },
{ i_DIVL, _T("DIVL") },
{ i_BFTST, _T("BFTST") },
{ i_BFEXTU, _T("BFEXTU") },
{ i_BFCHG, _T("BFCHG") },
@ -109,6 +110,7 @@ struct mnemolookup lookuptab[] = {
{ i_BFFFO, _T("BFFFO") },
{ i_BFSET, _T("BFSET") },
{ i_BFINS, _T("BFINS") },
{ i_PACK, _T("PACK") },
{ i_UNPK, _T("UNPK") },
{ i_TAS, _T("TAS") },
@ -117,6 +119,7 @@ struct mnemolookup lookuptab[] = {
{ i_RTM, _T("RTM") },
{ i_TRAPcc, _T("TRAPcc") },
{ i_MOVES, _T("MOVES") },
{ i_FPP, _T("FPP") },
{ i_FDBcc, _T("FDBcc") },
{ i_FScc, _T("FScc") },
@ -836,7 +839,7 @@ void read_table68k (void)
static int imismatch;
static void handle_merges (long int opcode)
static void handle_merges (uae_s32 opcode)
{
uae_u16 smsk;
uae_u16 dmsk;
@ -915,7 +918,7 @@ static void handle_merges (long int opcode)
void do_merges (void)
{
long int opcode;
uae_s32 opcode;
int nr = 0;
imismatch = 0;
for (opcode = 0; opcode < 65536; opcode++) {