mirror of
https://github.com/holub/mame
synced 2025-05-25 15:25:33 +03:00
1379 lines
51 KiB
C
1379 lines
51 KiB
C
/***************************************************************************
|
|
|
|
r3000->c
|
|
Core implementation for the portable MIPS R3000 emulator.
|
|
Written by Aaron Giles
|
|
|
|
***************************************************************************/
|
|
|
|
#include "debugger.h"
|
|
#include "r3000.h"
|
|
|
|
|
|
#define ENABLE_OVERFLOWS 0
|
|
|
|
|
|
/***************************************************************************
|
|
CONSTANTS
|
|
***************************************************************************/
|
|
|
|
#define COP0_Index 0
|
|
#define COP0_Random 1
|
|
#define COP0_EntryLo 2
|
|
#define COP0_Context 4
|
|
#define COP0_BadVAddr 8
|
|
#define COP0_Status 12
|
|
#define COP0_Cause 13
|
|
#define COP0_EPC 14
|
|
#define COP0_PRId 15
|
|
|
|
#define SR_IEc 0x00000001
|
|
#define SR_KUc 0x00000002
|
|
#define SR_IEp 0x00000004
|
|
#define SR_KUp 0x00000008
|
|
#define SR_IEo 0x00000010
|
|
#define SR_KUo 0x00000020
|
|
#define SR_IMSW0 0x00000100
|
|
#define SR_IMSW1 0x00000200
|
|
#define SR_IMEX0 0x00000400
|
|
#define SR_IMEX1 0x00000800
|
|
#define SR_IMEX2 0x00001000
|
|
#define SR_IMEX3 0x00002000
|
|
#define SR_IMEX4 0x00004000
|
|
#define SR_IMEX5 0x00008000
|
|
#define SR_IsC 0x00010000
|
|
#define SR_SwC 0x00020000
|
|
#define SR_PZ 0x00040000
|
|
#define SR_CM 0x00080000
|
|
#define SR_PE 0x00100000
|
|
#define SR_TS 0x00200000
|
|
#define SR_BEV 0x00400000
|
|
#define SR_RE 0x02000000
|
|
#define SR_COP0 0x10000000
|
|
#define SR_COP1 0x20000000
|
|
#define SR_COP2 0x40000000
|
|
#define SR_COP3 0x80000000
|
|
|
|
#define EXCEPTION_INTERRUPT 0
|
|
#define EXCEPTION_TLBMOD 1
|
|
#define EXCEPTION_TLBLOAD 2
|
|
#define EXCEPTION_TLBSTORE 3
|
|
#define EXCEPTION_ADDRLOAD 4
|
|
#define EXCEPTION_ADDRSTORE 5
|
|
#define EXCEPTION_BUSINST 6
|
|
#define EXCEPTION_BUSDATA 7
|
|
#define EXCEPTION_SYSCALL 8
|
|
#define EXCEPTION_BREAK 9
|
|
#define EXCEPTION_INVALIDOP 10
|
|
#define EXCEPTION_BADCOP 11
|
|
#define EXCEPTION_OVERFLOW 12
|
|
#define EXCEPTION_TRAP 13
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
HELPER MACROS
|
|
***************************************************************************/
|
|
|
|
#define RSREG ((op >> 21) & 31)
|
|
#define RTREG ((op >> 16) & 31)
|
|
#define RDREG ((op >> 11) & 31)
|
|
#define SHIFT ((op >> 6) & 31)
|
|
|
|
#define RSVAL r[RSREG]
|
|
#define RTVAL r[RTREG]
|
|
#define RDVAL r[RDREG]
|
|
|
|
#define SIMMVAL ((INT16)op)
|
|
#define UIMMVAL ((UINT16)op)
|
|
#define LIMMVAL (op & 0x03ffffff)
|
|
|
|
#define ADDPC(R,x) do { (R)->nextpc = (R)->pc + ((x) << 2); } while (0)
|
|
#define ADDPCL(R,x,l) do { (R)->nextpc = (R)->pc + ((x) << 2); (R)->r[l] = (R)->pc + 4; } while (0)
|
|
#define ABSPC(R,x) do { (R)->nextpc = ((R)->pc & 0xf0000000) | ((x) << 2); } while (0)
|
|
#define ABSPCL(R,x,l) do { (R)->nextpc = ((R)->pc & 0xf0000000) | ((x) << 2); (R)->r[l] = (R)->pc + 4; } while (0)
|
|
#define SETPC(R,x) do { (R)->nextpc = (x); } while (0)
|
|
#define SETPCL(R,x,l) do { (R)->nextpc = (x); (R)->r[l] = (R)->pc + 4; } while (0)
|
|
|
|
#define RBYTE(R,x) (*(R)->cur.read_byte)((R)->program, x)
|
|
#define RWORD(R,x) (*(R)->cur.read_word)((R)->program, x)
|
|
#define RLONG(R,x) (*(R)->cur.read_dword)((R)->program, x)
|
|
|
|
#define WBYTE(R,x,v) (*(R)->cur.write_byte)((R)->program, x, v)
|
|
#define WWORD(R,x,v) (*(R)->cur.write_word)((R)->program, x, v)
|
|
#define WLONG(R,x,v) (*(R)->cur.write_dword)((R)->program, x, v)
|
|
|
|
#define SR cpr[0][COP0_Status]
|
|
#define CAUSE cpr[0][COP0_Cause]
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
STRUCTURES & TYPEDEFS
|
|
***************************************************************************/
|
|
|
|
/* R3000 Registers */
|
|
typedef struct _r3000_state r3000_state;
|
|
struct _r3000_state
|
|
{
|
|
/* core registers */
|
|
UINT32 pc;
|
|
UINT32 hi;
|
|
UINT32 lo;
|
|
UINT32 r[32];
|
|
|
|
/* COP registers */
|
|
UINT32 cpr[4][32];
|
|
UINT32 ccr[4][32];
|
|
UINT8 cf[4];
|
|
|
|
/* internal stuff */
|
|
UINT32 ppc;
|
|
UINT32 nextpc;
|
|
int op;
|
|
int icount;
|
|
int interrupt_cycles;
|
|
int hasfpu;
|
|
cpu_irq_callback irq_callback;
|
|
const device_config *device;
|
|
const address_space *program;
|
|
|
|
/* endian-dependent load/store */
|
|
void (*lwl)(r3000_state *r3000, UINT32 op);
|
|
void (*lwr)(r3000_state *r3000, UINT32 op);
|
|
void (*swl)(r3000_state *r3000, UINT32 op);
|
|
void (*swr)(r3000_state *r3000, UINT32 op);
|
|
|
|
/* memory accesses */
|
|
UINT8 bigendian;
|
|
data_accessors cur;
|
|
const data_accessors *memory_hand;
|
|
const data_accessors *cache_hand;
|
|
|
|
/* cache memory */
|
|
UINT32 * cache;
|
|
UINT32 * icache;
|
|
UINT32 * dcache;
|
|
size_t cache_size;
|
|
size_t icache_size;
|
|
size_t dcache_size;
|
|
};
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
FUNCTION PROTOTYPES
|
|
***************************************************************************/
|
|
|
|
static void lwl_be(r3000_state *r3000, UINT32 op);
|
|
static void lwr_be(r3000_state *r3000, UINT32 op);
|
|
static void swl_be(r3000_state *r3000, UINT32 op);
|
|
static void swr_be(r3000_state *r3000, UINT32 op);
|
|
|
|
static void lwl_le(r3000_state *r3000, UINT32 op);
|
|
static void lwr_le(r3000_state *r3000, UINT32 op);
|
|
static void swl_le(r3000_state *r3000, UINT32 op);
|
|
static void swr_le(r3000_state *r3000, UINT32 op);
|
|
|
|
static UINT8 readcache_be(const address_space *space, offs_t offset);
|
|
static UINT16 readcache_be_word(const address_space *space, offs_t offset);
|
|
static UINT32 readcache_be_dword(const address_space *space, offs_t offset);
|
|
static void writecache_be(const address_space *space, offs_t offset, UINT8 data);
|
|
static void writecache_be_word(const address_space *space, offs_t offset, UINT16 data);
|
|
static void writecache_be_dword(const address_space *space, offs_t offset, UINT32 data);
|
|
|
|
static UINT8 readcache_le(const address_space *space, offs_t offset);
|
|
static UINT16 readcache_le_word(const address_space *space, offs_t offset);
|
|
static UINT32 readcache_le_dword(const address_space *space, offs_t offset);
|
|
static void writecache_le(const address_space *space, offs_t offset, UINT8 data);
|
|
static void writecache_le_word(const address_space *space, offs_t offset, UINT16 data);
|
|
static void writecache_le_dword(const address_space *space, offs_t offset, UINT32 data);
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
PRIVATE GLOBAL VARIABLES
|
|
***************************************************************************/
|
|
|
|
static const data_accessors be_cache =
|
|
{
|
|
readcache_be, readcache_be_word, NULL, readcache_be_dword, NULL, NULL, NULL,
|
|
writecache_be, writecache_be_word, NULL, writecache_be_dword, NULL, NULL, NULL
|
|
};
|
|
|
|
static const data_accessors le_cache =
|
|
{
|
|
readcache_le, readcache_le_word, NULL, readcache_le_dword, NULL, NULL, NULL,
|
|
writecache_le, writecache_le_word, NULL, writecache_le_dword, NULL, NULL, NULL
|
|
};
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
MEMORY ACCESSORS
|
|
***************************************************************************/
|
|
|
|
#define ROPCODE(R,pc) memory_decrypted_read_dword((R)->program, pc)
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
EXECEPTION HANDLING
|
|
***************************************************************************/
|
|
|
|
INLINE void generate_exception(r3000_state *r3000, int exception)
|
|
{
|
|
/* set the exception PC */
|
|
r3000->cpr[0][COP0_EPC] = r3000->pc;
|
|
|
|
/* put the cause in the low 8 bits and clear the branch delay flag */
|
|
r3000->CAUSE = (r3000->CAUSE & ~0x800000ff) | (exception << 2);
|
|
|
|
/* if we were in a branch delay slot, adjust */
|
|
if (r3000->nextpc != ~0)
|
|
{
|
|
r3000->nextpc = ~0;
|
|
r3000->cpr[0][COP0_EPC] -= 4;
|
|
r3000->CAUSE |= 0x80000000;
|
|
}
|
|
|
|
/* shift the exception bits */
|
|
r3000->SR = (r3000->SR & 0xffffffc0) | ((r3000->SR << 2) & 0x3c);
|
|
|
|
/* based on the BEV bit, we either go to ROM or RAM */
|
|
r3000->pc = (r3000->SR & SR_BEV) ? 0xbfc00000 : 0x80000000;
|
|
|
|
/* most exceptions go to offset 0x180, except for TLB stuff */
|
|
if (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE)
|
|
r3000->pc += 0x80;
|
|
else
|
|
r3000->pc += 0x180;
|
|
}
|
|
|
|
|
|
INLINE void invalid_instruction(r3000_state *r3000, UINT32 op)
|
|
{
|
|
generate_exception(r3000, EXCEPTION_INVALIDOP);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
IRQ HANDLING
|
|
***************************************************************************/
|
|
|
|
static void check_irqs(r3000_state *r3000)
|
|
{
|
|
if ((r3000->CAUSE & r3000->SR & 0xff00) && (r3000->SR & SR_IEc))
|
|
generate_exception(r3000, EXCEPTION_INTERRUPT);
|
|
}
|
|
|
|
|
|
static void set_irq_line(r3000_state *r3000, int irqline, int state)
|
|
{
|
|
if (state != CLEAR_LINE)
|
|
r3000->CAUSE |= 0x400 << irqline;
|
|
else
|
|
r3000->CAUSE &= ~(0x400 << irqline);
|
|
check_irqs(r3000);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
INITIALIZATION AND SHUTDOWN
|
|
***************************************************************************/
|
|
|
|
static CPU_INIT( r3000 )
|
|
{
|
|
const r3000_cpu_core *configdata = device->static_config;
|
|
r3000_state *r3000 = device->token;
|
|
|
|
/* allocate memory */
|
|
r3000->icache = auto_malloc(configdata->icache);
|
|
r3000->dcache = auto_malloc(configdata->dcache);
|
|
|
|
r3000->icache_size = configdata->icache;
|
|
r3000->dcache_size = configdata->dcache;
|
|
r3000->hasfpu = configdata->hasfpu;
|
|
|
|
r3000->irq_callback = irqcallback;
|
|
r3000->device = device;
|
|
r3000->program = memory_find_address_space(device, ADDRESS_SPACE_PROGRAM);
|
|
}
|
|
|
|
|
|
static void r3000_reset(r3000_state *r3000, int bigendian)
|
|
{
|
|
/* set up the endianness */
|
|
r3000->bigendian = bigendian;
|
|
if (r3000->bigendian)
|
|
{
|
|
r3000->memory_hand = &r3000->program->accessors;
|
|
r3000->cache_hand = &be_cache;
|
|
r3000->lwl = lwl_be;
|
|
r3000->lwr = lwr_be;
|
|
r3000->swl = swl_be;
|
|
r3000->swr = swr_be;
|
|
}
|
|
else
|
|
{
|
|
r3000->memory_hand = &r3000->program->accessors;
|
|
r3000->cache_hand = &le_cache;
|
|
r3000->lwl = lwl_le;
|
|
r3000->lwr = lwr_le;
|
|
r3000->swl = swl_le;
|
|
r3000->swr = swr_le;
|
|
}
|
|
|
|
/* initialize the rest of the config */
|
|
r3000->cur = *r3000->memory_hand;
|
|
r3000->cache = r3000->dcache;
|
|
r3000->cache_size = r3000->dcache_size;
|
|
|
|
/* initialize the state */
|
|
r3000->pc = 0xbfc00000;
|
|
r3000->nextpc = ~0;
|
|
r3000->cpr[0][COP0_PRId] = 0x0200;
|
|
r3000->cpr[0][COP0_Status] = 0x0000;
|
|
}
|
|
|
|
static CPU_RESET( r3000be )
|
|
{
|
|
r3000_reset(device->token, 1);
|
|
}
|
|
|
|
static CPU_RESET( r3000le )
|
|
{
|
|
r3000_reset(device->token, 0);
|
|
}
|
|
|
|
|
|
static CPU_EXIT( r3000 )
|
|
{
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COP0 (SYSTEM) EXECUTION HANDLING
|
|
***************************************************************************/
|
|
|
|
INLINE UINT32 get_cop0_reg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->cpr[0][idx];
|
|
}
|
|
|
|
INLINE void set_cop0_reg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
if (idx == COP0_Cause)
|
|
{
|
|
r3000->CAUSE = (r3000->CAUSE & 0xfc00) | (val & ~0xfc00);
|
|
|
|
/* update interrupts -- software ints can occur this way */
|
|
check_irqs(r3000);
|
|
}
|
|
else if (idx == COP0_Status)
|
|
{
|
|
UINT32 oldsr = r3000->cpr[0][idx];
|
|
UINT32 diff = oldsr ^ val;
|
|
|
|
/* handle cache isolation */
|
|
if (diff & SR_IsC)
|
|
{
|
|
if (val & SR_IsC)
|
|
r3000->cur = *r3000->cache_hand;
|
|
else
|
|
r3000->cur = *r3000->memory_hand;
|
|
}
|
|
|
|
/* handle cache switching */
|
|
if (diff & SR_SwC)
|
|
{
|
|
if (val & SR_SwC)
|
|
r3000->cache = r3000->icache, r3000->cache_size = r3000->icache_size;
|
|
else
|
|
r3000->cache = r3000->dcache, r3000->cache_size = r3000->dcache_size;
|
|
}
|
|
r3000->cpr[0][idx] = val;
|
|
|
|
/* update interrupts */
|
|
check_irqs(r3000);
|
|
}
|
|
else
|
|
r3000->cpr[0][idx] = val;
|
|
}
|
|
|
|
INLINE UINT32 get_cop0_creg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->ccr[0][idx];
|
|
}
|
|
|
|
INLINE void set_cop0_creg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->ccr[0][idx] = val;
|
|
}
|
|
|
|
INLINE void handle_cop0(r3000_state *r3000, UINT32 op)
|
|
{
|
|
if (!(r3000->SR & SR_COP0) && (r3000->SR & SR_KUc))
|
|
generate_exception(r3000, EXCEPTION_BADCOP);
|
|
|
|
switch (RSREG)
|
|
{
|
|
case 0x00: /* MFCz */ if (RTREG) r3000->RTVAL = get_cop0_reg(r3000, RDREG); break;
|
|
case 0x02: /* CFCz */ if (RTREG) r3000->RTVAL = get_cop0_creg(r3000, RDREG); break;
|
|
case 0x04: /* MTCz */ set_cop0_reg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x06: /* CTCz */ set_cop0_creg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x08: /* BC */
|
|
switch (RTREG)
|
|
{
|
|
case 0x00: /* BCzF */ if (!r3000->cf[0]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x01: /* BCzF */ if (r3000->cf[0]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x02: /* BCzFL */ invalid_instruction(r3000, op); break;
|
|
case 0x03: /* BCzTL */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f: /* COP */
|
|
switch (op & 0x01ffffff)
|
|
{
|
|
case 0x01: /* TLBR */ break;
|
|
case 0x02: /* TLBWI */ break;
|
|
case 0x06: /* TLBWR */ break;
|
|
case 0x08: /* TLBP */ break;
|
|
case 0x10: /* RFE */ r3000->SR = (r3000->SR & 0xfffffff0) | ((r3000->SR >> 2) & 0x0f); break;
|
|
case 0x18: /* ERET */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COP1 (FPU) EXECUTION HANDLING
|
|
***************************************************************************/
|
|
|
|
INLINE UINT32 get_cop1_reg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->cpr[1][idx];
|
|
}
|
|
|
|
INLINE void set_cop1_reg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->cpr[1][idx] = val;
|
|
}
|
|
|
|
INLINE UINT32 get_cop1_creg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->ccr[1][idx];
|
|
}
|
|
|
|
INLINE void set_cop1_creg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->ccr[1][idx] = val;
|
|
}
|
|
|
|
INLINE void handle_cop1(r3000_state *r3000, UINT32 op)
|
|
{
|
|
if (!(r3000->SR & SR_COP1))
|
|
generate_exception(r3000, EXCEPTION_BADCOP);
|
|
if (!r3000->hasfpu)
|
|
return;
|
|
|
|
switch (RSREG)
|
|
{
|
|
case 0x00: /* MFCz */ if (RTREG) r3000->RTVAL = get_cop1_reg(r3000, RDREG); break;
|
|
case 0x02: /* CFCz */ if (RTREG) r3000->RTVAL = get_cop1_creg(r3000, RDREG); break;
|
|
case 0x04: /* MTCz */ set_cop1_reg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x06: /* CTCz */ set_cop1_creg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x08: /* BC */
|
|
switch (RTREG)
|
|
{
|
|
case 0x00: /* BCzF */ if (!r3000->cf[1]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x01: /* BCzF */ if (r3000->cf[1]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x02: /* BCzFL */ invalid_instruction(r3000, op); break;
|
|
case 0x03: /* BCzTL */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f: /* COP */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COP2 (CUSTOM) EXECUTION HANDLING
|
|
***************************************************************************/
|
|
|
|
INLINE UINT32 get_cop2_reg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->cpr[2][idx];
|
|
}
|
|
|
|
INLINE void set_cop2_reg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->cpr[2][idx] = val;
|
|
}
|
|
|
|
INLINE UINT32 get_cop2_creg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->ccr[2][idx];
|
|
}
|
|
|
|
INLINE void set_cop2_creg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->ccr[2][idx] = val;
|
|
}
|
|
|
|
INLINE void handle_cop2(r3000_state *r3000, UINT32 op)
|
|
{
|
|
if (!(r3000->SR & SR_COP2))
|
|
generate_exception(r3000, EXCEPTION_BADCOP);
|
|
|
|
switch (RSREG)
|
|
{
|
|
case 0x00: /* MFCz */ if (RTREG) r3000->RTVAL = get_cop2_reg(r3000, RDREG); break;
|
|
case 0x02: /* CFCz */ if (RTREG) r3000->RTVAL = get_cop2_creg(r3000, RDREG); break;
|
|
case 0x04: /* MTCz */ set_cop2_reg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x06: /* CTCz */ set_cop2_creg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x08: /* BC */
|
|
switch (RTREG)
|
|
{
|
|
case 0x00: /* BCzF */ if (!r3000->cf[2]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x01: /* BCzF */ if (r3000->cf[2]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x02: /* BCzFL */ invalid_instruction(r3000, op); break;
|
|
case 0x03: /* BCzTL */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f: /* COP */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COP3 (CUSTOM) EXECUTION HANDLING
|
|
***************************************************************************/
|
|
|
|
INLINE UINT32 get_cop3_reg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->cpr[3][idx];
|
|
}
|
|
|
|
INLINE void set_cop3_reg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->cpr[3][idx] = val;
|
|
}
|
|
|
|
INLINE UINT32 get_cop3_creg(r3000_state *r3000, int idx)
|
|
{
|
|
return r3000->ccr[3][idx];
|
|
}
|
|
|
|
INLINE void set_cop3_creg(r3000_state *r3000, int idx, UINT32 val)
|
|
{
|
|
r3000->ccr[3][idx] = val;
|
|
}
|
|
|
|
INLINE void handle_cop3(r3000_state *r3000, UINT32 op)
|
|
{
|
|
if (!(r3000->SR & SR_COP3))
|
|
generate_exception(r3000, EXCEPTION_BADCOP);
|
|
|
|
switch (RSREG)
|
|
{
|
|
case 0x00: /* MFCz */ if (RTREG) r3000->RTVAL = get_cop3_reg(r3000, RDREG); break;
|
|
case 0x02: /* CFCz */ if (RTREG) r3000->RTVAL = get_cop3_creg(r3000, RDREG); break;
|
|
case 0x04: /* MTCz */ set_cop3_reg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x06: /* CTCz */ set_cop3_creg(r3000, RDREG, r3000->RTVAL); break;
|
|
case 0x08: /* BC */
|
|
switch (RTREG)
|
|
{
|
|
case 0x00: /* BCzF */ if (!r3000->cf[3]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x01: /* BCzF */ if (r3000->cf[3]) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x02: /* BCzFL */ invalid_instruction(r3000, op); break;
|
|
case 0x03: /* BCzTL */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
case 0x18:
|
|
case 0x19:
|
|
case 0x1a:
|
|
case 0x1b:
|
|
case 0x1c:
|
|
case 0x1d:
|
|
case 0x1e:
|
|
case 0x1f: /* COP */ invalid_instruction(r3000, op); break;
|
|
default: invalid_instruction(r3000, op); break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CORE EXECUTION LOOP
|
|
***************************************************************************/
|
|
|
|
static CPU_EXECUTE( r3000 )
|
|
{
|
|
r3000_state *r3000 = device->token;
|
|
|
|
/* count cycles and interrupt cycles */
|
|
r3000->icount = cycles;
|
|
r3000->icount -= r3000->interrupt_cycles;
|
|
r3000->interrupt_cycles = 0;
|
|
|
|
/* check for IRQs */
|
|
check_irqs(r3000);
|
|
|
|
/* core execution loop */
|
|
do
|
|
{
|
|
UINT32 op;
|
|
UINT64 temp64;
|
|
int temp;
|
|
|
|
/* debugging */
|
|
r3000->ppc = r3000->pc;
|
|
debugger_instruction_hook(device, r3000->pc);
|
|
|
|
/* instruction fetch */
|
|
op = ROPCODE(r3000, r3000->pc);
|
|
|
|
/* adjust for next PC */
|
|
if (r3000->nextpc != ~0)
|
|
{
|
|
r3000->pc = r3000->nextpc;
|
|
r3000->nextpc = ~0;
|
|
}
|
|
else
|
|
r3000->pc += 4;
|
|
|
|
/* parse the instruction */
|
|
switch (op >> 26)
|
|
{
|
|
case 0x00: /* SPECIAL */
|
|
switch (op & 63)
|
|
{
|
|
case 0x00: /* SLL */ if (RDREG) r3000->RDVAL = r3000->RTVAL << SHIFT; break;
|
|
case 0x02: /* SRL */ if (RDREG) r3000->RDVAL = r3000->RTVAL >> SHIFT; break;
|
|
case 0x03: /* SRA */ if (RDREG) r3000->RDVAL = (INT32)r3000->RTVAL >> SHIFT; break;
|
|
case 0x04: /* SLLV */ if (RDREG) r3000->RDVAL = r3000->RTVAL << (r3000->RSVAL & 31); break;
|
|
case 0x06: /* SRLV */ if (RDREG) r3000->RDVAL = r3000->RTVAL >> (r3000->RSVAL & 31); break;
|
|
case 0x07: /* SRAV */ if (RDREG) r3000->RDVAL = (INT32)r3000->RTVAL >> (r3000->RSVAL & 31); break;
|
|
case 0x08: /* JR */ SETPC(r3000, r3000->RSVAL); break;
|
|
case 0x09: /* JALR */ SETPCL(r3000, r3000->RSVAL, RDREG); break;
|
|
case 0x0c: /* SYSCALL */ generate_exception(r3000, EXCEPTION_SYSCALL); break;
|
|
case 0x0d: /* BREAK */ generate_exception(r3000, EXCEPTION_BREAK); break;
|
|
case 0x0f: /* SYNC */ invalid_instruction(r3000, op); break;
|
|
case 0x10: /* MFHI */ if (RDREG) r3000->RDVAL = r3000->hi; break;
|
|
case 0x11: /* MTHI */ r3000->hi = r3000->RSVAL; break;
|
|
case 0x12: /* MFLO */ if (RDREG) r3000->RDVAL = r3000->lo; break;
|
|
case 0x13: /* MTLO */ r3000->lo = r3000->RSVAL; break;
|
|
case 0x18: /* MULT */
|
|
temp64 = (INT64)(INT32)r3000->RSVAL * (INT64)(INT32)r3000->RTVAL;
|
|
r3000->lo = (UINT32)temp64;
|
|
r3000->hi = (UINT32)(temp64 >> 32);
|
|
r3000->icount -= 11;
|
|
break;
|
|
case 0x19: /* MULTU */
|
|
temp64 = (UINT64)r3000->RSVAL * (UINT64)r3000->RTVAL;
|
|
r3000->lo = (UINT32)temp64;
|
|
r3000->hi = (UINT32)(temp64 >> 32);
|
|
r3000->icount -= 11;
|
|
break;
|
|
case 0x1a: /* DIV */
|
|
if (r3000->RTVAL)
|
|
{
|
|
r3000->lo = (INT32)r3000->RSVAL / (INT32)r3000->RTVAL;
|
|
r3000->hi = (INT32)r3000->RSVAL % (INT32)r3000->RTVAL;
|
|
}
|
|
r3000->icount -= 34;
|
|
break;
|
|
case 0x1b: /* DIVU */
|
|
if (r3000->RTVAL)
|
|
{
|
|
r3000->lo = r3000->RSVAL / r3000->RTVAL;
|
|
r3000->hi = r3000->RSVAL % r3000->RTVAL;
|
|
}
|
|
r3000->icount -= 34;
|
|
break;
|
|
case 0x20: /* ADD */
|
|
if (ENABLE_OVERFLOWS && r3000->RSVAL > ~r3000->RTVAL) generate_exception(r3000, EXCEPTION_OVERFLOW);
|
|
else r3000->RDVAL = r3000->RSVAL + r3000->RTVAL;
|
|
break;
|
|
case 0x21: /* ADDU */ if (RDREG) r3000->RDVAL = r3000->RSVAL + r3000->RTVAL; break;
|
|
case 0x22: /* SUB */
|
|
if (ENABLE_OVERFLOWS && r3000->RSVAL < r3000->RTVAL) generate_exception(r3000, EXCEPTION_OVERFLOW);
|
|
else r3000->RDVAL = r3000->RSVAL - r3000->RTVAL;
|
|
break;
|
|
case 0x23: /* SUBU */ if (RDREG) r3000->RDVAL = r3000->RSVAL - r3000->RTVAL; break;
|
|
case 0x24: /* AND */ if (RDREG) r3000->RDVAL = r3000->RSVAL & r3000->RTVAL; break;
|
|
case 0x25: /* OR */ if (RDREG) r3000->RDVAL = r3000->RSVAL | r3000->RTVAL; break;
|
|
case 0x26: /* XOR */ if (RDREG) r3000->RDVAL = r3000->RSVAL ^ r3000->RTVAL; break;
|
|
case 0x27: /* NOR */ if (RDREG) r3000->RDVAL = ~(r3000->RSVAL | r3000->RTVAL); break;
|
|
case 0x2a: /* SLT */ if (RDREG) r3000->RDVAL = (INT32)r3000->RSVAL < (INT32)r3000->RTVAL; break;
|
|
case 0x2b: /* SLTU */ if (RDREG) r3000->RDVAL = (UINT32)r3000->RSVAL < (UINT32)r3000->RTVAL; break;
|
|
case 0x30: /* TEQ */ invalid_instruction(r3000, op); break;
|
|
case 0x31: /* TGEU */ invalid_instruction(r3000, op); break;
|
|
case 0x32: /* TLT */ invalid_instruction(r3000, op); break;
|
|
case 0x33: /* TLTU */ invalid_instruction(r3000, op); break;
|
|
case 0x34: /* TGE */ invalid_instruction(r3000, op); break;
|
|
case 0x36: /* TNE */ invalid_instruction(r3000, op); break;
|
|
default: /* ??? */ invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
|
|
case 0x01: /* REGIMM */
|
|
switch (RTREG)
|
|
{
|
|
case 0x00: /* BLTZ */ if ((INT32)r3000->RSVAL < 0) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x01: /* BGEZ */ if ((INT32)r3000->RSVAL >= 0) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x02: /* BLTZL */ invalid_instruction(r3000, op); break;
|
|
case 0x03: /* BGEZL */ invalid_instruction(r3000, op); break;
|
|
case 0x08: /* TGEI */ invalid_instruction(r3000, op); break;
|
|
case 0x09: /* TGEIU */ invalid_instruction(r3000, op); break;
|
|
case 0x0a: /* TLTI */ invalid_instruction(r3000, op); break;
|
|
case 0x0b: /* TLTIU */ invalid_instruction(r3000, op); break;
|
|
case 0x0c: /* TEQI */ invalid_instruction(r3000, op); break;
|
|
case 0x0e: /* TNEI */ invalid_instruction(r3000, op); break;
|
|
case 0x10: /* BLTZAL */ if ((INT32)r3000->RSVAL < 0) ADDPCL(r3000,SIMMVAL,31); break;
|
|
case 0x11: /* BGEZAL */ if ((INT32)r3000->RSVAL >= 0) ADDPCL(r3000,SIMMVAL,31); break;
|
|
case 0x12: /* BLTZALL */ invalid_instruction(r3000, op); break;
|
|
case 0x13: /* BGEZALL */ invalid_instruction(r3000, op); break;
|
|
default: /* ??? */ invalid_instruction(r3000, op); break;
|
|
}
|
|
break;
|
|
|
|
case 0x02: /* J */ ABSPC(r3000, LIMMVAL); break;
|
|
case 0x03: /* JAL */ ABSPCL(r3000, LIMMVAL,31); break;
|
|
case 0x04: /* BEQ */ if (r3000->RSVAL == r3000->RTVAL) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x05: /* BNE */ if (r3000->RSVAL != r3000->RTVAL) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x06: /* BLEZ */ if ((INT32)r3000->RSVAL <= 0) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x07: /* BGTZ */ if ((INT32)r3000->RSVAL > 0) ADDPC(r3000, SIMMVAL); break;
|
|
case 0x08: /* ADDI */
|
|
if (ENABLE_OVERFLOWS && r3000->RSVAL > ~SIMMVAL) generate_exception(r3000, EXCEPTION_OVERFLOW);
|
|
else if (RTREG) r3000->RTVAL = r3000->RSVAL + SIMMVAL;
|
|
break;
|
|
case 0x09: /* ADDIU */ if (RTREG) r3000->RTVAL = r3000->RSVAL + SIMMVAL; break;
|
|
case 0x0a: /* SLTI */ if (RTREG) r3000->RTVAL = (INT32)r3000->RSVAL < (INT32)SIMMVAL; break;
|
|
case 0x0b: /* SLTIU */ if (RTREG) r3000->RTVAL = (UINT32)r3000->RSVAL < (UINT32)SIMMVAL; break;
|
|
case 0x0c: /* ANDI */ if (RTREG) r3000->RTVAL = r3000->RSVAL & UIMMVAL; break;
|
|
case 0x0d: /* ORI */ if (RTREG) r3000->RTVAL = r3000->RSVAL | UIMMVAL; break;
|
|
case 0x0e: /* XORI */ if (RTREG) r3000->RTVAL = r3000->RSVAL ^ UIMMVAL; break;
|
|
case 0x0f: /* LUI */ if (RTREG) r3000->RTVAL = UIMMVAL << 16; break;
|
|
case 0x10: /* COP0 */ handle_cop0(r3000, op); break;
|
|
case 0x11: /* COP1 */ handle_cop1(r3000, op); break;
|
|
case 0x12: /* COP2 */ handle_cop2(r3000, op); break;
|
|
case 0x13: /* COP3 */ handle_cop3(r3000, op); break;
|
|
case 0x14: /* BEQL */ invalid_instruction(r3000, op); break;
|
|
case 0x15: /* BNEL */ invalid_instruction(r3000, op); break;
|
|
case 0x16: /* BLEZL */ invalid_instruction(r3000, op); break;
|
|
case 0x17: /* BGTZL */ invalid_instruction(r3000, op); break;
|
|
case 0x20: /* LB */ temp = RBYTE(r3000, SIMMVAL+r3000->RSVAL); if (RTREG) r3000->RTVAL = (INT8)temp; break;
|
|
case 0x21: /* LH */ temp = RWORD(r3000, SIMMVAL+r3000->RSVAL); if (RTREG) r3000->RTVAL = (INT16)temp; break;
|
|
case 0x22: /* LWL */ (*r3000->lwl)(r3000, op); break;
|
|
case 0x23: /* LW */ temp = RLONG(r3000, SIMMVAL+r3000->RSVAL); if (RTREG) r3000->RTVAL = temp; break;
|
|
case 0x24: /* LBU */ temp = RBYTE(r3000, SIMMVAL+r3000->RSVAL); if (RTREG) r3000->RTVAL = (UINT8)temp; break;
|
|
case 0x25: /* LHU */ temp = RWORD(r3000, SIMMVAL+r3000->RSVAL); if (RTREG) r3000->RTVAL = (UINT16)temp; break;
|
|
case 0x26: /* LWR */ (*r3000->lwr)(r3000, op); break;
|
|
case 0x28: /* SB */ WBYTE(r3000, SIMMVAL+r3000->RSVAL, r3000->RTVAL); break;
|
|
case 0x29: /* SH */ WWORD(r3000, SIMMVAL+r3000->RSVAL, r3000->RTVAL); break;
|
|
case 0x2a: /* SWL */ (*r3000->swl)(r3000, op); break;
|
|
case 0x2b: /* SW */ WLONG(r3000, SIMMVAL+r3000->RSVAL, r3000->RTVAL); break;
|
|
case 0x2e: /* SWR */ (*r3000->swr)(r3000, op); break;
|
|
case 0x2f: /* CACHE */ invalid_instruction(r3000, op); break;
|
|
case 0x30: /* LL */ invalid_instruction(r3000, op); break;
|
|
case 0x31: /* LWC1 */ set_cop1_reg(r3000, RTREG, RLONG(r3000, SIMMVAL+r3000->RSVAL)); break;
|
|
case 0x32: /* LWC2 */ set_cop2_reg(r3000, RTREG, RLONG(r3000, SIMMVAL+r3000->RSVAL)); break;
|
|
case 0x33: /* LWC3 */ set_cop3_reg(r3000, RTREG, RLONG(r3000, SIMMVAL+r3000->RSVAL)); break;
|
|
case 0x34: /* LDC0 */ invalid_instruction(r3000, op); break;
|
|
case 0x35: /* LDC1 */ invalid_instruction(r3000, op); break;
|
|
case 0x36: /* LDC2 */ invalid_instruction(r3000, op); break;
|
|
case 0x37: /* LDC3 */ invalid_instruction(r3000, op); break;
|
|
case 0x38: /* SC */ invalid_instruction(r3000, op); break;
|
|
case 0x39: /* LWC1 */ WLONG(r3000, SIMMVAL+r3000->RSVAL, get_cop1_reg(r3000, RTREG)); break;
|
|
case 0x3a: /* LWC2 */ WLONG(r3000, SIMMVAL+r3000->RSVAL, get_cop2_reg(r3000, RTREG)); break;
|
|
case 0x3b: /* LWC3 */ WLONG(r3000, SIMMVAL+r3000->RSVAL, get_cop3_reg(r3000, RTREG)); break;
|
|
case 0x3c: /* SDC0 */ invalid_instruction(r3000, op); break;
|
|
case 0x3d: /* SDC1 */ invalid_instruction(r3000, op); break;
|
|
case 0x3e: /* SDC2 */ invalid_instruction(r3000, op); break;
|
|
case 0x3f: /* SDC3 */ invalid_instruction(r3000, op); break;
|
|
default: /* ??? */ invalid_instruction(r3000, op); break;
|
|
}
|
|
r3000->icount--;
|
|
|
|
} while (r3000->icount > 0 || r3000->nextpc != ~0);
|
|
|
|
r3000->icount -= r3000->interrupt_cycles;
|
|
r3000->interrupt_cycles = 0;
|
|
return cycles - r3000->icount;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
DISASSEMBLY HOOK
|
|
***************************************************************************/
|
|
|
|
static CPU_DISASSEMBLE( r3000be )
|
|
{
|
|
extern unsigned dasmr3k(char *, unsigned, UINT32);
|
|
UINT32 op = *(UINT32 *)oprom;
|
|
op = BIG_ENDIANIZE_INT32(op);
|
|
return dasmr3k(buffer, pc, op);
|
|
}
|
|
|
|
|
|
static CPU_DISASSEMBLE( r3000le )
|
|
{
|
|
extern unsigned dasmr3k(char *, unsigned, UINT32);
|
|
UINT32 op = *(UINT32 *)oprom;
|
|
op = LITTLE_ENDIANIZE_INT32(op);
|
|
return dasmr3k(buffer, pc, op);
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
CACHE I/O
|
|
***************************************************************************/
|
|
|
|
static UINT8 readcache_be(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? r3000->cache[BYTE4_XOR_BE(offset)] : 0xff;
|
|
}
|
|
|
|
static UINT16 readcache_be_word(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? *(UINT16 *)&r3000->cache[WORD_XOR_BE(offset)] : 0xffff;
|
|
}
|
|
|
|
static UINT32 readcache_be_dword(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? *(UINT32 *)&r3000->cache[offset] : 0xffffffff;
|
|
}
|
|
|
|
static void writecache_be(const address_space *space, offs_t offset, UINT8 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) r3000->cache[BYTE4_XOR_BE(offset)] = data;
|
|
}
|
|
|
|
static void writecache_be_word(const address_space *space, offs_t offset, UINT16 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) *(UINT16 *)&r3000->cache[WORD_XOR_BE(offset)] = data;
|
|
}
|
|
|
|
static void writecache_be_dword(const address_space *space, offs_t offset, UINT32 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) *(UINT32 *)&r3000->cache[offset] = data;
|
|
}
|
|
|
|
static UINT8 readcache_le(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? r3000->cache[BYTE4_XOR_LE(offset)] : 0xff;
|
|
}
|
|
|
|
static UINT16 readcache_le_word(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? *(UINT16 *)&r3000->cache[WORD_XOR_LE(offset)] : 0xffff;
|
|
}
|
|
|
|
static UINT32 readcache_le_dword(const address_space *space, offs_t offset)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
return (offset * 4 < r3000->cache_size) ? *(UINT32 *)&r3000->cache[offset] : 0xffffffff;
|
|
}
|
|
|
|
static void writecache_le(const address_space *space, offs_t offset, UINT8 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) r3000->cache[BYTE4_XOR_LE(offset)] = data;
|
|
}
|
|
|
|
static void writecache_le_word(const address_space *space, offs_t offset, UINT16 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) *(UINT16 *)&r3000->cache[WORD_XOR_LE(offset)] = data;
|
|
}
|
|
|
|
static void writecache_le_dword(const address_space *space, offs_t offset, UINT32 data)
|
|
{
|
|
r3000_state *r3000 = space->cpu->token;
|
|
offset &= 0x1fffffff;
|
|
if (offset * 4 < r3000->cache_size) *(UINT32 *)&r3000->cache[offset] = data;
|
|
}
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
COMPLEX OPCODE IMPLEMENTATIONS
|
|
***************************************************************************/
|
|
|
|
static void lwl_be(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
if (RTREG)
|
|
{
|
|
if (!(offs & 3)) r3000->RTVAL = temp;
|
|
else
|
|
{
|
|
int shift = 8 * (offs & 3);
|
|
r3000->RTVAL = (r3000->RTVAL & (0x00ffffff >> (24 - shift))) | (temp << shift);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lwr_be(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
if (RTREG)
|
|
{
|
|
if ((offs & 3) == 3) r3000->RTVAL = temp;
|
|
else
|
|
{
|
|
int shift = 8 * (offs & 3);
|
|
r3000->RTVAL = (r3000->RTVAL & (0xffffff00 << shift)) | (temp >> (24 - shift));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swl_be(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
if (!(offs & 3)) WLONG(r3000, offs, r3000->RTVAL);
|
|
else
|
|
{
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
int shift = 8 * (offs & 3);
|
|
WLONG(r3000, offs & ~3, (temp & (0xffffff00 << (24 - shift))) | (r3000->RTVAL >> shift));
|
|
}
|
|
}
|
|
|
|
|
|
static void swr_be(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
if ((offs & 3) == 3) WLONG(r3000, offs & ~3, r3000->RTVAL);
|
|
else
|
|
{
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
int shift = 8 * (offs & 3);
|
|
WLONG(r3000, offs & ~3, (temp & (0x00ffffff >> shift)) | (r3000->RTVAL << (24 - shift)));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void lwl_le(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
if (RTREG)
|
|
{
|
|
if (!(offs & 3)) r3000->RTVAL = temp;
|
|
else
|
|
{
|
|
int shift = 8 * (offs & 3);
|
|
r3000->RTVAL = (r3000->RTVAL & (0xffffff00 << (24 - shift))) | (temp >> shift);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void lwr_le(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
if (RTREG)
|
|
{
|
|
if ((offs & 3) == 3) r3000->RTVAL = temp;
|
|
else
|
|
{
|
|
int shift = 8 * (offs & 3);
|
|
r3000->RTVAL = (r3000->RTVAL & (0x00ffffff >> shift)) | (temp << (24 - shift));
|
|
}
|
|
}
|
|
}
|
|
|
|
static void swl_le(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
if (!(offs & 3)) WLONG(r3000, offs, r3000->RTVAL);
|
|
else
|
|
{
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
int shift = 8 * (offs & 3);
|
|
WLONG(r3000, offs & ~3, (temp & (0x00ffffff >> (24 - shift))) | (r3000->RTVAL << shift));
|
|
}
|
|
}
|
|
|
|
static void swr_le(r3000_state *r3000, UINT32 op)
|
|
{
|
|
offs_t offs = SIMMVAL + r3000->RSVAL;
|
|
if ((offs & 3) == 3) WLONG(r3000, offs & ~3, r3000->RTVAL);
|
|
else
|
|
{
|
|
UINT32 temp = RLONG(r3000, offs & ~3);
|
|
int shift = 8 * (offs & 3);
|
|
WLONG(r3000, offs & ~3, (temp & (0xffffff00 << shift)) | (r3000->RTVAL >> (24 - shift)));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic set_info
|
|
**************************************************************************/
|
|
|
|
static CPU_SET_INFO( r3000 )
|
|
{
|
|
r3000_state *r3000 = device->token;
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are set as 64-bit signed integers --- */
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ0: set_irq_line(r3000, R3000_IRQ0, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ1: set_irq_line(r3000, R3000_IRQ1, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ2: set_irq_line(r3000, R3000_IRQ2, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ3: set_irq_line(r3000, R3000_IRQ3, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ4: set_irq_line(r3000, R3000_IRQ4, info->i); break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ5: set_irq_line(r3000, R3000_IRQ5, info->i); break;
|
|
|
|
case CPUINFO_INT_PC:
|
|
case CPUINFO_INT_REGISTER + R3000_PC: r3000->pc = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_SR: r3000->SR = info->i; break;
|
|
|
|
case CPUINFO_INT_REGISTER + R3000_R0: r3000->r[0] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R1: r3000->r[1] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R2: r3000->r[2] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R3: r3000->r[3] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R4: r3000->r[4] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R5: r3000->r[5] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R6: r3000->r[6] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R7: r3000->r[7] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R8: r3000->r[8] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R9: r3000->r[9] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R10: r3000->r[10] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R11: r3000->r[11] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R12: r3000->r[12] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R13: r3000->r[13] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R14: r3000->r[14] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R15: r3000->r[15] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R16: r3000->r[16] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R17: r3000->r[17] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R18: r3000->r[18] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R19: r3000->r[19] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R20: r3000->r[20] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R21: r3000->r[21] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R22: r3000->r[22] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R23: r3000->r[23] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R24: r3000->r[24] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R25: r3000->r[25] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R26: r3000->r[26] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R27: r3000->r[27] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R28: r3000->r[28] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R29: r3000->r[29] = info->i; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R30: r3000->r[30] = info->i; break;
|
|
case CPUINFO_INT_SP:
|
|
case CPUINFO_INT_REGISTER + R3000_R31: r3000->r[31] = info->i; break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************
|
|
* Generic get_info
|
|
**************************************************************************/
|
|
|
|
static CPU_GET_INFO( r3000 )
|
|
{
|
|
r3000_state *r3000 = (device != NULL) ? device->token : NULL;
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_CONTEXT_SIZE: info->i = sizeof(r3000_state); break;
|
|
case CPUINFO_INT_INPUT_LINES: info->i = 6; break;
|
|
case CPUINFO_INT_DEFAULT_IRQ_VECTOR: info->i = 0; break;
|
|
case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
|
|
case CPUINFO_INT_CLOCK_MULTIPLIER: info->i = 1; break;
|
|
case CPUINFO_INT_CLOCK_DIVIDER: info->i = 1; break;
|
|
case CPUINFO_INT_MIN_INSTRUCTION_BYTES: info->i = 4; break;
|
|
case CPUINFO_INT_MAX_INSTRUCTION_BYTES: info->i = 4; break;
|
|
case CPUINFO_INT_MIN_CYCLES: info->i = 1; break;
|
|
case CPUINFO_INT_MAX_CYCLES: info->i = 40; break;
|
|
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 29; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_DATA: info->i = 0; break;
|
|
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
case CPUINFO_INT_ADDRBUS_SHIFT + ADDRESS_SPACE_IO: info->i = 0; break;
|
|
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ0: info->i = (r3000->cpr[0][COP0_Cause] & 0x400) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ1: info->i = (r3000->cpr[0][COP0_Cause] & 0x800) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ2: info->i = (r3000->cpr[0][COP0_Cause] & 0x1000) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ3: info->i = (r3000->cpr[0][COP0_Cause] & 0x2000) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ4: info->i = (r3000->cpr[0][COP0_Cause] & 0x4000) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
case CPUINFO_INT_INPUT_STATE + R3000_IRQ5: info->i = (r3000->cpr[0][COP0_Cause] & 0x8000) ? ASSERT_LINE : CLEAR_LINE; break;
|
|
|
|
case CPUINFO_INT_PREVIOUSPC: info->i = r3000->ppc; break;
|
|
|
|
case CPUINFO_INT_PC: info->i = r3000->pc & 0x1fffffff; break;
|
|
case CPUINFO_INT_REGISTER + R3000_PC: info->i = r3000->pc; break;
|
|
case CPUINFO_INT_REGISTER + R3000_SR: info->i = r3000->SR; break;
|
|
|
|
case CPUINFO_INT_REGISTER + R3000_R0: info->i = r3000->r[0]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R1: info->i = r3000->r[1]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R2: info->i = r3000->r[2]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R3: info->i = r3000->r[3]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R4: info->i = r3000->r[4]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R5: info->i = r3000->r[5]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R6: info->i = r3000->r[6]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R7: info->i = r3000->r[7]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R8: info->i = r3000->r[8]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R9: info->i = r3000->r[9]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R10: info->i = r3000->r[10]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R11: info->i = r3000->r[11]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R12: info->i = r3000->r[12]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R13: info->i = r3000->r[13]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R14: info->i = r3000->r[14]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R15: info->i = r3000->r[15]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R16: info->i = r3000->r[16]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R17: info->i = r3000->r[17]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R18: info->i = r3000->r[18]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R19: info->i = r3000->r[19]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R20: info->i = r3000->r[20]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R21: info->i = r3000->r[21]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R22: info->i = r3000->r[22]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R23: info->i = r3000->r[23]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R24: info->i = r3000->r[24]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R25: info->i = r3000->r[25]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R26: info->i = r3000->r[26]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R27: info->i = r3000->r[27]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R28: info->i = r3000->r[28]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R29: info->i = r3000->r[29]; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R30: info->i = r3000->r[30]; break;
|
|
case CPUINFO_INT_SP: info->i = r3000->r[31] & 0x1fffffff; break;
|
|
case CPUINFO_INT_REGISTER + R3000_R31: info->i = r3000->r[31]; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_SET_INFO: info->setinfo = CPU_SET_INFO_NAME(r3000); break;
|
|
case CPUINFO_PTR_INIT: info->init = CPU_INIT_NAME(r3000); break;
|
|
case CPUINFO_PTR_RESET: /* provided per-CPU */ break;
|
|
case CPUINFO_PTR_EXIT: info->exit = CPU_EXIT_NAME(r3000); break;
|
|
case CPUINFO_PTR_EXECUTE: info->execute = CPU_EXECUTE_NAME(r3000); break;
|
|
case CPUINFO_PTR_BURN: info->burn = NULL; break;
|
|
case CPUINFO_PTR_DISASSEMBLE: /* provided per-CPU */ break;
|
|
case CPUINFO_PTR_INSTRUCTION_COUNTER: info->icount = &r3000->icount; break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "R3000"); break;
|
|
case CPUINFO_STR_CORE_FAMILY: strcpy(info->s, "MIPS II"); break;
|
|
case CPUINFO_STR_CORE_VERSION: strcpy(info->s, "1.0"); break;
|
|
case CPUINFO_STR_CORE_FILE: strcpy(info->s, __FILE__); break;
|
|
case CPUINFO_STR_CORE_CREDITS: strcpy(info->s, "Copyright Aaron Giles"); break;
|
|
|
|
case CPUINFO_STR_FLAGS: strcpy(info->s, " "); break;
|
|
|
|
case CPUINFO_STR_REGISTER + R3000_PC: sprintf(info->s, "PC: %08X", r3000->pc); break;
|
|
case CPUINFO_STR_REGISTER + R3000_SR: sprintf(info->s, "SR: %08X", r3000->SR); break;
|
|
|
|
case CPUINFO_STR_REGISTER + R3000_R0: sprintf(info->s, "R0: %08X", r3000->r[0]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R1: sprintf(info->s, "R1: %08X", r3000->r[1]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R2: sprintf(info->s, "R2: %08X", r3000->r[2]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R3: sprintf(info->s, "R3: %08X", r3000->r[3]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R4: sprintf(info->s, "R4: %08X", r3000->r[4]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R5: sprintf(info->s, "R5: %08X", r3000->r[5]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R6: sprintf(info->s, "R6: %08X", r3000->r[6]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R7: sprintf(info->s, "R7: %08X", r3000->r[7]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R8: sprintf(info->s, "R8: %08X", r3000->r[8]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R9: sprintf(info->s, "R9: %08X", r3000->r[9]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R10: sprintf(info->s, "R10:%08X", r3000->r[10]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R11: sprintf(info->s, "R11:%08X", r3000->r[11]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R12: sprintf(info->s, "R12:%08X", r3000->r[12]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R13: sprintf(info->s, "R13:%08X", r3000->r[13]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R14: sprintf(info->s, "R14:%08X", r3000->r[14]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R15: sprintf(info->s, "R15:%08X", r3000->r[15]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R16: sprintf(info->s, "R16:%08X", r3000->r[16]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R17: sprintf(info->s, "R17:%08X", r3000->r[17]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R18: sprintf(info->s, "R18:%08X", r3000->r[18]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R19: sprintf(info->s, "R19:%08X", r3000->r[19]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R20: sprintf(info->s, "R20:%08X", r3000->r[20]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R21: sprintf(info->s, "R21:%08X", r3000->r[21]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R22: sprintf(info->s, "R22:%08X", r3000->r[22]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R23: sprintf(info->s, "R23:%08X", r3000->r[23]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R24: sprintf(info->s, "R24:%08X", r3000->r[24]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R25: sprintf(info->s, "R25:%08X", r3000->r[25]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R26: sprintf(info->s, "R26:%08X", r3000->r[26]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R27: sprintf(info->s, "R27:%08X", r3000->r[27]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R28: sprintf(info->s, "R28:%08X", r3000->r[28]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R29: sprintf(info->s, "R29:%08X", r3000->r[29]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R30: sprintf(info->s, "R30:%08X", r3000->r[30]); break;
|
|
case CPUINFO_STR_REGISTER + R3000_R31: sprintf(info->s, "R31:%08X", r3000->r[31]); break;
|
|
}
|
|
}
|
|
|
|
|
|
/**************************************************************************
|
|
* CPU-specific set_info
|
|
**************************************************************************/
|
|
|
|
CPU_GET_INFO( r3000be )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(r3000be); break;
|
|
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(r3000be); break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "R3000 (big)"); break;
|
|
|
|
default: CPU_GET_INFO_CALL(r3000); break;
|
|
}
|
|
}
|
|
|
|
|
|
CPU_GET_INFO( r3000le )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(r3000le); break;
|
|
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(r3000le); break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "R3000 (little)"); break;
|
|
|
|
default: CPU_GET_INFO_CALL(r3000); break;
|
|
}
|
|
}
|
|
|
|
|
|
CPU_GET_INFO( r3041be )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_BIG; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(r3000be); break;
|
|
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(r3000be); break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "R3041 (big)"); break;
|
|
|
|
default: CPU_GET_INFO_CALL(r3000); break;
|
|
}
|
|
}
|
|
|
|
|
|
CPU_GET_INFO( r3041le )
|
|
{
|
|
switch (state)
|
|
{
|
|
/* --- the following bits of info are returned as 64-bit signed integers --- */
|
|
case CPUINFO_INT_ENDIANNESS: info->i = ENDIANNESS_LITTLE; break;
|
|
|
|
/* --- the following bits of info are returned as pointers to data or functions --- */
|
|
case CPUINFO_PTR_RESET: info->reset = CPU_RESET_NAME(r3000le); break;
|
|
case CPUINFO_PTR_DISASSEMBLE: info->disassemble = CPU_DISASSEMBLE_NAME(r3000le); break;
|
|
|
|
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
|
case CPUINFO_STR_NAME: strcpy(info->s, "R3041 (little)"); break;
|
|
|
|
default: CPU_GET_INFO_CALL(r3000); break;
|
|
}
|
|
}
|