summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mips/r4000.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mips/r4000.cpp')
-rw-r--r--src/devices/cpu/mips/r4000.cpp240
1 files changed, 171 insertions, 69 deletions
diff --git a/src/devices/cpu/mips/r4000.cpp b/src/devices/cpu/mips/r4000.cpp
index 1cf885379cc..15f161b32c3 100644
--- a/src/devices/cpu/mips/r4000.cpp
+++ b/src/devices/cpu/mips/r4000.cpp
@@ -55,6 +55,8 @@
// experimental primary instruction cache
#define ICACHE 0
+#define SCACHE !(m_cp0[CP0_Config] & CONFIG_SC)
+
#include "logmacro.h"
#define USE_ABI_REG_NAMES 1
@@ -197,6 +199,9 @@ void r4000_base_device::device_start()
m_icache_data = std::make_unique<u32 []>((0x1000U << config_ic) >> 2);
R4000_ENDIAN_LE_BE(accessors(m_le), accessors(m_be));
+
+ if (SCACHE)
+ save_pointer(NAME(m_scache_tag), m_scache_tag_size);
}
void r4000_base_device::device_reset()
@@ -945,75 +950,7 @@ void r4000_base_device::cpu_execute(u32 const op)
cpu_swr(op);
break;
case 0x2f: // CACHE
- if ((SR & SR_KSU) && !(SR & SR_CU0) && !(SR & (SR_EXL | SR_ERL)))
- {
- cpu_exception(EXCEPTION_CP0);
- break;
- }
-
- switch ((op >> 16) & 0x1f)
- {
- case 0x00: // index invalidate (I)
- if (ICACHE)
- {
- m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] &= ~ICACHE_V;
- break;
- }
- [[fallthrough]];
- case 0x04: // index load tag (I)
- if (ICACHE)
- {
- u32 const tag = m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift];
-
- m_cp0[CP0_TagLo] = ((tag & ICACHE_PTAG) << 8) | ((tag & ICACHE_V) >> 18) | ((tag & ICACHE_P) >> 25);
- m_cp0[CP0_ECC] = 0; // data ecc or parity
-
- break;
- }
- [[fallthrough]];
- case 0x08: // index store tag (I)
- if (ICACHE)
- {
- // FIXME: compute parity
- m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] =
- (m_cp0[CP0_TagLo] & TAGLO_PTAGLO) >> 8 | (m_cp0[CP0_TagLo] & TAGLO_PSTATE) << 18;
-
- break;
- }
- [[fallthrough]];
- case 0x01: // index writeback invalidate (D)
- case 0x02: // index invalidate (SI)
- case 0x03: // index writeback invalidate (SD)
-
- case 0x05: // index load tag (D)
- case 0x06: // index load tag (SI)
- case 0x07: // index load tag (SI)
-
- case 0x09: // index store tag (D)
- case 0x0a: // index store tag (SI)
- case 0x0b: // index store tag (SD)
-
- case 0x0d: // create dirty exclusive (D)
- case 0x0f: // create dirty exclusive (SD)
-
- case 0x10: // hit invalidate (I)
- case 0x11: // hit invalidate (D)
- case 0x12: // hit invalidate (SI)
- case 0x13: // hit invalidate (SD)
-
- case 0x14: // fill (I)
- case 0x15: // hit writeback invalidate (D)
- case 0x17: // hit writeback invalidate (SD)
-
- case 0x18: // hit writeback (I)
- case 0x19: // hit writeback (D)
- case 0x1b: // hit writeback (SD)
-
- case 0x1e: // hit set virtual (SI)
- case 0x1f: // hit set virtual (SD)
- //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
- break;
- }
+ cp0_cache(op);
break;
case 0x30: // LL
load_linked<u32>(ADDR(m_r[RSREG], s16(op)),
@@ -1263,6 +1200,128 @@ void r4000_base_device::cpu_sdr(u32 const op)
store<u64, false>(offset, m_r[RTREG] << shift, ~u64(0) << shift);
}
+void r4000_base_device::cp0_cache(u32 const op)
+{
+ if ((SR & SR_KSU) && !(SR & SR_CU0) && !(SR & (SR_EXL | SR_ERL)))
+ {
+ cpu_exception(EXCEPTION_CP0);
+ return;
+ }
+
+ switch ((op >> 16) & 0x1f)
+ {
+ case 0x00: // index invalidate (I)
+ if (ICACHE)
+ {
+ m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] &= ~ICACHE_V;
+ break;
+ }
+ [[fallthrough]];
+ case 0x04: // index load tag (I)
+ if (ICACHE)
+ {
+ u32 const tag = m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift];
+
+ m_cp0[CP0_TagLo] = ((tag & ICACHE_PTAG) << 8) | ((tag & ICACHE_V) >> 18) | ((tag & ICACHE_P) >> 25);
+ m_cp0[CP0_ECC] = 0; // data ecc or parity
+
+ break;
+ }
+ [[fallthrough]];
+ case 0x08: // index store tag (I)
+ if (ICACHE)
+ {
+ // FIXME: compute parity
+ m_icache_tag[(ADDR(m_r[RSREG], s16(op)) & m_icache_mask_hi) >> m_icache_shift] =
+ (m_cp0[CP0_TagLo] & TAGLO_PTAGLO) >> 8 | (m_cp0[CP0_TagLo] & TAGLO_PSTATE) << 18;
+ break;
+ }
+ [[fallthrough]];
+ case 0x01: // index writeback invalidate (D)
+ case 0x02: // index invalidate (SI)
+ case 0x03: // index writeback invalidate (SD)
+ case 0x05: // index load tag (D)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ case 0x06: // index load tag (SI)
+ case 0x07: // index load tag (SD)
+ if (SCACHE)
+ {
+ // TODO: translation type for CACHE instruction? Read seems reasonable since only the tag is changing here
+ u64 physical_address = ADDR(m_r[RSREG], s16(op));
+ translate_result const t = translate(TRANSLATE_READ, physical_address);
+ if (t == ERROR || t == MISS)
+ return;
+
+ u32 const index = (physical_address & m_scache_tag_mask) >> m_scache_line_index;
+ if (index < m_scache_tag_size)
+ {
+ // TODO: Load the ECC register here
+ u32 const tag = m_scache_tag[index];
+ u32 const cs = (tag & SCACHE_CS) >> 22;
+ u32 const stag = tag & SCACHE_STAG;
+ u32 const pidx = (tag & SCACHE_PIDX) >> 19;
+ m_cp0[CP0_TagLo] = (stag << 13) | (cs << 10) | (pidx << 7);
+ }
+ else
+ fatalerror("r4000 scache load tag index out of range!");
+ }
+ else
+ LOGMASKED(LOG_CACHE, "cache 0x%08x called without scache enabled (%s)\n", op, machine().describe_context());
+ break;
+ case 0x09: // index store tag (D)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ case 0x0a: // index store tag (SI)
+ case 0x0b: // index store tag (SD)
+ if (SCACHE)
+ {
+ // TODO: translation type for CACHE instruction? Read seems reasonable since only the tag is changing here
+ u64 const virtual_address = ADDR(m_r[RSREG], s16(op));
+ u64 physical_address = virtual_address;
+ translate_result const t = translate(TRANSLATE_READ, physical_address);
+ if (t == ERROR || t == MISS)
+ return;
+
+ u64 const index = (physical_address & m_scache_tag_mask) >> m_scache_line_index;
+ if (index < m_scache_tag_size)
+ {
+ // TODO: Calculate ECC bits here
+ u64 const tag_lo = m_cp0[CP0_TagLo];
+ u32 const cs = (tag_lo & TAGLO_CS) >> 10;
+ u32 const stag = (tag_lo & TAGLO_STAG) >> 13;
+ u32 const pidx = (virtual_address & 0x7000) >> 12;
+ m_scache_tag[index] = cs << 22 | pidx << 19 | stag;
+ }
+ else
+ fatalerror("r4000 scache store tag index out of range!");
+ }
+ else
+ LOGMASKED(LOG_CACHE, "cache 0x%08x called without scache enabled (%s)\n", op, machine().describe_context());
+ break;
+ case 0x0d: // create dirty exclusive (D)
+ case 0x0f: // create dirty exclusive (SD)
+
+ case 0x10: // hit invalidate (I)
+ case 0x11: // hit invalidate (D)
+ case 0x12: // hit invalidate (SI)
+ case 0x13: // hit invalidate (SD)
+
+ case 0x14: // fill (I)
+ case 0x15: // hit writeback invalidate (D)
+ case 0x17: // hit writeback invalidate (SD)
+
+ case 0x18: // hit writeback (I)
+ case 0x19: // hit writeback (D)
+ case 0x1b: // hit writeback (SD)
+
+ case 0x1e: // hit set virtual (SI)
+ case 0x1f: // hit set virtual (SD)
+ //LOGMASKED(LOG_CACHE, "cache 0x%08x unimplemented (%s)\n", op, machine().describe_context());
+ break;
+ }
+}
+
void r4000_base_device::cp0_execute(u32 const op)
{
if ((SR & SR_KSU) && !(SR & SR_CU0) && !(SR & (SR_EXL | SR_ERL)))
@@ -4021,3 +4080,46 @@ std::string r4000_base_device::debug_unicode_string(u64 unicode_string_pointer)
return utf8_from_wstring(result);
}
+
+void r4000_base_device::configure_scache()
+{
+ if (m_scache_size > 0)
+ {
+ /*
+ * Secondary cache tag size depends on the cache line size
+ * (how many bytes are transferred with one cache operation) and the
+ * size of the cache itself.
+ * For example, the Sony NEWS NWS-5000X has a 1MB secondary cache
+ * and a cache line size of 16 words. So, the slice of the physical
+ * address used to index into the cache is bits 19:6.
+ * See chapter 11 of the R4000 user manual for more details.
+ */
+ if (m_scache_line_size == 0)
+ fatalerror("SCACHE size set but line size was not set!");
+
+ if (m_scache_line_size <= 0x10)
+ m_scache_line_index = 4;
+ else if (m_scache_line_size <= 0x20)
+ {
+ m_scache_line_index = 5;
+ m_cp0[CP0_Config] |= 1 << 22;
+ }
+ else if (m_scache_line_size <= 0x40)
+ {
+ m_scache_line_index = 6;
+ m_cp0[CP0_Config] |= 2 << 22;
+ }
+ else
+ {
+ m_scache_line_index = 7;
+ m_cp0[CP0_Config] |= 3 << 22;
+ }
+
+ m_scache_tag_size = m_scache_size >> m_scache_line_index;
+ m_scache_tag_mask = m_scache_size - 1;
+
+ m_scache_tag = std::make_unique<u32[]>(m_scache_tag_size);
+ }
+ else
+ m_cp0[CP0_Config] |= CONFIG_SC;
+}