mirror of
https://github.com/holub/mame
synced 2025-06-10 06:47:18 +03:00
mips1: emulate instruction and data caches
This commit is contained in:
parent
cede97e6ae
commit
4af341e49b
@ -6,9 +6,10 @@
|
|||||||
* IDT devices come in two variations: those with an "E" suffix include a TLB,
|
* IDT devices come in two variations: those with an "E" suffix include a TLB,
|
||||||
* while those without have hard-wired address translation.
|
* while those without have hard-wired address translation.
|
||||||
*
|
*
|
||||||
* TODO
|
* TODO:
|
||||||
|
* - multi-word cache line sizes
|
||||||
|
* - verify lwl/lwr and swl/swr cache logic
|
||||||
* - R3041 features
|
* - R3041 features
|
||||||
* - cache emulation
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
@ -24,6 +25,167 @@
|
|||||||
|
|
||||||
#include "logmacro.h"
|
#include "logmacro.h"
|
||||||
|
|
||||||
|
enum registers : unsigned
|
||||||
|
{
|
||||||
|
MIPS1_R0 = 0,
|
||||||
|
MIPS1_COP0 = 32,
|
||||||
|
MIPS1_F0 = 64,
|
||||||
|
|
||||||
|
MIPS1_PC = 80,
|
||||||
|
MIPS1_HI,
|
||||||
|
MIPS1_LO,
|
||||||
|
MIPS1_FCR30,
|
||||||
|
MIPS1_FCR31,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum exception : u32
|
||||||
|
{
|
||||||
|
EXCEPTION_INTERRUPT = 0x00000000,
|
||||||
|
EXCEPTION_TLBMOD = 0x00000004,
|
||||||
|
EXCEPTION_TLBLOAD = 0x00000008,
|
||||||
|
EXCEPTION_TLBSTORE = 0x0000000c,
|
||||||
|
EXCEPTION_ADDRLOAD = 0x00000010,
|
||||||
|
EXCEPTION_ADDRSTORE = 0x00000014,
|
||||||
|
EXCEPTION_BUSINST = 0x00000018,
|
||||||
|
EXCEPTION_BUSDATA = 0x0000001c,
|
||||||
|
EXCEPTION_SYSCALL = 0x00000020,
|
||||||
|
EXCEPTION_BREAK = 0x00000024,
|
||||||
|
EXCEPTION_INVALIDOP = 0x00000028,
|
||||||
|
EXCEPTION_BADCOP = 0x0000002c,
|
||||||
|
EXCEPTION_OVERFLOW = 0x00000030,
|
||||||
|
EXCEPTION_TRAP = 0x00000034,
|
||||||
|
|
||||||
|
EXCEPTION_BADCOP0 = 0x0000002c,
|
||||||
|
EXCEPTION_BADCOP1 = 0x1000002c,
|
||||||
|
EXCEPTION_BADCOP2 = 0x2000002c,
|
||||||
|
EXCEPTION_BADCOP3 = 0x3000002c,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum cop0_reg : u8
|
||||||
|
{
|
||||||
|
COP0_Index = 0,
|
||||||
|
COP0_Random = 1,
|
||||||
|
COP0_EntryLo = 2,
|
||||||
|
COP0_BusCtrl = 2, // r3041 only
|
||||||
|
COP0_Config = 3, // r3041/r3071/r3081 only
|
||||||
|
COP0_Context = 4,
|
||||||
|
COP0_BadVAddr = 8,
|
||||||
|
COP0_Count = 9, // r3041 only
|
||||||
|
COP0_EntryHi = 10,
|
||||||
|
COP0_PortSize = 10, // r3041 only
|
||||||
|
COP0_Compare = 11, // r3041 only
|
||||||
|
COP0_Status = 12,
|
||||||
|
COP0_Cause = 13,
|
||||||
|
COP0_EPC = 14,
|
||||||
|
COP0_PRId = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sr_mask : u32
|
||||||
|
{
|
||||||
|
SR_IEc = 0x00000001, // interrupt enable (current)
|
||||||
|
SR_KUc = 0x00000002, // user mode (current)
|
||||||
|
SR_IEp = 0x00000004, // interrupt enable (previous)
|
||||||
|
SR_KUp = 0x00000008, // user mode (previous)
|
||||||
|
SR_IEo = 0x00000010, // interrupt enable (old)
|
||||||
|
SR_KUo = 0x00000020, // user mode (old)
|
||||||
|
SR_IMSW0 = 0x00000100, // software interrupt 0 enable
|
||||||
|
SR_IMSW1 = 0x00000200, // software interrupt 1 enable
|
||||||
|
SR_IMEX0 = 0x00000400, // external interrupt 0 enable
|
||||||
|
SR_IMEX1 = 0x00000800, // external interrupt 1 enable
|
||||||
|
SR_IMEX2 = 0x00001000, // external interrupt 2 enable
|
||||||
|
SR_IMEX3 = 0x00002000, // external interrupt 3 enable
|
||||||
|
SR_IMEX4 = 0x00004000, // external interrupt 4 enable
|
||||||
|
SR_IMEX5 = 0x00008000, // external interrupt 5 enable
|
||||||
|
SR_IsC = 0x00010000, // isolate (data) cache
|
||||||
|
SR_SwC = 0x00020000, // swap caches
|
||||||
|
SR_PZ = 0x00040000, // cache parity zero
|
||||||
|
SR_CM = 0x00080000, // cache miss
|
||||||
|
SR_PE = 0x00100000, // cache parity error
|
||||||
|
SR_TS = 0x00200000, // tlb shutdown
|
||||||
|
SR_BEV = 0x00400000, // boot exception vectors
|
||||||
|
SR_RE = 0x02000000, // reverse endianness in user mode
|
||||||
|
SR_COP0 = 0x10000000, // coprocessor 0 usable
|
||||||
|
SR_COP1 = 0x20000000, // coprocessor 1 usable
|
||||||
|
SR_COP2 = 0x40000000, // coprocessor 2 usable
|
||||||
|
SR_COP3 = 0x80000000, // coprocessor 3 usable
|
||||||
|
|
||||||
|
SR_KUIE = 0x0000003f, // all interrupt enable and user mode bits
|
||||||
|
SR_KUIEpc = 0x0000000f, // previous and current interrupt enable and user mode bits
|
||||||
|
SR_KUIEop = 0x0000003c, // old and previous interrupt enable and user mode bits
|
||||||
|
SR_IM = 0x0000ff00, // all interrupt mask bits
|
||||||
|
};
|
||||||
|
|
||||||
|
enum cause_mask : u32
|
||||||
|
{
|
||||||
|
CAUSE_EXCCODE = 0x0000007c, // exception code
|
||||||
|
CAUSE_IPSW0 = 0x00000100, // software interrupt 0 pending
|
||||||
|
CAUSE_IPSW1 = 0x00000200, // software interrupt 1 pending
|
||||||
|
CAUSE_IPEX0 = 0x00000400, // external interrupt 0 pending
|
||||||
|
CAUSE_IPEX1 = 0x00000800, // external interrupt 1 pending
|
||||||
|
CAUSE_IPEX2 = 0x00001000, // external interrupt 2 pending
|
||||||
|
CAUSE_IPEX3 = 0x00002000, // external interrupt 3 pending
|
||||||
|
CAUSE_IPEX4 = 0x00004000, // external interrupt 4 pending
|
||||||
|
CAUSE_IPEX5 = 0x00008000, // external interrupt 5 pending
|
||||||
|
CAUSE_IP = 0x0000ff00, // interrupt pending
|
||||||
|
CAUSE_CE = 0x30000000, // co-processor error
|
||||||
|
CAUSE_BD = 0x80000000, // branch delay
|
||||||
|
|
||||||
|
CAUSE_IPEX = 0x0000fc00, // external interrupt pending
|
||||||
|
};
|
||||||
|
|
||||||
|
enum entryhi_mask : u32
|
||||||
|
{
|
||||||
|
EH_VPN = 0xfffff000, // virtual page number
|
||||||
|
EH_ASID = 0x00000fc0, // address space identifier
|
||||||
|
|
||||||
|
EH_WM = 0xffffffc0, // write mask
|
||||||
|
};
|
||||||
|
enum entrylo_mask : u32
|
||||||
|
{
|
||||||
|
EL_PFN = 0xfffff000, // physical frame
|
||||||
|
EL_N = 0x00000800, // noncacheable
|
||||||
|
EL_D = 0x00000400, // dirty
|
||||||
|
EL_V = 0x00000200, // valid
|
||||||
|
EL_G = 0x00000100, // global
|
||||||
|
|
||||||
|
EL_WM = 0xffffff00, // write mask
|
||||||
|
};
|
||||||
|
enum context_mask : u32
|
||||||
|
{
|
||||||
|
PTE_BASE = 0xffe00000, // base address of page table
|
||||||
|
BAD_VPN = 0x001ffffc, // virtual address bits 30..12
|
||||||
|
};
|
||||||
|
|
||||||
|
enum cp1_fcr31_mask : u32
|
||||||
|
{
|
||||||
|
FCR31_RM = 0x00000003, // rounding mode
|
||||||
|
|
||||||
|
FCR31_FI = 0x00000004, // inexact operation flag
|
||||||
|
FCR31_FU = 0x00000008, // underflow flag
|
||||||
|
FCR31_FO = 0x00000010, // overflow flag
|
||||||
|
FCR31_FZ = 0x00000020, // divide by zero flag
|
||||||
|
FCR31_FV = 0x00000040, // invalid operation flag
|
||||||
|
|
||||||
|
FCR31_EI = 0x00000080, // inexact operation enable
|
||||||
|
FCR31_EU = 0x00000100, // underflow enable
|
||||||
|
FCR31_EO = 0x00000200, // overflow enable
|
||||||
|
FCR31_EZ = 0x00000400, // divide by zero enable
|
||||||
|
FCR31_EV = 0x00000800, // invalid operation enable
|
||||||
|
|
||||||
|
FCR31_CI = 0x00001000, // inexact operation cause
|
||||||
|
FCR31_CU = 0x00002000, // underflow cause
|
||||||
|
FCR31_CO = 0x00004000, // overflow cause
|
||||||
|
FCR31_CZ = 0x00008000, // divide by zero cause
|
||||||
|
FCR31_CV = 0x00010000, // invalid operation cause
|
||||||
|
FCR31_CE = 0x00020000, // unimplemented operation cause
|
||||||
|
|
||||||
|
FCR31_C = 0x00800000, // condition
|
||||||
|
|
||||||
|
FCR31_FM = 0x0000007c, // flag mask
|
||||||
|
FCR31_EM = 0x00000f80, // enable mask
|
||||||
|
FCR31_CM = 0x0001f000, // cause mask (except unimplemented)
|
||||||
|
};
|
||||||
|
|
||||||
#define RSREG ((op >> 21) & 31)
|
#define RSREG ((op >> 21) & 31)
|
||||||
#define RTREG ((op >> 16) & 31)
|
#define RTREG ((op >> 16) & 31)
|
||||||
#define RDREG ((op >> 11) & 31)
|
#define RDREG ((op >> 11) & 31)
|
||||||
@ -58,13 +220,12 @@ mips1core_device_base::mips1core_device_base(machine_config const &mconfig, devi
|
|||||||
: cpu_device(mconfig, type, tag, owner, clock)
|
: cpu_device(mconfig, type, tag, owner, clock)
|
||||||
, m_program_config_be("program", ENDIANNESS_BIG, 32, 32)
|
, m_program_config_be("program", ENDIANNESS_BIG, 32, 32)
|
||||||
, m_program_config_le("program", ENDIANNESS_LITTLE, 32, 32)
|
, m_program_config_le("program", ENDIANNESS_LITTLE, 32, 32)
|
||||||
, m_icache_config("icache", ENDIANNESS_BIG, 32, 32)
|
|
||||||
, m_dcache_config("dcache", ENDIANNESS_BIG, 32, 32)
|
|
||||||
, m_cpurev(cpurev)
|
, m_cpurev(cpurev)
|
||||||
, m_endianness(ENDIANNESS_BIG)
|
, m_endianness(ENDIANNESS_BIG)
|
||||||
, m_icount(0)
|
, m_icount(0)
|
||||||
, m_icache_size(icache_size)
|
, m_icache(icache_size)
|
||||||
, m_dcache_size(dcache_size)
|
, m_dcache(dcache_size)
|
||||||
|
, m_cache((icache_size && dcache_size) ? CACHED : UNCACHED)
|
||||||
, m_in_brcond(*this, 0)
|
, m_in_brcond(*this, 0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -132,17 +293,6 @@ iop_device::iop_device(machine_config const &mconfig, char const *tag, device_t
|
|||||||
m_endianness = ENDIANNESS_LITTLE;
|
m_endianness = ENDIANNESS_LITTLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Two additional address spaces are defined to represent the instruction and
|
|
||||||
* data caches. These are only used to simulate cache isolation functionality
|
|
||||||
* at this point, but could simulate other behaviour as needed in future.
|
|
||||||
*/
|
|
||||||
void mips1core_device_base::device_add_mconfig(machine_config &config)
|
|
||||||
{
|
|
||||||
set_addrmap(1, &mips1core_device_base::icache_map);
|
|
||||||
set_addrmap(2, &mips1core_device_base::dcache_map);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mips1core_device_base::device_start()
|
void mips1core_device_base::device_start()
|
||||||
{
|
{
|
||||||
// set our instruction counter
|
// set our instruction counter
|
||||||
@ -181,6 +331,14 @@ void mips1core_device_base::device_start()
|
|||||||
m_cop0[COP0_Cause] = 0;
|
m_cop0[COP0_Cause] = 0;
|
||||||
|
|
||||||
m_r[0] = 0;
|
m_r[0] = 0;
|
||||||
|
|
||||||
|
m_icache.start();
|
||||||
|
m_dcache.start();
|
||||||
|
|
||||||
|
save_pointer(STRUCT_MEMBER(m_icache.line, tag), m_icache.lines());
|
||||||
|
save_pointer(STRUCT_MEMBER(m_icache.line, data), m_icache.lines());
|
||||||
|
save_pointer(STRUCT_MEMBER(m_dcache.line, tag), m_dcache.lines());
|
||||||
|
save_pointer(STRUCT_MEMBER(m_dcache.line, data), m_dcache.lines());
|
||||||
}
|
}
|
||||||
|
|
||||||
void r3041_device::device_start()
|
void r3041_device::device_start()
|
||||||
@ -208,7 +366,6 @@ void mips1core_device_base::device_reset()
|
|||||||
// non-tlb devices have tlb shut down
|
// non-tlb devices have tlb shut down
|
||||||
m_cop0[COP0_Status] = SR_BEV | SR_TS;
|
m_cop0[COP0_Status] = SR_BEV | SR_TS;
|
||||||
|
|
||||||
m_data_spacenum = 0;
|
|
||||||
m_bus_error = false;
|
m_bus_error = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -632,21 +789,21 @@ void mips1core_device_base::execute_set_input(int irqline, int state)
|
|||||||
device_memory_interface::space_config_vector mips1core_device_base::memory_space_config() const
|
device_memory_interface::space_config_vector mips1core_device_base::memory_space_config() const
|
||||||
{
|
{
|
||||||
return space_config_vector {
|
return space_config_vector {
|
||||||
std::make_pair(AS_PROGRAM, (m_endianness == ENDIANNESS_BIG) ? &m_program_config_be : &m_program_config_le),
|
std::make_pair(AS_PROGRAM, (m_endianness == ENDIANNESS_BIG) ? &m_program_config_be : &m_program_config_le)
|
||||||
std::make_pair(1, &m_icache_config),
|
|
||||||
std::make_pair(2, &m_dcache_config)
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
|
bool mips1core_device_base::memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space)
|
||||||
{
|
{
|
||||||
target_space = &space(spacenum);
|
target_space = &space(spacenum);
|
||||||
|
|
||||||
if (spacenum != AS_PROGRAM)
|
if (spacenum != AS_PROGRAM)
|
||||||
return true;
|
return true;
|
||||||
return translate(intention, address, true);
|
|
||||||
|
return translate(intention, address, true) != ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mips1core_device_base::translate(int intention, offs_t &address, bool debug)
|
mips1core_device_base::translate_result mips1core_device_base::translate(int intention, offs_t &address, bool debug)
|
||||||
{
|
{
|
||||||
// check for kernel memory address
|
// check for kernel memory address
|
||||||
if (BIT(address, 31))
|
if (BIT(address, 31))
|
||||||
@ -657,9 +814,12 @@ bool mips1core_device_base::translate(int intention, offs_t &address, bool debug
|
|||||||
switch (address & 0xe0000000)
|
switch (address & 0xe0000000)
|
||||||
{
|
{
|
||||||
case 0x80000000: // kseg0: unmapped, cached, privileged
|
case 0x80000000: // kseg0: unmapped, cached, privileged
|
||||||
|
address &= ~0xe0000000;
|
||||||
|
return m_cache;
|
||||||
|
|
||||||
case 0xa0000000: // kseg1: unmapped, uncached, privileged
|
case 0xa0000000: // kseg1: unmapped, uncached, privileged
|
||||||
address &= ~0xe0000000;
|
address &= ~0xe0000000;
|
||||||
break;
|
return UNCACHED;
|
||||||
|
|
||||||
case 0xc0000000: // kseg2: mapped, cached, privileged
|
case 0xc0000000: // kseg2: mapped, cached, privileged
|
||||||
case 0xe0000000:
|
case 0xe0000000:
|
||||||
@ -670,14 +830,14 @@ bool mips1core_device_base::translate(int intention, offs_t &address, bool debug
|
|||||||
{
|
{
|
||||||
address_error(intention, address);
|
address_error(intention, address);
|
||||||
|
|
||||||
return false;
|
return ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// kuseg physical addresses have a 1GB offset
|
// kuseg physical addresses have a 1GB offset
|
||||||
address += 0x40000000;
|
address += 0x40000000;
|
||||||
|
|
||||||
return true;
|
return m_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembler()
|
std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembler()
|
||||||
@ -685,18 +845,6 @@ std::unique_ptr<util::disasm_interface> mips1core_device_base::create_disassembl
|
|||||||
return std::make_unique<mips1_disassembler>();
|
return std::make_unique<mips1_disassembler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mips1core_device_base::icache_map(address_map &map)
|
|
||||||
{
|
|
||||||
if (m_icache_size)
|
|
||||||
map(0, m_icache_size - 1).ram().mirror(~(m_icache_size - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void mips1core_device_base::dcache_map(address_map &map)
|
|
||||||
{
|
|
||||||
if (m_dcache_size)
|
|
||||||
map(0, m_dcache_size - 1).ram().mirror(~(m_dcache_size - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
void mips1core_device_base::generate_exception(u32 exception, bool refill)
|
void mips1core_device_base::generate_exception(u32 exception, bool refill)
|
||||||
{
|
{
|
||||||
if ((VERBOSE & LOG_RISCOS) && (exception == EXCEPTION_SYSCALL))
|
if ((VERBOSE & LOG_RISCOS) && (exception == EXCEPTION_SYSCALL))
|
||||||
@ -954,10 +1102,10 @@ void mips1core_device_base::set_cop0_reg(unsigned const reg, u32 const data)
|
|||||||
{
|
{
|
||||||
u32 const delta = SR ^ data;
|
u32 const delta = SR ^ data;
|
||||||
|
|
||||||
m_cop0[COP0_Status] = data;
|
if ((delta & SR_IsC) && (m_cache == UNCACHED))
|
||||||
|
fatalerror("mips1: cannot isolate non-existent cache (%s)\n", machine().describe_context());
|
||||||
|
|
||||||
// handle cache isolation and swap
|
m_cop0[COP0_Status] = data;
|
||||||
m_data_spacenum = (data & SR_IsC) ? ((data & SR_SwC) ? 1 : 2) : 0;
|
|
||||||
|
|
||||||
if ((delta & SR_KUc) && (m_branch_state != EXCEPTION))
|
if ((delta & SR_KUc) && (m_branch_state != EXCEPTION))
|
||||||
debugger_privilege_hook();
|
debugger_privilege_hook();
|
||||||
@ -1074,7 +1222,7 @@ void mips1core_device_base::lwr(u32 const op)
|
|||||||
offs_t const offset = SIMMVAL + m_r[RSREG];
|
offs_t const offset = SIMMVAL + m_r[RSREG];
|
||||||
load<u32, false>(offset, [this, op, offset](u32 temp)
|
load<u32, false>(offset, [this, op, offset](u32 temp)
|
||||||
{
|
{
|
||||||
unsigned const shift = ((offset & 0x3) ^ (m_endianness == ENDIANNESS_LITTLE ? 0 : 3)) << 3;
|
unsigned const shift = ((offset & 3) ^ (m_endianness == ENDIANNESS_LITTLE ? 0 : 3)) << 3;
|
||||||
|
|
||||||
m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU >> shift)) | (temp >> shift);
|
m_r[RTREG] = (m_r[RTREG] & ~u32(0xffffffffU >> shift)) | (temp >> shift);
|
||||||
});
|
});
|
||||||
@ -1096,6 +1244,53 @@ void mips1core_device_base::swr(u32 const op)
|
|||||||
store<u32, false>(offset, m_r[RTREG] << shift, 0xffffffffU << shift);
|
store<u32, false>(offset, m_r[RTREG] << shift, 0xffffffffU << shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function determines the active cache (instruction or data) depending on
|
||||||
|
* the icache parameter and the status register SwC (swap caches) flag. A line
|
||||||
|
* within the cache is then selected based upon the low address bits. The upper
|
||||||
|
* address bits are compared with the line tag to identify whether the lookup
|
||||||
|
* is a hit or a miss.
|
||||||
|
*
|
||||||
|
* If the cache lookup misses and the invalidate parameter evaluates to true,
|
||||||
|
* the cache line tag is updated to match the input address and invalidated.
|
||||||
|
*
|
||||||
|
* The function returns the selected line and the miss state.
|
||||||
|
*
|
||||||
|
* TODO: multiple-word cache lines
|
||||||
|
*/
|
||||||
|
std::tuple<struct mips1core_device_base::cache::line &, bool> mips1core_device_base::cache_lookup(u32 address, bool invalidate, bool icache)
|
||||||
|
{
|
||||||
|
// cache line data is word-addressed
|
||||||
|
address &= ~3;
|
||||||
|
|
||||||
|
// select instruction or data cache
|
||||||
|
struct cache const &c = (icache ^ bool(SR & SR_SwC)) ? m_icache : m_dcache;
|
||||||
|
|
||||||
|
// select line within cache based on low address bits
|
||||||
|
struct cache::line &l = c.line[(address & (c.size - 1)) >> 2];
|
||||||
|
|
||||||
|
// compare cache line tag against upper address bits and line valid bit
|
||||||
|
bool const miss = (l.tag ^ address) & (-c.size | cache::line::INV);
|
||||||
|
|
||||||
|
// on cache miss, optionally update the line tag and invalidate (cache
|
||||||
|
// miss is usually followed by line replacement)
|
||||||
|
if (miss && invalidate)
|
||||||
|
l.tag = (address & -c.size) | cache::line::INV;
|
||||||
|
|
||||||
|
return std::tie(l, miss);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute bit position of sub-unit within a word given endianness and address
|
||||||
|
template <typename T> unsigned mips1core_device_base::shift_factor(u32 address) const
|
||||||
|
{
|
||||||
|
if constexpr (sizeof(T) == 1)
|
||||||
|
return ((m_endianness == ENDIANNESS_BIG) ? (address & 3) ^ 3 : (address & 3)) * 8;
|
||||||
|
else if constexpr (sizeof(T) == 2)
|
||||||
|
return ((m_endianness == ENDIANNESS_BIG) ? (address & 2) ^ 2 : (address & 2)) * 8;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply)
|
template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> mips1core_device_base::load(u32 address, U &&apply)
|
||||||
{
|
{
|
||||||
// alignment error
|
// alignment error
|
||||||
@ -1105,28 +1300,75 @@ template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convert
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translate(TR_READ, address, false))
|
T data;
|
||||||
|
if (!(SR & SR_IsC))
|
||||||
{
|
{
|
||||||
|
translate_result const t = translate(TR_READ, address, false);
|
||||||
|
if (t == ERROR)
|
||||||
|
return;
|
||||||
|
|
||||||
// align address for ld[lr] instructions
|
// align address for ld[lr] instructions
|
||||||
if (!Aligned)
|
if (!Aligned)
|
||||||
address &= ~(sizeof(T) - 1);
|
address &= ~(sizeof(T) - 1);
|
||||||
|
|
||||||
T const data
|
if (t == CACHED)
|
||||||
= (sizeof(T) == 1) ? space(m_data_spacenum).read_byte(address)
|
{
|
||||||
: (sizeof(T) == 2) ? space(m_data_spacenum).read_word(address)
|
auto [l, miss] = cache_lookup(address, true);
|
||||||
: space(m_data_spacenum).read_dword(address);
|
|
||||||
|
if (miss)
|
||||||
|
{
|
||||||
|
// load
|
||||||
|
u32 const data = space(AS_PROGRAM).read_dword(address);
|
||||||
|
if (m_bus_error)
|
||||||
|
{
|
||||||
|
m_bus_error = false;
|
||||||
|
generate_exception(EXCEPTION_BUSDATA);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace cache line data and mark valid
|
||||||
|
l.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = l.data >> shift_factor<T>(address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if constexpr (sizeof(T) == 4)
|
||||||
|
data = space(AS_PROGRAM).read_dword(address);
|
||||||
|
else if constexpr (sizeof(T) == 2)
|
||||||
|
data = space(AS_PROGRAM).read_word(address);
|
||||||
|
else if constexpr (sizeof(T) == 1)
|
||||||
|
data = space(AS_PROGRAM).read_byte(address);
|
||||||
|
|
||||||
if (m_bus_error)
|
if (m_bus_error)
|
||||||
{
|
{
|
||||||
m_bus_error = false;
|
m_bus_error = false;
|
||||||
generate_exception(EXCEPTION_BUSDATA);
|
generate_exception(EXCEPTION_BUSDATA);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
apply(data);
|
{
|
||||||
|
// when isolated, loads always hit the cache and the status register
|
||||||
|
// CM flag reflects the actual hit/miss state
|
||||||
|
auto [l, miss] = cache_lookup(address, false);
|
||||||
|
|
||||||
|
if (miss)
|
||||||
|
SR |= SR_CM;
|
||||||
|
else
|
||||||
|
SR &= ~SR_CM;
|
||||||
|
|
||||||
|
data = l.data >> shift_factor<T>(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apply(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> mips1core_device_base::store(u32 address, U data, T mem_mask)
|
template <typename T, bool Aligned> void mips1core_device_base::store(u32 address, T data, T mem_mask)
|
||||||
{
|
{
|
||||||
// alignment error
|
// alignment error
|
||||||
if (Aligned && (address & (sizeof(T) - 1)))
|
if (Aligned && (address & (sizeof(T) - 1)))
|
||||||
@ -1135,47 +1377,99 @@ template <typename T, bool Aligned, typename U> std::enable_if_t<std::is_convert
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translate(TR_WRITE, address, false))
|
if (!(SR & SR_IsC))
|
||||||
{
|
{
|
||||||
|
translate_result const t = translate(TR_WRITE, address, false);
|
||||||
|
if (t == ERROR)
|
||||||
|
return;
|
||||||
|
|
||||||
// align address for sd[lr] instructions
|
// align address for sd[lr] instructions
|
||||||
if (!Aligned)
|
if (!Aligned)
|
||||||
address &= ~(sizeof(T) - 1);
|
address &= ~(sizeof(T) - 1);
|
||||||
|
|
||||||
switch (sizeof(T))
|
if (t == CACHED)
|
||||||
{
|
{
|
||||||
case 1: space(m_data_spacenum).write_byte(address, T(data)); break;
|
auto [l, miss] = cache_lookup(address, sizeof(T) == 4);
|
||||||
case 2: space(m_data_spacenum).write_word(address, T(data), mem_mask); break;
|
|
||||||
case 4: space(m_data_spacenum).write_dword(address, T(data), mem_mask); break;
|
if (!miss)
|
||||||
|
{
|
||||||
|
unsigned const shift = shift_factor<T>(address);
|
||||||
|
|
||||||
|
l.update(u32(data) << shift, u32(mem_mask) << shift);
|
||||||
}
|
}
|
||||||
|
else if constexpr (sizeof(T) == 4)
|
||||||
|
// only full word stores update the cache after a miss
|
||||||
|
l.update(data, mem_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// uncached or write-through store
|
||||||
|
if constexpr (sizeof(T) == 4)
|
||||||
|
space(AS_PROGRAM).write_dword(address, T(data), mem_mask);
|
||||||
|
else if constexpr (sizeof(T) == 2)
|
||||||
|
space(AS_PROGRAM).write_word(address, T(data), mem_mask);
|
||||||
|
else if constexpr (sizeof(T) == 1)
|
||||||
|
space(AS_PROGRAM).write_byte(address, T(data));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// when isolated, full word stores update the cache, while partial word
|
||||||
|
// stores invalidate the cache line
|
||||||
|
auto [l, miss] = cache_lookup(address, true);
|
||||||
|
|
||||||
|
if constexpr (sizeof(T) == 4)
|
||||||
|
l.update(data, mem_mask);
|
||||||
|
else
|
||||||
|
l.invalidate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mips1core_device_base::fetch(u32 address, std::function<void(u32)> &&apply)
|
void mips1core_device_base::fetch(u32 address, std::function<void(u32)> &&apply)
|
||||||
{
|
{
|
||||||
// alignment error
|
// alignment error
|
||||||
if (address & 3)
|
if (address & 3)
|
||||||
{
|
|
||||||
address_error(TR_FETCH, address);
|
address_error(TR_FETCH, address);
|
||||||
return false;
|
|
||||||
|
translate_result const t = translate(TR_FETCH, address, false);
|
||||||
|
if (t == ERROR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
u32 data;
|
||||||
|
if (t == CACHED)
|
||||||
|
{
|
||||||
|
auto [l, miss] = cache_lookup(address, true, true);
|
||||||
|
|
||||||
|
if (miss)
|
||||||
|
{
|
||||||
|
// fetch
|
||||||
|
u32 const data = space(AS_PROGRAM).read_dword(address);
|
||||||
|
if (m_bus_error)
|
||||||
|
{
|
||||||
|
m_bus_error = false;
|
||||||
|
generate_exception(EXCEPTION_BUSINST);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (translate(TR_FETCH, address, false))
|
// replace cache line data and mark valid
|
||||||
|
l.update(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = l.data;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
u32 const data = space(AS_PROGRAM).read_dword(address);
|
data = space(AS_PROGRAM).read_dword(address);
|
||||||
|
|
||||||
if (m_bus_error)
|
if (m_bus_error)
|
||||||
{
|
{
|
||||||
m_bus_error = false;
|
m_bus_error = false;
|
||||||
generate_exception(EXCEPTION_BUSINST);
|
generate_exception(EXCEPTION_BUSINST);
|
||||||
|
|
||||||
return false;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(data);
|
apply(data);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string mips1core_device_base::debug_string(u32 string_pointer, unsigned const limit)
|
std::string mips1core_device_base::debug_string(u32 string_pointer, unsigned const limit)
|
||||||
@ -1949,7 +2243,7 @@ template <typename T> void mips1_device_base::set_cop1_reg(unsigned const reg, T
|
|||||||
m_f[reg] = data;
|
m_f[reg] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
mips1core_device_base::translate_result mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
||||||
{
|
{
|
||||||
// check for kernel memory address
|
// check for kernel memory address
|
||||||
if (BIT(address, 31))
|
if (BIT(address, 31))
|
||||||
@ -1960,9 +2254,12 @@ bool mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
|||||||
switch (address & 0xe0000000)
|
switch (address & 0xe0000000)
|
||||||
{
|
{
|
||||||
case 0x80000000: // kseg0: unmapped, cached, privileged
|
case 0x80000000: // kseg0: unmapped, cached, privileged
|
||||||
|
address &= ~0xe0000000;
|
||||||
|
return m_cache;
|
||||||
|
|
||||||
case 0xa0000000: // kseg1: unmapped, uncached, privileged
|
case 0xa0000000: // kseg1: unmapped, uncached, privileged
|
||||||
address &= ~0xe0000000;
|
address &= ~0xe0000000;
|
||||||
return true;
|
return UNCACHED;
|
||||||
|
|
||||||
case 0xc0000000: // kseg2: mapped, cached, privileged
|
case 0xc0000000: // kseg2: mapped, cached, privileged
|
||||||
case 0xe0000000:
|
case 0xe0000000:
|
||||||
@ -1973,7 +2270,7 @@ bool mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
|||||||
{
|
{
|
||||||
address_error(intention, address);
|
address_error(intention, address);
|
||||||
|
|
||||||
return false;
|
return ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2018,7 +2315,7 @@ bool mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
|||||||
if (i > 0)
|
if (i > 0)
|
||||||
std::swap(mru[i - 1], mru[i]);
|
std::swap(mru[i - 1], mru[i]);
|
||||||
|
|
||||||
return true;
|
return (entry[1] & EL_N) ? UNCACHED : m_cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!machine().side_effects_disabled() && !debug)
|
if (!machine().side_effects_disabled() && !debug)
|
||||||
@ -2041,5 +2338,5 @@ bool mips1_device_base::translate(int intention, offs_t &address, bool debug)
|
|||||||
generate_exception(modify ? EXCEPTION_TLBMOD : (intention == TR_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill);
|
generate_exception(modify ? EXCEPTION_TLBMOD : (intention == TR_WRITE) ? EXCEPTION_TLBSTORE : EXCEPTION_TLBLOAD, refill);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return ERROR;
|
||||||
}
|
}
|
||||||
|
@ -19,139 +19,7 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
mips1core_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
||||||
|
|
||||||
enum registers : unsigned
|
|
||||||
{
|
|
||||||
MIPS1_R0 = 0,
|
|
||||||
MIPS1_COP0 = 32,
|
|
||||||
MIPS1_F0 = 64,
|
|
||||||
|
|
||||||
MIPS1_PC = 80,
|
|
||||||
MIPS1_HI,
|
|
||||||
MIPS1_LO,
|
|
||||||
MIPS1_FCR30,
|
|
||||||
MIPS1_FCR31,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum exception : u32
|
|
||||||
{
|
|
||||||
EXCEPTION_INTERRUPT = 0x00000000,
|
|
||||||
EXCEPTION_TLBMOD = 0x00000004,
|
|
||||||
EXCEPTION_TLBLOAD = 0x00000008,
|
|
||||||
EXCEPTION_TLBSTORE = 0x0000000c,
|
|
||||||
EXCEPTION_ADDRLOAD = 0x00000010,
|
|
||||||
EXCEPTION_ADDRSTORE = 0x00000014,
|
|
||||||
EXCEPTION_BUSINST = 0x00000018,
|
|
||||||
EXCEPTION_BUSDATA = 0x0000001c,
|
|
||||||
EXCEPTION_SYSCALL = 0x00000020,
|
|
||||||
EXCEPTION_BREAK = 0x00000024,
|
|
||||||
EXCEPTION_INVALIDOP = 0x00000028,
|
|
||||||
EXCEPTION_BADCOP = 0x0000002c,
|
|
||||||
EXCEPTION_OVERFLOW = 0x00000030,
|
|
||||||
EXCEPTION_TRAP = 0x00000034,
|
|
||||||
|
|
||||||
EXCEPTION_BADCOP0 = 0x0000002c,
|
|
||||||
EXCEPTION_BADCOP1 = 0x1000002c,
|
|
||||||
EXCEPTION_BADCOP2 = 0x2000002c,
|
|
||||||
EXCEPTION_BADCOP3 = 0x3000002c,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum cop0_reg : u8
|
|
||||||
{
|
|
||||||
COP0_Index = 0,
|
|
||||||
COP0_Random = 1,
|
|
||||||
COP0_EntryLo = 2,
|
|
||||||
COP0_BusCtrl = 2, // r3041 only
|
|
||||||
COP0_Config = 3, // r3041/r3071/r3081 only
|
|
||||||
COP0_Context = 4,
|
|
||||||
COP0_BadVAddr = 8,
|
|
||||||
COP0_Count = 9, // r3041 only
|
|
||||||
COP0_EntryHi = 10,
|
|
||||||
COP0_PortSize = 10, // r3041 only
|
|
||||||
COP0_Compare = 11, // r3041 only
|
|
||||||
COP0_Status = 12,
|
|
||||||
COP0_Cause = 13,
|
|
||||||
COP0_EPC = 14,
|
|
||||||
COP0_PRId = 15,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum sr_mask : u32
|
|
||||||
{
|
|
||||||
SR_IEc = 0x00000001, // interrupt enable (current)
|
|
||||||
SR_KUc = 0x00000002, // user mode (current)
|
|
||||||
SR_IEp = 0x00000004, // interrupt enable (previous)
|
|
||||||
SR_KUp = 0x00000008, // user mode (previous)
|
|
||||||
SR_IEo = 0x00000010, // interrupt enable (old)
|
|
||||||
SR_KUo = 0x00000020, // user mode (old)
|
|
||||||
SR_IMSW0 = 0x00000100, // software interrupt 0 enable
|
|
||||||
SR_IMSW1 = 0x00000200, // software interrupt 1 enable
|
|
||||||
SR_IMEX0 = 0x00000400, // external interrupt 0 enable
|
|
||||||
SR_IMEX1 = 0x00000800, // external interrupt 1 enable
|
|
||||||
SR_IMEX2 = 0x00001000, // external interrupt 2 enable
|
|
||||||
SR_IMEX3 = 0x00002000, // external interrupt 3 enable
|
|
||||||
SR_IMEX4 = 0x00004000, // external interrupt 4 enable
|
|
||||||
SR_IMEX5 = 0x00008000, // external interrupt 5 enable
|
|
||||||
SR_IsC = 0x00010000, // isolate (data) cache
|
|
||||||
SR_SwC = 0x00020000, // swap caches
|
|
||||||
SR_PZ = 0x00040000, // cache parity zero
|
|
||||||
SR_CM = 0x00080000, // cache match
|
|
||||||
SR_PE = 0x00100000, // cache parity error
|
|
||||||
SR_TS = 0x00200000, // tlb shutdown
|
|
||||||
SR_BEV = 0x00400000, // boot exception vectors
|
|
||||||
SR_RE = 0x02000000, // reverse endianness in user mode
|
|
||||||
SR_COP0 = 0x10000000, // coprocessor 0 usable
|
|
||||||
SR_COP1 = 0x20000000, // coprocessor 1 usable
|
|
||||||
SR_COP2 = 0x40000000, // coprocessor 2 usable
|
|
||||||
SR_COP3 = 0x80000000, // coprocessor 3 usable
|
|
||||||
|
|
||||||
SR_KUIE = 0x0000003f, // all interrupt enable and user mode bits
|
|
||||||
SR_KUIEpc = 0x0000000f, // previous and current interrupt enable and user mode bits
|
|
||||||
SR_KUIEop = 0x0000003c, // old and previous interrupt enable and user mode bits
|
|
||||||
SR_IM = 0x0000ff00, // all interrupt mask bits
|
|
||||||
};
|
|
||||||
|
|
||||||
enum cause_mask : u32
|
|
||||||
{
|
|
||||||
CAUSE_EXCCODE = 0x0000007c, // exception code
|
|
||||||
CAUSE_IPSW0 = 0x00000100, // software interrupt 0 pending
|
|
||||||
CAUSE_IPSW1 = 0x00000200, // software interrupt 1 pending
|
|
||||||
CAUSE_IPEX0 = 0x00000400, // external interrupt 0 pending
|
|
||||||
CAUSE_IPEX1 = 0x00000800, // external interrupt 1 pending
|
|
||||||
CAUSE_IPEX2 = 0x00001000, // external interrupt 2 pending
|
|
||||||
CAUSE_IPEX3 = 0x00002000, // external interrupt 3 pending
|
|
||||||
CAUSE_IPEX4 = 0x00004000, // external interrupt 4 pending
|
|
||||||
CAUSE_IPEX5 = 0x00008000, // external interrupt 5 pending
|
|
||||||
CAUSE_IP = 0x0000ff00, // interrupt pending
|
|
||||||
CAUSE_CE = 0x30000000, // co-processor error
|
|
||||||
CAUSE_BD = 0x80000000, // branch delay
|
|
||||||
|
|
||||||
CAUSE_IPEX = 0x0000fc00, // external interrupt pending
|
|
||||||
};
|
|
||||||
|
|
||||||
enum entryhi_mask : u32
|
|
||||||
{
|
|
||||||
EH_VPN = 0xfffff000, // virtual page number
|
|
||||||
EH_ASID = 0x00000fc0, // address space identifier
|
|
||||||
|
|
||||||
EH_WM = 0xffffffc0, // write mask
|
|
||||||
};
|
|
||||||
enum entrylo_mask : u32
|
|
||||||
{
|
|
||||||
EL_PFN = 0xfffff000, // physical frame
|
|
||||||
EL_N = 0x00000800, // noncacheable
|
|
||||||
EL_D = 0x00000400, // dirty
|
|
||||||
EL_V = 0x00000200, // valid
|
|
||||||
EL_G = 0x00000100, // global
|
|
||||||
|
|
||||||
EL_WM = 0xffffff00, // write mask
|
|
||||||
};
|
|
||||||
enum context_mask : u32
|
|
||||||
{
|
|
||||||
PTE_BASE = 0xffe00000, // base address of page table
|
|
||||||
BAD_VPN = 0x001ffffc, // virtual address bits 30..12
|
|
||||||
};
|
|
||||||
|
|
||||||
// device_t implementation
|
// device_t implementation
|
||||||
virtual void device_add_mconfig(machine_config &config) override;
|
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
|
||||||
@ -169,11 +37,6 @@ protected:
|
|||||||
// device_disasm_interface implementation
|
// device_disasm_interface implementation
|
||||||
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
||||||
|
|
||||||
virtual bool translate(int intention, offs_t &address, bool debug);
|
|
||||||
|
|
||||||
void icache_map(address_map &map);
|
|
||||||
void dcache_map(address_map &map);
|
|
||||||
|
|
||||||
// exceptions
|
// exceptions
|
||||||
void generate_exception(u32 exception, bool refill = false);
|
void generate_exception(u32 exception, bool refill = false);
|
||||||
void address_error(int intention, u32 const address);
|
void address_error(int intention, u32 const address);
|
||||||
@ -194,10 +57,47 @@ protected:
|
|||||||
void swl(u32 const op);
|
void swl(u32 const op);
|
||||||
void swr(u32 const op);
|
void swr(u32 const op);
|
||||||
|
|
||||||
// memory accessors
|
// memory
|
||||||
|
enum translate_result : unsigned { ERROR, UNCACHED, CACHED };
|
||||||
|
virtual translate_result translate(int intention, offs_t &address, bool debug);
|
||||||
template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
|
template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, void> load(u32 address, U &&apply);
|
||||||
template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, T>::value, void> store(u32 address, U data, T mem_mask = ~T(0));
|
template <typename T, bool Aligned = true> void store(u32 address, T data, T mem_mask = ~T(0));
|
||||||
bool fetch(u32 address, std::function<void(u32)> &&apply);
|
void fetch(u32 address, std::function<void(u32)> &&apply);
|
||||||
|
|
||||||
|
// cache
|
||||||
|
template <typename T> unsigned shift_factor(u32 address) const;
|
||||||
|
struct cache
|
||||||
|
{
|
||||||
|
cache(size_t size)
|
||||||
|
: size(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
struct line
|
||||||
|
{
|
||||||
|
enum tag_mask : u32
|
||||||
|
{
|
||||||
|
INV = 0x0000'0001, // cache line invalid
|
||||||
|
};
|
||||||
|
|
||||||
|
void invalidate() { tag = INV; }
|
||||||
|
void update(u32 data, u32 mask = 0xffff'ffffU)
|
||||||
|
{
|
||||||
|
this->tag &= ~INV;
|
||||||
|
this->data = (this->data & ~mask) | (data & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 tag;
|
||||||
|
u32 data;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t lines() const { return size / 4; }
|
||||||
|
void start() { line = std::make_unique<struct line[]>(lines()); }
|
||||||
|
|
||||||
|
size_t const size;
|
||||||
|
std::unique_ptr<struct line[]> line;
|
||||||
|
};
|
||||||
|
std::tuple<struct cache::line &, bool> cache_lookup(u32 address, bool invalidate, bool icache = false);
|
||||||
|
|
||||||
// debug helpers
|
// debug helpers
|
||||||
std::string debug_string(u32 string_pointer, unsigned const limit = 0);
|
std::string debug_string(u32 string_pointer, unsigned const limit = 0);
|
||||||
@ -206,10 +106,6 @@ protected:
|
|||||||
// address spaces
|
// address spaces
|
||||||
address_space_config const m_program_config_be;
|
address_space_config const m_program_config_be;
|
||||||
address_space_config const m_program_config_le;
|
address_space_config const m_program_config_le;
|
||||||
address_space_config const m_icache_config;
|
|
||||||
address_space_config const m_dcache_config;
|
|
||||||
|
|
||||||
int m_data_spacenum;
|
|
||||||
|
|
||||||
// configuration
|
// configuration
|
||||||
u32 const m_cpurev;
|
u32 const m_cpurev;
|
||||||
@ -237,8 +133,9 @@ protected:
|
|||||||
u32 m_branch_target;
|
u32 m_branch_target;
|
||||||
|
|
||||||
// cache memory
|
// cache memory
|
||||||
size_t const m_icache_size;
|
struct cache m_icache;
|
||||||
size_t const m_dcache_size;
|
struct cache m_dcache;
|
||||||
|
translate_result const m_cache;
|
||||||
|
|
||||||
// I/O
|
// I/O
|
||||||
devcb_read_line::array<4> m_in_brcond;
|
devcb_read_line::array<4> m_in_brcond;
|
||||||
@ -265,41 +162,11 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
mips1_device_base(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 cpurev, size_t icache_size, size_t dcache_size);
|
||||||
|
|
||||||
enum cp1_fcr31_mask : u32
|
|
||||||
{
|
|
||||||
FCR31_RM = 0x00000003, // rounding mode
|
|
||||||
|
|
||||||
FCR31_FI = 0x00000004, // inexact operation flag
|
|
||||||
FCR31_FU = 0x00000008, // underflow flag
|
|
||||||
FCR31_FO = 0x00000010, // overflow flag
|
|
||||||
FCR31_FZ = 0x00000020, // divide by zero flag
|
|
||||||
FCR31_FV = 0x00000040, // invalid operation flag
|
|
||||||
|
|
||||||
FCR31_EI = 0x00000080, // inexact operation enable
|
|
||||||
FCR31_EU = 0x00000100, // underflow enable
|
|
||||||
FCR31_EO = 0x00000200, // overflow enable
|
|
||||||
FCR31_EZ = 0x00000400, // divide by zero enable
|
|
||||||
FCR31_EV = 0x00000800, // invalid operation enable
|
|
||||||
|
|
||||||
FCR31_CI = 0x00001000, // inexact operation cause
|
|
||||||
FCR31_CU = 0x00002000, // underflow cause
|
|
||||||
FCR31_CO = 0x00004000, // overflow cause
|
|
||||||
FCR31_CZ = 0x00008000, // divide by zero cause
|
|
||||||
FCR31_CV = 0x00010000, // invalid operation cause
|
|
||||||
FCR31_CE = 0x00020000, // unimplemented operation cause
|
|
||||||
|
|
||||||
FCR31_C = 0x00800000, // condition
|
|
||||||
|
|
||||||
FCR31_FM = 0x0000007c, // flag mask
|
|
||||||
FCR31_EM = 0x00000f80, // enable mask
|
|
||||||
FCR31_CM = 0x0001f000, // cause mask (except unimplemented)
|
|
||||||
};
|
|
||||||
|
|
||||||
// device_t implementation
|
// device_t implementation
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
|
||||||
virtual bool translate(int intention, offs_t &address, bool debug) override;
|
virtual translate_result translate(int intention, offs_t &address, bool debug) override;
|
||||||
|
|
||||||
virtual void handle_cop0(u32 const op) override;
|
virtual void handle_cop0(u32 const op) override;
|
||||||
virtual u32 get_cop0_reg(unsigned const reg) override;
|
virtual u32 get_cop0_reg(unsigned const reg) override;
|
||||||
|
@ -38,11 +38,11 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
seeq8003_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock = 0);
|
seeq8003_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock = 0);
|
||||||
|
|
||||||
// device_t overrides
|
// device_t implementation
|
||||||
virtual void device_start() override;
|
virtual void device_start() override;
|
||||||
virtual void device_reset() override;
|
virtual void device_reset() override;
|
||||||
|
|
||||||
// device_network_interface overrides
|
// device_network_interface implementation
|
||||||
virtual int recv_start_cb(u8 *buf, int length) override;
|
virtual int recv_start_cb(u8 *buf, int length) override;
|
||||||
|
|
||||||
// register read handlers
|
// register read handlers
|
||||||
|
@ -180,20 +180,20 @@
|
|||||||
* Keyboard controller output port
|
* Keyboard controller output port
|
||||||
* 4: select 1M/4M SIMMs?
|
* 4: select 1M/4M SIMMs?
|
||||||
*
|
*
|
||||||
|
* rs3230 -window -nomax -ui_active -tty1 terminal -numscreens 2
|
||||||
* PON failures
|
* PON failures
|
||||||
* kseg0/kseg1 cache
|
* instruction cache functionality (failed)
|
||||||
* instruction cache functionality (skipped)
|
|
||||||
* instruction cache mats+ (skipped)
|
* instruction cache mats+ (skipped)
|
||||||
* data cache block refill
|
* data cache block refill (failed)
|
||||||
* instruction cache block refill (skipped)
|
* instruction cache block refill (skipped)
|
||||||
* scc - requires z80scc zero count interrupt
|
* id prom (failed)
|
||||||
* tod - loop <1 second real time?
|
* tod - loop <1 second real time?
|
||||||
* color frame buffer (skipped)
|
* color frame buffer (skipped)
|
||||||
* dma controller chip
|
* dma controller chip
|
||||||
* scsi controller chip
|
* scsi controller chip
|
||||||
* tlb (skipped) - all pass except tlb_n (requires cpu data cache)
|
* tlb (skipped) - all pass except tlb_n (requires cpu data cache)
|
||||||
* exception (skipped)
|
* exception (skipped)
|
||||||
* parity
|
* parity (failed)
|
||||||
* dma parity (skipped)
|
* dma parity (skipped)
|
||||||
* at serial board (skipped)
|
* at serial board (skipped)
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user