cpu/mips: Fixed memory access handling in the IDT MIPS R4650 core. (#11065) [Ryan Holtz]

Correctly support the R4650's lack of TLB.
This commit is contained in:
MooglyGuy 2023-04-02 18:19:29 +02:00 committed by GitHub
parent 8aabc8f527
commit fe00ebe1cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 369 additions and 74 deletions

View File

@ -243,7 +243,7 @@ void mips3_device::generate_exception(int exception, int backup)
if (exception != 0)
{
fprintf(stderr, "Exception: PC=%08X, PPC=%08X\n", m_core->pc, m_ppc);
fprintf(stderr, "Exception type %d: PC=%08X, PPC=%08X\n", exception, m_core->pc, m_ppc);
machine().debug_break();
}
*/
@ -1159,6 +1159,12 @@ bool mips3_device::memory_translate(int spacenum, int intention, offs_t &address
return true;
}
bool r4650_device::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
{
target_space = &space(spacenum);
return true;
}
std::unique_ptr<util::disasm_interface> mips3_device::create_disassembler()
{
return std::make_unique<mips3_disassembler>();
@ -1517,6 +1523,178 @@ inline void mips3_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t
}
}
inline bool r4650_device::RBYTE(offs_t address, uint32_t *result)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_byte)(*m_program, address);
return true;
}
if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_byte)(*m_program, address + m_core->cpr[0][COP0_R4650_DBase]);
return true;
}
inline bool r4650_device::RHALF(offs_t address, uint32_t *result)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_word)(*m_program, address);
return true;
}
if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_word)(*m_program, address + m_core->cpr[0][COP0_R4650_DBase]);
return true;
}
inline bool r4650_device::RWORD(offs_t address, uint32_t *result, bool insn)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_dword)(*m_program, address);
return true;
}
static const uint32_t BASE_INDICES[2] = { COP0_R4650_DBase, COP0_R4650_IBase };
static const uint32_t BOUND_INDICES[2] = { COP0_R4650_DBound, COP0_R4650_IBound };
const uint32_t base = m_core->cpr[0][BASE_INDICES[insn]];
const uint32_t bound = m_core->cpr[0][BOUND_INDICES[insn]];
if ((address & 0xfffff000) > bound)
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_dword)(*m_program, address + base);
return true;
}
inline bool r4650_device::RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_dword_masked)(*m_program, address, mem_mask);
return true;
}
if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_dword_masked)(*m_program, address + m_core->cpr[0][COP0_R4650_DBase], mem_mask);
return true;
}
inline bool r4650_device::RDOUBLE(offs_t address, uint64_t *result)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_qword)(*m_program, address);
return true;
}
if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_qword)(*m_program, address + m_core->cpr[0][COP0_R4650_DBase]);
return true;
}
inline bool r4650_device::RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
{
*result = (*m_memory.read_qword_masked)(*m_program, address, mem_mask);
return true;
}
if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
{
generate_tlb_exception(EXCEPTION_ADDRLOAD, address);
*result = 0;
return false;
}
*result = (*m_memory.read_qword_masked)(*m_program, address + m_core->cpr[0][COP0_R4650_DBase], mem_mask);
return true;
}
inline void r4650_device::WBYTE(offs_t address, uint8_t data)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_byte)(*m_program, address, data);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_byte)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data);
}
inline void r4650_device::WHALF(offs_t address, uint16_t data)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_word)(*m_program, address, data);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_word)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data);
}
inline void r4650_device::WWORD(offs_t address, uint32_t data)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_dword)(*m_program, address, data);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_dword)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data);
}
inline void r4650_device::WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_dword_masked)(*m_program, address, data, mem_mask);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_dword_masked)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data, mem_mask);
}
inline void r4650_device::WDOUBLE(offs_t address, uint64_t data)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_qword)(*m_program, address, data);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_qword)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data);
}
inline void r4650_device::WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask)
{
if ((SR & SR_KSU_USER) == SR_KSU_KERNEL)
(*m_memory.write_qword_masked)(*m_program, address, data, mem_mask);
else if ((address & 0xfffff000) > m_core->cpr[0][COP0_R4650_DBound])
generate_tlb_exception(EXCEPTION_ADDRSTORE, address);
else
(*m_memory.write_qword_masked)(*m_program, address + m_core->cpr[0][COP0_R4650_DBound], data, mem_mask);
}
inline void r5900le_device::WBYTE(offs_t address, uint8_t data)
{
if (address >= 0x70000000 && address < 0x70004000) (*m_memory.write_byte)(*m_program, address, data);
@ -1713,6 +1891,22 @@ uint64_t mips3_device::get_cop0_reg(int idx)
return m_core->cpr[0][idx];
}
void r4650_device::set_cop0_reg(int idx, uint64_t val)
{
switch (idx)
{
case COP0_R4650_IBase:
case COP0_R4650_IBound:
case COP0_R4650_DBase:
case COP0_R4650_DBound:
m_core->cpr[0][idx] = val;
break;
default:
mips3_device::set_cop0_reg(idx, val);
break;
}
}
void mips3_device::set_cop0_reg(int idx, uint64_t val)
{
switch (idx)

View File

@ -352,6 +352,8 @@ protected:
virtual void WDOUBLE(offs_t address, uint64_t data);
virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask);
virtual void set_cop0_reg(int idx, uint64_t val);
struct internal_mips3_state {
/* core registers */
uint32_t pc;
@ -519,6 +521,12 @@ protected:
void generate_exception(int exception, int backup);
void generate_tlb_exception(int exception, offs_t address);
void static_generate_memory_mode_checks(drcuml_block &block, uml::code_handle &exception_addrerr, int &label, int mode);
void static_generate_fastram_accessor(drcuml_block &block, int &label, int size, bool iswrite, bool ismasked);
void static_generate_memory_rw(drcuml_block &block, int size, bool iswrite, bool ismasked);
virtual void static_generate_memory_accessor(int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr);
virtual void check_irqs();
virtual void handle_mult(uint32_t op);
virtual void handle_multu(uint32_t op);
@ -539,7 +547,6 @@ private:
void tlb_write_common(int tlbindex);
uint64_t get_cop0_reg(int idx);
void set_cop0_reg(int idx, uint64_t val);
uint64_t get_cop0_creg(int idx);
void set_cop0_creg(int idx, uint64_t val);
void handle_cop0(uint32_t op);
@ -620,7 +627,6 @@ private:
void static_generate_out_of_cycles();
void static_generate_tlb_mismatch();
void static_generate_exception(uint8_t exception, int recover, const char *name);
void static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr);
void generate_update_mode(drcuml_block &block);
void generate_update_cycles(drcuml_block &block, compiler_state &compiler, uml::parameter param, bool allow_exception);
@ -745,20 +751,49 @@ public:
}
};
class r4650be_device : public mips3_device {
class r4650_device : public mips3_device {
public:
// construction/destruction
r4650_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, endianness_t endianness)
: mips3_device(mconfig, type, tag, owner, clock, MIPS3_TYPE_R4650, endianness, 32) // Should be 64 bits
{
}
protected:
virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
virtual void static_generate_memory_accessor(int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr) override;
virtual bool RBYTE(offs_t address, uint32_t *result) override;
virtual bool RHALF(offs_t address, uint32_t *result) override;
virtual bool RWORD(offs_t address, uint32_t *result, bool insn = false) override;
virtual bool RWORD_MASKED(offs_t address, uint32_t *result, uint32_t mem_mask) override;
virtual bool RDOUBLE(offs_t address, uint64_t *result) override;
virtual bool RDOUBLE_MASKED(offs_t address, uint64_t *result, uint64_t mem_mask) override;
virtual void WBYTE(offs_t address, uint8_t data) override;
virtual void WHALF(offs_t address, uint16_t data) override;
virtual void WWORD(offs_t address, uint32_t data) override;
virtual void WWORD_MASKED(offs_t address, uint32_t data, uint32_t mem_mask) override;
virtual void WDOUBLE(offs_t address, uint64_t data) override;
virtual void WDOUBLE_MASKED(offs_t address, uint64_t data, uint64_t mem_mask) override;
virtual void set_cop0_reg(int idx, uint64_t val) override;
};
class r4650be_device : public r4650_device {
public:
// construction/destruction
r4650be_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mips3_device(mconfig, R4650BE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_BIG, 32) // Should be 64 bits
: r4650_device(mconfig, R4650BE, tag, owner, clock, ENDIANNESS_BIG)
{
}
};
class r4650le_device : public mips3_device {
class r4650le_device : public r4650_device {
public:
// construction/destruction
r4650le_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: mips3_device(mconfig, R4650LE, tag, owner, clock, MIPS3_TYPE_R4650, ENDIANNESS_LITTLE, 32) // Should be 64 bits
: r4650_device(mconfig, R4650LE, tag, owner, clock, ENDIANNESS_LITTLE)
{
}
};

View File

@ -107,6 +107,10 @@
#define COP0_TagLo 28
#define COP0_TagHi 29
#define COP0_ErrorPC 30
#define COP0_R4650_IBase 0
#define COP0_R4650_IBound 1
#define COP0_R4650_DBase 2
#define COP0_R4650_DBound 3
/* Status register bits */
#define SR_IE 0x00000001

View File

@ -828,120 +828,106 @@ void mips3_device::static_generate_exception(uint8_t exception, int recover, con
/*------------------------------------------------------------------
static_generate_memory_accessor
static_generate_memory_mode_checks
------------------------------------------------------------------*/
void mips3_device::static_generate_memory_accessor(int mode, int size, int iswrite, int ismasked, const char *name, uml::code_handle *&handleptr)
void mips3_device::static_generate_memory_mode_checks(drcuml_block &block, uml::code_handle &exception_addrerr, int &label, int mode)
{
/* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
/* on exit, read result is in I0 */
/* routine trashes I0-I3 */
uml::code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
uml::code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL];
uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
int tlbmiss = 0;
int label = 1;
int ramnum;
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(1024));
/* add a global entry for this */
alloc_handle(*m_drcuml, handleptr, name);
UML_HANDLE(block, *handleptr); // handle handleptr
/* user mode? generate address exception if top bit is set */
if (mode == MODE_USER)
{
UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
UML_EXHc(block, COND_NZ, exception_addrerr, I0); // exh addrerr,i0,nz
UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
UML_EXHc(block, COND_NZ, exception_addrerr, I0); // exh addrerr,i0,nz
}
/* supervisor mode? generate address exception if not in user space or in $C0000000-DFFFFFFF */
if (mode == MODE_SUPER)
{
int addrok;
UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
UML_TEST(block, I0, 0x80000000); // test i0,0x80000000
UML_JMPc(block, COND_Z, addrok = label++); // jz addrok
UML_SHR(block, I3, I0, 29); // shr i3,i0,29
UML_CMP(block, I3, 6); // cmp i3,6
UML_SHR(block, I3, I0, 29); // shr i3,i0,29
UML_CMP(block, I3, 6); // cmp i3,6
UML_EXHc(block, COND_NE, exception_addrerr, I0); // exh addrerr,i0,ne
UML_LABEL(block, addrok); // addrok:
UML_LABEL(block, addrok); // addrok:
}
}
/* general case: assume paging and perform a translation */
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb_table],i3,dword
UML_TEST(block, I3, iswrite ? WRITE_ALLOWED : READ_ALLOWED);// test i3,iswrite ? WRITE_ALLOWED : READ_ALLOWED
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
/*------------------------------------------------------------------
static_generate_fastram_accessor
------------------------------------------------------------------*/
void mips3_device::static_generate_fastram_accessor(drcuml_block &block, int &label, int size, bool iswrite, bool ismasked)
{
if ((machine().debug_flags & DEBUG_FLAG_ENABLED) == 0)
for (ramnum = 0; ramnum < m_fastram_select; ramnum++)
{
for (int ramnum = 0; ramnum < m_fastram_select; ramnum++)
{
if (!(iswrite && m_fastram[ramnum].readonly))
{
void *fastbase = (uint8_t *)m_fastram[ramnum].base - m_fastram[ramnum].start;
uint32_t skip = label++;
if (m_fastram[ramnum].end != 0xffffffff)
{
UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end
UML_JMPc(block, COND_A, skip); // ja skip
UML_CMP(block, I0, m_fastram[ramnum].end); // cmp i0,end
UML_JMPc(block, COND_A, skip); // ja skip
}
if (m_fastram[ramnum].start != 0x00000000)
{
UML_CMP(block, I0, m_fastram[ramnum].start);// cmp i0,fastram_start
UML_JMPc(block, COND_B, skip); // jb skip
UML_CMP(block, I0, m_fastram[ramnum].start); // cmp i0,fastram_start
UML_JMPc(block, COND_B, skip); // jb skip
}
if (!iswrite)
{
if (size == 1)
{
UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
// xor i0,i0,bytexor
UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte
// xor i0,i0,bytexor
UML_LOAD(block, I0, fastbase, I0, SIZE_BYTE, SCALE_x1); // load i0,fastbase,i0,byte
}
else if (size == 2)
{
UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
// xor i0,i0,wordxor
UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1
// xor i0,i0,wordxor
UML_LOAD(block, I0, fastbase, I0, SIZE_WORD, SCALE_x1); // load i0,fastbase,i0,word_x1
}
else if (size == 4)
{
UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1
UML_LOAD(block, I0, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i0,fastbase,i0,dword_x1
}
else if (size == 8)
{
UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword_x1
UML_DLOAD(block, I0, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i0,fastbase,i0,qword_x1
UML_DROR(block, I0, I0, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
// dror i0,i0,32*bytexor
// dror i0,i0,32*bytexor
}
UML_RET(block); // ret
UML_RET(block); // ret
}
else
{
if (size == 1)
{
UML_XOR(block, I0, I0, m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0));
// xor i0,i0,bytexor
UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1);// store fastbase,i0,i1,byte
// xor i0,i0,bytexor
UML_STORE(block, fastbase, I0, I1, SIZE_BYTE, SCALE_x1); // store fastbase,i0,i1,byte
}
else if (size == 2)
{
UML_XOR(block, I0, I0, m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0));
// xor i0,i0,wordxor
UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1);// store fastbase,i0,i1,word_x1
// xor i0,i0,wordxor
UML_STORE(block, fastbase, I0, I1, SIZE_WORD, SCALE_x1); // store fastbase,i0,i1,word_x1
}
else if (size == 4)
{
if (ismasked)
{
UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1
UML_ROLINS(block, I3, I1, 0, I2); // rolins i3,i1,0,i2
UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i3,dword_x1
UML_LOAD(block, I3, fastbase, I0, SIZE_DWORD, SCALE_x1); // load i3,fastbase,i0,dword_x1
UML_ROLINS(block, I3, I1, 0, I2); // rolins i3,i1,0,i2
UML_STORE(block, fastbase, I0, I3, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i3,dword_x1
}
else
UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1
UML_STORE(block, fastbase, I0, I1, SIZE_DWORD, SCALE_x1); // store fastbase,i0,i1,dword_x1
}
else if (size == 8)
{
@ -951,8 +937,8 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
{
UML_DROR(block, I2, I2, 32 * (m_bigendian ? BYTE_XOR_BE(0) : BYTE_XOR_LE(0)));
// dror i2,i2,32*bytexor
UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1
UML_DROLINS(block, I3, I1, 0, I2); // drolins i3,i1,0,i2
UML_DLOAD(block, I3, fastbase, I0, SIZE_QWORD, SCALE_x1); // dload i3,fastbase,i0,qword_x1
UML_DROLINS(block, I3, I1, 0, I2); // drolins i3,i1,0,i2
UML_DSTORE(block, fastbase, I0, I3, SIZE_QWORD, SCALE_x1); // dstore fastbase,i0,i3,qword_x1
}
else
@ -961,9 +947,19 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
UML_RET(block); // ret
}
UML_LABEL(block, skip); // skip:
UML_LABEL(block, skip); // skip:
}
}
}
}
/*------------------------------------------------------------------
static_generate_memory_rw
------------------------------------------------------------------*/
void mips3_device::static_generate_memory_rw(drcuml_block &block, int size, bool iswrite, bool ismasked)
{
switch (size)
{
case 1:
@ -984,9 +980,9 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
if (iswrite)
{
if (!ismasked)
UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword
UML_WRITE(block, I0, I1, SIZE_DWORD, SPACE_PROGRAM); // write i0,i1,program_dword
else
UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i1,i2,program_dword
UML_WRITEM(block, I0, I1, I2, SIZE_DWORD, SPACE_PROGRAM); // writem i0,i1,i2,program_dword
}
else
{
@ -1001,38 +997,104 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
if (iswrite)
{
if (!ismasked)
UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword
UML_DWRITE(block, I0, I1, SIZE_QWORD, SPACE_PROGRAM); // dwrite i0,i1,program_qword
else
UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i1,i2,program_qword
UML_DWRITEM(block, I0, I1, I2, SIZE_QWORD, SPACE_PROGRAM); // dwritem i0,i1,i2,program_qword
}
else
{
if (!ismasked)
UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword
UML_DREAD(block, I0, I0, SIZE_QWORD, SPACE_PROGRAM); // dread i0,i0,program_qword
else
UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword
UML_DREADM(block, I0, I0, I2, SIZE_QWORD, SPACE_PROGRAM); // dreadm i0,i0,i2,program_qword
}
break;
}
UML_RET(block); // ret
}
/*------------------------------------------------------------------
static_generate_memory_accessor
------------------------------------------------------------------*/
void mips3_device::static_generate_memory_accessor(int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr)
{
/* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
/* on exit, read result is in I0 */
/* routine trashes I0-I3 */
uml::code_handle &exception_tlb = *m_exception[iswrite ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD];
uml::code_handle &exception_tlbfill = *m_exception[iswrite ? EXCEPTION_TLBSTORE_FILL : EXCEPTION_TLBLOAD_FILL];
uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
int tlbmiss = 0;
int label = 1;
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(1024));
/* add a global entry for this */
alloc_handle(*m_drcuml, handleptr, name);
UML_HANDLE(block, *handleptr); // handle handleptr
static_generate_memory_mode_checks(block, exception_addrerr, label, mode);
/* general case: assume paging and perform a translation */
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4); // load i3,[vtlb_table],i3,dword
UML_TEST(block, I3, iswrite ? WRITE_ALLOWED : READ_ALLOWED); // test i3,iswrite ? WRITE_ALLOWED : READ_ALLOWED
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
static_generate_fastram_accessor(block, label, size, iswrite, ismasked);
static_generate_memory_rw(block, size, iswrite, ismasked);
if (tlbmiss != 0)
{
UML_LABEL(block, tlbmiss); // tlbmiss:
UML_LABEL(block, tlbmiss); // tlbmiss:
if (iswrite)
{
UML_TEST(block, I3, READ_ALLOWED); // test i3,READ_ALLOWED
UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0);
// exh tlbmod,i0,nz
UML_TEST(block, I3, READ_ALLOWED); // test i3,READ_ALLOWED
UML_EXHc(block, COND_NZ, *m_exception[EXCEPTION_TLBMOD], I0); // exh tlbmod,i0,nz
}
UML_TEST(block, I3, FLAG_FIXED); // test i3,FLAG_FIXED
UML_TEST(block, I3, FLAG_FIXED); // test i3,FLAG_FIXED
UML_EXHc(block, COND_NZ, exception_tlb, I0); // exh tlb,i0,nz
UML_EXH(block, exception_tlbfill, I0); // exh tlbfill,i0
UML_EXH(block, exception_tlbfill, I0); // exh tlbfill,i0
}
block.end();
}
void r4650_device::static_generate_memory_accessor(int mode, int size, bool iswrite, bool ismasked, const char *name, uml::code_handle *&handleptr)
{
/* on entry, address is in I0; data for writes is in I1; mask for accesses is in I2 */
/* on exit, read result is in I0 */
/* routine trashes I0-I3 */
uml::code_handle &exception_addrerr = *m_exception[iswrite ? EXCEPTION_ADDRSTORE : EXCEPTION_ADDRLOAD];
int label = 1;
/* begin generating */
drcuml_block &block(m_drcuml->begin_block(1024));
/* add a global entry for this */
alloc_handle(*m_drcuml, handleptr, name);
UML_HANDLE(block, *handleptr); // handle handleptr
static_generate_memory_mode_checks(block, exception_addrerr, label, mode);
if (mode == MODE_USER)
{
int addrok;
UML_CMP(block, I0, CPR032(COP0_R4650_DBound)); // cmp i0,CPR0[DBound]
UML_JMPc(block, COND_LE, addrok = label++); // jle addrok
UML_EXHc(block, COND_G, exception_addrerr, I0); // exh addrerr,i0,ne
UML_LABEL(block, addrok); // addrok:
UML_ADD(block, I0, I0, CPR032(COP0_R4650_DBase)); // add i0,i0,CPR0[DBase]
}
static_generate_fastram_accessor(block, label, size, iswrite, ismasked);
static_generate_memory_rw(block, size, iswrite, ismasked);
block.end();
}
/***************************************************************************