summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu/mips/r4000.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/cpu/mips/r4000.h')
-rw-r--r--src/devices/cpu/mips/r4000.h152
1 files changed, 120 insertions, 32 deletions
diff --git a/src/devices/cpu/mips/r4000.h b/src/devices/cpu/mips/r4000.h
index 2430812919c..a6e0f816d9a 100644
--- a/src/devices/cpu/mips/r4000.h
+++ b/src/devices/cpu/mips/r4000.h
@@ -9,6 +9,7 @@
DECLARE_DEVICE_TYPE(R4000, r4000_device)
DECLARE_DEVICE_TYPE(R4400, r4400_device)
DECLARE_DEVICE_TYPE(R4600, r4600_device)
+DECLARE_DEVICE_TYPE(R5000, r5000_device)
class r4000_base_device : public cpu_device
{
@@ -16,7 +17,7 @@ public:
enum config_mask : u32
{
CONFIG_K0 = 0x00000007, // kseg0 cache coherency
- CONFIG_CU = 0x00000080, // store conditional cache coherent
+ CONFIG_CU = 0x00000008, // store conditional cache coherent
CONFIG_DB = 0x00000010, // primary d-cache line 32 bytes
CONFIG_IB = 0x00000020, // primary i-cache line 32 bytes
CONFIG_DC = 0x000001c0, // primary d-cache size
@@ -45,7 +46,7 @@ public:
void bus_error() { m_bus_error = true; }
protected:
- enum cache_size_t
+ enum cache_size
{
CACHE_4K = 0,
CACHE_8K = 1,
@@ -56,7 +57,7 @@ protected:
CACHE_256K = 6,
CACHE_512K = 7,
};
- r4000_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size_t icache_size, cache_size_t dcache_size);
+ r4000_base_device(machine_config const &mconfig, device_type type, char const *tag, device_t *owner, u32 clock, u32 prid, u32 fcr, cache_size icache_size, cache_size dcache_size, unsigned m32, unsigned m64, unsigned d32, unsigned d64, bool timer_interrupt_disabled);
enum cp0_reg : int
{
@@ -290,6 +291,8 @@ protected:
TAGLO_PTAGLO = 0xffffff00, // physical adddress bits 35:12
TAGLO_PSTATE = 0x000000c0, // primary cache state
TAGLO_P = 0x00000001, // primary tag even parity
+ TAGLO_CS = 0x00001c00, // scache status
+ TAGLO_STAG = 0xffffe000, // scache tag
};
enum icache_mask : u32
{
@@ -305,27 +308,35 @@ protected:
DCACHE_W = 0x02000000, // write-back
DCACHE_WP = 0x02000000, // even parity for write-back
};
+ enum scache_mask : u32
+ {
+ SCACHE_CS = 0x01c00000, // cache state
+ SCACHE_STAG = 0x0007ffff, // physical tag
+ SCACHE_PIDX = 0x00380000, // primary cache index
+ };
// device_t overrides
- virtual void device_start() override;
- virtual void device_reset() override;
- virtual void device_stop() override;
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_stop() override ATTR_COLD;
// device_memory_interface overrides
virtual space_config_vector memory_space_config() const override;
- virtual bool memory_translate(int spacenum, int intention, offs_t &address) override;
+ virtual bool memory_translate(int spacenum, int intention, offs_t &address, address_space *&target_space) override;
// device_disasm_interface overrides
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
// device_execute_interface overrides
- virtual u32 execute_min_cycles() const override { return 1; }
- virtual u32 execute_max_cycles() const override { return 40; }
- virtual u32 execute_input_lines() const override { return 6; }
+ virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks * 2); }
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles + 1) / 2; }
+ virtual u32 execute_min_cycles() const noexcept override { return 1; }
+ virtual u32 execute_max_cycles() const noexcept override { return *std::max_element(std::begin(m_hilo_cycles), std::end(m_hilo_cycles)); }
virtual void execute_run() override;
virtual void execute_set_input(int inputnum, int state) override;
// cpu implementation
+ virtual void handle_reserved_instruction(u32 const op);
void cpu_execute(u32 const op);
void cpu_exception(u32 exception, u16 const vector = 0x180);
void cpu_lwl(u32 const op);
@@ -338,6 +349,7 @@ protected:
void cpu_sdr(u32 const op);
// cp0 implementation
+ void cp0_cache(u32 const op);
void cp0_execute(u32 const op);
u64 cp0_get(unsigned const reg);
void cp0_set(unsigned const reg, u64 const data);
@@ -354,20 +366,24 @@ protected:
// cp1 implementation
void cp1_unimplemented();
template <typename T> bool cp1_op(T op);
- void cp1_execute(u32 const op);
+ virtual void cp1_execute(u32 const op);
+ virtual void cp1x_execute(u32 const op);
template <typename T> void cp1_set(unsigned const reg, T const data);
+ void cp1_mov_s(u32 const op);
+ void cp1_mov_d(u32 const op);
// cp2 implementation
void cp2_execute(u32 const op);
// address and memory handling
- enum translate_t { ERROR, MISS, UNCACHED, CACHED };
- translate_t translate(int intention, u64 &address);
+ enum translate_result : unsigned { ERROR, MISS, UNCACHED, CACHED };
+ translate_result translate(int intention, bool debug, u64 &address);
void address_error(int intention, u64 const address);
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(u64 program_address, U &&apply);
+ template <typename T> void accessors(T &m);
+ template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(u64 program_address, U &&apply);
template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(u64, T)>>::value, bool> load_linked(u64 program_address, U &&apply);
- template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(u64 program_address, U data, T mem_mask = ~T(0));
+ template <typename T, bool Aligned = true, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(u64 program_address, U data, T mem_mask = ~T(0));
bool fetch(u64 address, std::function<void(u32)> &&apply);
// debugging helpers
@@ -375,36 +391,60 @@ protected:
std::string debug_string_array(u64 array_pointer);
std::string debug_unicode_string(u64 unicode_string_pointer);
+ // configuration helpers
+ void configure_scache();
+
// device configuration state
address_space_config m_program_config_le;
address_space_config m_program_config_be;
+ // memory access helpers
+ memory_access<32, 3, 0, ENDIANNESS_LITTLE>::specific m_le;
+ memory_access<32, 3, 0, ENDIANNESS_BIG>::specific m_be;
+
+ std::function<u8(offs_t offset)> read_byte;
+ std::function<u16(offs_t offset)> read_word;
+ std::function<u32(offs_t offset)> read_dword;
+ std::function<u64(offs_t offset)> read_qword;
+ std::function<void(offs_t offset, u8 data)> write_byte;
+ std::function<void(offs_t offset, u16 data, u16 mem_mask)> write_word;
+ std::function<void(offs_t offset, u32 data, u32 mem_mask)> write_dword;
+ std::function<void(offs_t offset, u64 data, u64 mem_mask)> write_qword;
+
+ enum branch_state : u64
+ {
+ STATE = 0x00000000'00000003,
+ TARGET = 0xffffffff'fffffffc,
+
+ NONE = 0,
+ BRANCH = 1, // retire delayed branch
+ DELAY = 2, // delay slot instruction
+ NULLIFY = 3, // next instruction nullified
+ };
+
// runtime state
int m_icount;
+ // integer multiple/divide state
+ unsigned const m_hilo_cycles[4];
+ unsigned m_hilo_delay;
+
// cpu state
u64 m_pc;
u64 m_r[32];
u64 m_hi;
u64 m_lo;
- enum branch_state_t : unsigned
- {
- NONE = 0,
- DELAY = 1, // delay slot instruction active
- BRANCH = 2, // branch instruction active
- EXCEPTION = 3, // exception triggered
- NULLIFY = 4, // next instruction nullified
- }
- m_branch_state;
- u64 m_branch_target;
+ u64 m_branch_state;
// cp0 state
u64 m_cp0[32];
u64 m_cp0_timer_zero;
emu_timer *m_cp0_timer;
+ bool m_hard_reset;
bool m_ll_active;
bool m_bus_error;
- struct tlb_entry_t
+ bool m_timer_interrupt_disabled;
+ struct tlb_entry
{
u64 mask;
u64 vpn;
@@ -429,6 +469,14 @@ protected:
std::unique_ptr<u32[]> m_icache_tag;
std::unique_ptr<u32[]> m_icache_data;
+ // experimental scache state
+ u32 m_scache_size; // Size in bytes
+ u8 m_scache_line_size;
+ u32 m_scache_line_index; // Secondary cache line shift
+ u32 m_scache_tag_mask; // Mask for extracting the tag from a physical address
+ u32 m_scache_tag_size;
+ std::unique_ptr<u32[]> m_scache_tag;
+
// statistics
u64 m_tlb_scans;
u64 m_tlb_loops;
@@ -440,33 +488,73 @@ class r4000_device : public r4000_base_device
{
public:
// NOTE: R4000 chips prior to 3.0 have an xtlb bug
- r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K)
+ r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R4000, tag, owner, clock, 0x0430, 0x0500, CACHE_8K, CACHE_8K, 10, 20, 69, 133, timer_interrupt_disabled)
{
// no secondary cache
m_cp0[CP0_Config] |= CONFIG_SC;
}
+
+ r4000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : r4000_device(mconfig, tag, owner, clock, false)
+ {
+ }
};
class r4400_device : public r4000_base_device
{
public:
+ r4400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled, u32 scache_size, u8 scache_line_size)
+ : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K, 10, 20, 69, 133, timer_interrupt_disabled)
+ {
+ m_scache_size = scache_size;
+ m_scache_line_size = scache_line_size;
+ configure_scache();
+ }
+
r4400_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4400, tag, owner, clock, 0x0440, 0x0500, CACHE_16K, CACHE_16K)
+ : r4400_device(mconfig, tag, owner, clock, false, 0, 0)
{
- // no secondary cache
- m_cp0[CP0_Config] |= CONFIG_SC;
}
};
class r4600_device : public r4000_base_device
{
public:
+ r4600_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K, 10, 12, 42, 74, timer_interrupt_disabled)
+ {
+ // no secondary cache
+ m_cp0[CP0_Config] |= CONFIG_SC;
+ }
+
r4600_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
- : r4000_base_device(mconfig, R4600, tag, owner, clock, 0x2020, 0x2020, CACHE_16K, CACHE_16K)
+ : r4600_device(mconfig, tag, owner, clock, false)
+ {
+ }
+};
+
+class r5000_device : public r4000_base_device
+{
+public:
+ r5000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock, bool timer_interrupt_disabled)
+ : r4000_base_device(mconfig, R5000, tag, owner, clock, 0x2320, 0x2320, CACHE_32K, CACHE_32K, 5, 9, 36, 68, timer_interrupt_disabled)
{
// no secondary cache
m_cp0[CP0_Config] |= CONFIG_SC;
}
+
+ r5000_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
+ : r5000_device(mconfig, tag, owner, clock, false)
+ {
+ }
+
+private:
+ virtual void handle_reserved_instruction(u32 const op) override;
+ virtual void cp1_execute(u32 const op) override;
+ virtual void cp1x_execute(u32 const op) override;
+
+ static u32 const s_fcc_masks[8];
+ static u32 const s_fcc_shifts[8];
};
#endif // MAME_CPU_MIPS_R4000_H