diff options
Diffstat (limited to 'src/devices/cpu/mips/r4000.h')
-rw-r--r-- | src/devices/cpu/mips/r4000.h | 152 |
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 |