summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/machine/cammu.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/machine/cammu.h')
-rw-r--r--src/devices/machine/cammu.h665
1 files changed, 665 insertions, 0 deletions
diff --git a/src/devices/machine/cammu.h b/src/devices/machine/cammu.h
new file mode 100644
index 00000000000..2f0760ddfa1
--- /dev/null
+++ b/src/devices/machine/cammu.h
@@ -0,0 +1,665 @@
+// license:BSD-3-Clause
+// copyright-holders:Patrick Mackinlay
+
+#ifndef MAME_MACHINE_CAMMU_H
+#define MAME_MACHINE_CAMMU_H
+
+#pragma once
+
+#include "cpu/clipper/common.h"
+
+class cammu_device : public device_t
+{
+public:
+ auto exception_callback() { return m_exception_func.bind(); }
+
+ static const u32 CAMMU_PAGE_SIZE = 0x1000;
+ static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1);
+
+ enum pdo_mask : u32
+ {
+ PDO_MASK = 0xfffff000
+ };
+
+ enum ptde_mask : u32
+ {
+ PTDE_F = 0x00000001, // page fault
+ PTDE_PTO = 0xfffff000 // page table origin
+ };
+
+ enum pte_mask : u32
+ {
+ PTE_F = 0x00000001, // page fault
+ PTE_R = 0x00000002, // referenced flag
+ PTE_D = 0x00000004, // dirty flag
+ PTE_PL = 0x00000078, // protection level
+ PTE_S = 0x00000180, // system reserved
+ PTE_ST = 0x00000e00, // system tag
+ PTE_RA = 0xfffff000, // real address
+
+ PTE_CW = 0x00000040, // copy on write (c400)
+ PTE_NDREF = 0x00000080, // secondary reference (software) / copy on write (fault)?
+ PTE_LOCK = 0x00000100 // page lock (software)
+ };
+
+ static constexpr int PL_SHIFT = 3;
+ static constexpr int ST_SHIFT = 9;
+
+ enum va_mask : u32
+ {
+ VA_POFS = 0x00000fff, // page offset
+ VA_PTI = 0x003ff000, // page table index
+ VA_PTDI = 0xffc00000 // page table directory index
+ };
+
+ enum system_tag_t : u8
+ {
+ ST0 = 0, // private, write-through, main memory space
+ ST1 = 1, // shared, write-through, main memory space
+ ST2 = 2, // private, copy-back, main memory space
+ ST3 = 3, // noncacheable, main memory space
+ ST4 = 4, // noncacheable, i/o space
+ ST5 = 5, // noncacheable, boot space
+ ST6 = 6, // cache purge
+ ST7 = 7 // slave i/o
+ };
+
+ void set_spaces(address_space &main_space, address_space &io_space, address_space &boot_space);
+
+ // translation lookaside buffer and register access
+ virtual u32 cammu_r(const u32 address) = 0;
+ virtual void cammu_w(const u32 address, const u32 data) = 0;
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> load(const u32 ssw, const u32 address, U &&apply)
+ {
+ // check for cammu access
+ if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800))
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 1: apply(T(t.cache->read_byte(t.address))); break;
+ case 2: apply(T(t.cache->read_word(t.address))); break;
+ case 4: apply(T(t.cache->read_dword(t.address))); break;
+ case 8: apply(T(t.cache->read_qword(t.address))); break;
+ default:
+ fatalerror("unhandled load 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+ }
+ else if (sizeof(T) == 4)
+ apply(cammu_r(address));
+ else
+ fatalerror("unhandled cammu load 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, T>::value, bool> store(const u32 ssw, const u32 address, U data)
+ {
+ // check for cammu access
+ if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800))
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 1: t.cache->write_byte(t.address, T(data)); break;
+ case 2: t.cache->write_word(t.address, T(data)); break;
+ case 4: t.cache->write_dword(t.address, T(data)); break;
+ case 8: t.cache->write_qword(t.address, T(data)); break;
+ default:
+ fatalerror("unhandled store 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+ }
+ else if (sizeof(T) == 4)
+ cammu_w(address, data);
+ else
+ fatalerror("unhandled cammu store 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<T(T)>>::value, bool> modify(const u32 ssw, const u32 address, U &&apply)
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), access_type(READ | WRITE));
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 4: t.cache->write_dword(t.address, apply(T(t.cache->read_dword(t.address)))); break;
+ default:
+ fatalerror("unhandled modify 0x%08x size %d (%s)",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+
+ return true;
+ }
+
+ template <typename T, typename U> std::enable_if_t<std::is_convertible<U, std::function<void(T)>>::value, bool> fetch(const u32 ssw, const u32 address, U &&apply)
+ {
+ translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE);
+
+ if (!t.cache)
+ return false;
+
+ switch (sizeof(T))
+ {
+ case 2: apply(T(t.cache->read_word(t.address))); break;
+ case 4:
+ {
+ // check for unaligned access
+ if (address & 0x2)
+ {
+ // check for page span
+ if ((address & CAMMU_PAGE_MASK) == (CAMMU_PAGE_SIZE - 2))
+ {
+ translated_t u = translate_address(ssw, address + 2, access_size(sizeof(u16)), EXECUTE);
+ if (u.cache)
+ {
+ const u16 lsw = t.cache->read_word(t.address);
+ const u16 msw = t.cache->read_word(u.address);
+
+ apply((T(msw) << 16) | lsw);
+ }
+ else
+ return false;
+ }
+ else
+ apply(T(t.cache->read_dword_unaligned(t.address)));
+ }
+ else
+ apply(T(t.cache->read_dword(t.address)));
+ }
+ break;
+ default:
+ fatalerror("unhandled fetch 0x%08x size %d (%s)\n",
+ address, access_size(sizeof(T)), machine().describe_context().c_str());
+ }
+
+ return true;
+ }
+
+ // address translation for debugger
+ bool memory_translate(const u32 ssw, const int spacenum, const int intention, offs_t &address, address_space *&target_space);
+
+protected:
+ cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ // device-level overrides
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+
+ enum access_size : u8
+ {
+ BYTE = 1,
+ WORD = 2,
+ DWORD = 4,
+ QWORD = 8
+ };
+
+ enum access_type : u8
+ {
+ READ = 1,
+ WRITE = 2,
+ EXECUTE = 4,
+
+ // matrix abbreviations and combinations
+ N = 0,
+ R = READ,
+ W = WRITE,
+ RW = READ | WRITE,
+ RE = READ | EXECUTE,
+ RWE = READ | WRITE | EXECUTE,
+ };
+
+ struct translated_t
+ {
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache *const cache;
+ const u32 address;
+ };
+
+ struct pte_t
+ {
+ u32 entry;
+ u32 address;
+ };
+
+ struct memory_t
+ {
+ address_space *space = nullptr;
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache;
+ };
+
+ // address translation
+ virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode);
+ pte_t get_pte(const u32 va, const bool user);
+
+ // helpers
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0;
+ virtual bool get_alignment() const = 0;
+ virtual u32 get_pdo(const bool user) const = 0;
+ virtual system_tag_t get_ust_space() const = 0;
+ virtual void set_fault(const u32 address, const exception_vector type) = 0;
+
+ // device state
+ devcb_write16 m_exception_func;
+ memory_t m_memory[8];
+};
+
+class cammu_c4_device : public cammu_device
+{
+public:
+ // TODO: translation lookaside buffer and register access
+ virtual void map(address_map &map) = 0;
+ virtual u32 cammu_r(const u32 address) override { return 0; }
+ virtual void cammu_w(const u32 address, const u32 data) override {}
+
+ void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; }
+
+ u32 s_pdo_r() { return m_s_pdo; }
+ void s_pdo_w(offs_t offset, u32 data, u32 mem_mask = ~0) { m_s_pdo = ((m_s_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
+ u32 u_pdo_r() { return m_u_pdo; }
+ void u_pdo_w(offs_t offset, u32 data, u32 mem_mask = ~0) { m_u_pdo = ((m_u_pdo & ~mem_mask) | (data & mem_mask)) & PDO_MASK; }
+
+ virtual u32 control_r() = 0;
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask = ~0) = 0;
+
+ u32 i_fault_r() { return m_i_fault; }
+ void i_fault_w(u32 data) { m_i_fault = data; }
+ u32 fault_address_1_r() { return m_fault_address_1; }
+ void fault_address_1_w(u32 data) { m_fault_address_1 = data; }
+ u32 fault_address_2_r() { return m_fault_address_2; }
+ void fault_address_2_w(u32 data) { m_fault_address_2 = data; }
+ u32 fault_data_1_lo_r() { return m_fault_data_1_lo; }
+ void fault_data_1_lo_w(u32 data) { m_fault_data_1_lo = data; }
+ u32 fault_data_1_hi_r() { return m_fault_data_1_hi; }
+ void fault_data_1_hi_w(u32 data) { m_fault_data_1_hi = data; }
+ u32 fault_data_2_lo_r() { return m_fault_data_2_lo; }
+ void fault_data_2_lo_w(u32 data) { m_fault_data_2_lo = data; }
+ u32 fault_data_2_hi_r() { return m_fault_data_2_hi; }
+ void fault_data_2_hi_w(u32 data) { m_fault_data_2_hi = data; }
+
+protected:
+ cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void device_start() override ATTR_COLD;
+
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
+ virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
+
+ virtual void set_fault(const u32 address, const exception_vector type) override { m_fault_address_1 = address; m_exception_func(type); }
+
+ u32 m_s_pdo;
+ u32 m_u_pdo;
+ u32 m_control;
+
+ u32 m_i_fault;
+ u32 m_fault_address_1;
+ u32 m_fault_address_2;
+ u32 m_fault_data_1_lo;
+ u32 m_fault_data_1_hi;
+ u32 m_fault_data_2_lo;
+ u32 m_fault_data_2_hi;
+};
+
+class cammu_c4t_device : public cammu_c4_device
+{
+public:
+ cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override ATTR_COLD;
+
+ u32 ram_line_r() { return m_ram_line; }
+ void ram_line_w(u32 data) { m_ram_line = data; }
+
+ u32 htlb_offset_r() { return m_htlb_offset; }
+ void htlb_offset_w(u32 data) { m_htlb_offset = data; }
+
+ u32 c4_bus_poll_r() { return m_c4_bus_poll; }
+ void c4_bus_poll_w(u32 data) { m_c4_bus_poll = data; }
+
+ enum control_mask : u32
+ {
+ CNTL_RUV = 0x00000001, // reset user valid
+ CNTL_RSV = 0x00000002, // reset supervisor valid
+ CNTL_DBWR = 0x00000004, // disable bus watch read
+ CNTL_ATD = 0x00000008, // alignment trap disable
+ CNTL_UST = 0x00000030, // unmapped system tag
+ CNTL_IOTS = 0x00000040, // i/o tag select
+ CNTL_UVS = 0x00000080, // user valid status
+ CNTL_PB = 0x00000100, // purge busy
+ CNTL_CICT = 0x00000200, // clear i-side cache tags
+ CNTL_CFR = 0x00000400, // clear trap registers
+ CNTL_HTLBD = 0x00000800, // htlb disable
+ CNTL_CDCT = 0x00001000, // clear d-side cache tags
+ CNTL_CID = 0xff000000 // cammu id
+ };
+
+ enum control_ust_mask : u32
+ {
+ UST_NCA = 0x00, // unmapped system tag, noncacheable
+ UST_PWT = 0x10, // unmapped system tag, write through
+ UST_PCB = 0x20, // unmapped system tag, copy back
+ UST_PGE = 0x30 // unmapped system tag, purge mode
+ };
+
+ enum control_cid_mask : u32
+ {
+ CID_C4T = 0x00000000 // unknown
+ };
+
+ virtual u32 control_r() override { return m_control; }
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask = ~0) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
+ u32 bio_control_r() { return m_bio_control; }
+ void bio_control_w(u32 data) { m_bio_control = data; }
+ u32 bio_address_tag_r() { return m_bio_address_tag; }
+ void bio_address_tag_w(u32 data) { m_bio_address_tag = data; }
+
+ u32 cache_data_lo_r() { return m_cache_data_lo; }
+ void cache_data_lo_w(u32 data) { m_cache_data_lo = data; }
+ u32 cache_data_hi_r() { return m_cache_data_hi; }
+ void cache_data_hi_w(u32 data) { m_cache_data_hi = data; }
+ u32 cache_cpu_tag_r() { return m_cache_cpu_tag; }
+ void cache_cpu_tag_w(u32 data) { m_cache_cpu_tag = data; }
+ u32 cache_system_tag_valid_r() { return m_cache_system_tag_valid; }
+ void cache_system_tag_valid_w(u32 data) { m_cache_system_tag_valid = data; }
+ u32 cache_system_tag_r() { return m_cache_system_tag; }
+ void cache_system_tag_w(u32 data) { m_cache_system_tag = data; }
+ u32 tlb_va_line_r() { return m_tlb_va_line; }
+ void tlb_va_line_w(u32 data) { m_tlb_va_line = data; }
+ u32 tlb_ra_line_r() { return m_tlb_ra_line; }
+ void tlb_ra_line_w(u32 data) { m_tlb_ra_line = data; }
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+
+ virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
+ virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); }
+
+private:
+ u32 m_ram_line;
+ u32 m_htlb_offset;
+ u32 m_c4_bus_poll;
+ u32 m_bio_control;
+ u32 m_bio_address_tag;
+
+ u32 m_cache_data_lo;
+ u32 m_cache_data_hi;
+ u32 m_cache_cpu_tag;
+ u32 m_cache_system_tag_valid;
+ u32 m_cache_system_tag;
+ u32 m_tlb_va_line;
+ u32 m_tlb_ra_line;
+};
+
+class cammu_c4i_device : public cammu_c4_device
+{
+public:
+ cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ virtual void map(address_map &map) override ATTR_COLD;
+
+ enum control_mask : u32
+ {
+ CNTL_LRAS = 0x00000001, // tlb line replacement
+ CNTL_BWWD = 0x00000002, // buswatch write disable
+ CNTL_BWRD = 0x00000004, // buswatch read disable
+ CNTL_FSR = 0x00000010, // fake system response
+ CNTL_ATD = 0x00000100, // alignment trap disable
+ CNTL_UMM = 0x00003000, // unmapped mode address space select
+ CNTL_POLL = 0x00030000, // poll bus signals
+ CNTL_BM = 0x00040000, // burst mode address space select
+ CNTL_PZBS = 0x00080000, // page 0 boot select
+ CNTL_CRR = 0x00700000, // cache memory refresh rate
+ CNTL_CID = 0xff000000 // cammu identification
+ };
+
+ enum control_umm_mask : u32
+ {
+ UMM_MM = 0x00000000, // mm space, noncacheable
+ UMM_MMRIO = 0x00001000, // mm or i/o space, noncacheable
+ UMM_IO = 0x00002000 // i/o space noncacheable
+ };
+
+ enum control_crr_mask : u32
+ {
+ CRR_GT131 = 0x00000000, // clock rate over 131 MHz
+ CRR_GT66 = 0x00100000, // clock rate over 66 MHz
+ CRR_GT33 = 0x00200000, // clock rate over 33 MHz
+ CRR_GT8 = 0x00300000, // clock rate over 8 MHz
+ CRR_GT2 = 0x00400000, // clock rate over 2 MHz
+ CRR_GT1 = 0x00500000, // clock rate over 1 MHz
+ CRR_GTHALF = 0x00600000, // clock rate over 0.5 MHz
+ CRR_OFF = 0x00700000, // refresh off
+ };
+
+ // c4i cammu identification (rev 2 and rev 3 known to have existed)
+ enum control_cid_mask : u32
+ {
+ CID_C4IR0 = 0x00000000,
+ CID_C4IR2 = 0x02000000
+ };
+
+ virtual u32 control_r() override { return m_control; }
+ virtual void control_w(offs_t offset, u32 data, u32 mem_mask) override { m_control = ((m_control & (~mem_mask | CNTL_CID)) | (data & (mem_mask & ~CNTL_CID))); }
+
+ enum reset_mask : u32
+ {
+ RESET_CDCT = 0x00000001, // clear data cache tags
+ RESET_RDUV = 0x00000100, // reset all d-side uv flags
+ RESET_RDSV = 0x00001000, // reset all d-side sv flags
+ RESET_CICT = 0x00010000, // clear ins. cache tags
+ RESET_RIUV = 0x01000000, // reset all i-side uv flags
+ RESET_RISV = 0x10000000, // reset all i-side sv flags
+ RESET_FLUSH = 0x40000000, // flush out burst io buffer
+ RESET_CFR = 0x80000000 // clear fault registers
+ };
+ u32 reset_r() { return m_reset; }
+ void reset_w(u32 data) { m_reset = data; }
+
+ u32 clr_s_data_tlb_r() { return m_clr_s_data_tlb; }
+ void clr_s_data_tlb_w(u32 data) { m_clr_s_data_tlb = data; }
+ u32 clr_u_data_tlb_r() { return m_clr_u_data_tlb; }
+ void clr_u_data_tlb_w(u32 data) { m_clr_u_data_tlb = data; }
+ u32 clr_s_insn_tlb_r() { return m_clr_s_insn_tlb; }
+ void clr_s_insn_tlb_w(u32 data) { m_clr_s_insn_tlb = data; }
+ u32 clr_u_insn_tlb_r() { return m_clr_u_insn_tlb; }
+ void clr_u_insn_tlb_w(u32 data) { m_clr_u_insn_tlb = data; }
+
+ u32 test_data_r() { return m_test_data; }
+ void test_data_w(u32 data) { m_test_data = data; }
+
+ u32 test_address_r() { return m_test_address; }
+ void test_address_w(u32 data) { m_test_address = data; }
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+
+ virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; }
+ // FIXME: don't really know how unmapped mode works on c4i
+ virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; }
+
+private:
+ u32 m_reset;
+ u32 m_clr_s_data_tlb;
+ u32 m_clr_u_data_tlb;
+ u32 m_clr_s_insn_tlb;
+ u32 m_clr_u_insn_tlb;
+ u32 m_test_data;
+ u32 m_test_address;
+};
+
+class cammu_c3_device : public cammu_device
+{
+public:
+ cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ void add_linked(cammu_c3_device *child) { m_linked.push_back(child); }
+
+protected:
+ // device-level overrides
+ virtual void device_reset() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+
+ // translation lookaside buffer and register access
+ virtual u32 cammu_r(const u32 address) override;
+ virtual void cammu_w(const u32 address, const u32 data) override;
+
+ // address translation
+ virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode) override;
+
+private:
+ enum cammu_address_mask : u32
+ {
+ CAMMU_TLB_VA = 0x00000001, // tlb va/ra select
+ CAMMU_TLB_X = 0x00000002, // tlb x/w line select
+ CAMMU_TLB_SET = 0x000000fc, // tlb set select
+ CAMMU_REG = 0x000000ff, // register select
+ CAMMU_SELECT = 0x00000700, // cammu select
+ };
+ enum tlb_ra_mask : u32
+ {
+ TLB_RA_U = 0x00000001, // used flag
+ TLB_RA_R = 0x00000002, // referenced flag
+ TLB_RA_D = 0x00000004, // dirty flag
+ TLB_RA_PL = 0x00000078, // protection level
+ TLB_RA_ST = 0x00000e00, // system tag
+ TLB_RA_RA = 0xfffff000, // real address
+ };
+ enum tlb_va_mask : u32
+ {
+ TLB_VA_UV = 0x00000002, // user valid flag
+ TLB_VA_SV = 0x00000004, // supervisor valid flag
+ TLB_VA_VA = 0xfffc0000, // virtual address tag
+ };
+
+ /*
+ * The C1/C3 CAMMU has 64-entry, two-way set associative TLB, with lines
+ * grouped into W and X compartments. The associated U flag is set to
+ * indicate that the W line of the set was most recently accessed, and
+ * cleared when the X line was most recently accessed. On TLB miss, the
+ * least recently used line as indicated by this flag is replaced.
+ *
+ * Each line consists of a real address field and a virtual address field.
+ * The real address field format is practically identical to the page table
+ * entry format.
+ */
+ struct tlb_line_t
+ {
+ u32 ra; // real address field
+ u32 va; // virtual address field
+
+ memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache;
+ };
+ struct tlb_set_t
+ {
+ tlb_line_t w;
+ tlb_line_t x;
+ bool u;
+ };
+
+ enum cammu_select_mask : u32
+ {
+ CAMMU_D_TLB = 0x000, // d-cammu tlb
+ CAMMU_D_REG = 0x100, // d-cammu register
+ CAMMU_I_TLB = 0x200, // i-cammu tlb
+ CAMMU_I_REG = 0x300, // i-cammu register
+ CAMMU_G_TLB = 0x400, // global tlb
+ CAMMU_G_REG = 0x500, // global register
+ };
+ enum cammu_register_mask : u8
+ {
+ CAMMU_REG_SPDO = 0x04, // supervisor pdo register
+ CAMMU_REG_UPDO = 0x08, // user pdo register
+ CAMMU_REG_FAULT = 0x10, // fault register
+ CAMMU_REG_CONTROL = 0x40, // control register
+ CAMMU_REG_RESET = 0x80, // reset register
+ };
+
+ enum control_mask : u32
+ {
+ CNTL_EP = 0x00000001, // enable prefetch
+ CNTL_EWCW = 0x00000002, // enable watch cpu writes
+ CNTL_EWIW = 0x00000004, // enable watch i/o writes
+ CNTL_EWIR = 0x00000008, // enable watch i/o reads
+ CNTL_UST = 0x00000030, // unmapped system tag
+ CNTL_CV = 0x00000100, // clear valid
+ CNTL_ATE = 0x00000200, // alignment trap enable
+ CNTL_CID = 0xff000000 // cammu id
+ };
+ enum control_ust_mask : u32
+ {
+ UST_0 = 0x00000000, // private, write-through, main memory space
+ UST_1 = 0x00000010, // shared, write-through, main memory space
+ UST_2 = 0x00000020, // private, copy-back, main memory space
+ UST_3 = 0x00000030 // noncacheable, main memory space
+ };
+ enum control_cid_mask : u32
+ {
+ CID_C3 = 0x00000000 // unknown
+ };
+
+ enum reset_mask : u32
+ {
+ RESET_RLVW = 0x00000001, // reset all W line LV flags in cache
+ RESET_RLVX = 0x00000002, // reset all X line LV flags in cache
+ RESET_RSV = 0x00000004, // reset all SV flags in tlb
+ RESET_RUV = 0x00000008, // reset all UV flags in tlb
+ RESET_RD = 0x00000010, // reset all D flags in tlb
+ RESET_RR = 0x00000020, // reset all R flags in tlb
+ RESET_RU = 0x00000040, // reset all U flags in cache
+ };
+
+ u32 tlb_r(const u8 address) const;
+ void tlb_w(const u8 address, const u32 data);
+ tlb_line_t &tlb_lookup(const bool user, const u32 virtual_address, const access_type mode);
+
+ u32 s_pdo_r() const { return m_s_pdo; }
+ void s_pdo_w(const u32 data) { m_s_pdo = data & PDO_MASK; }
+ u32 u_pdo_r() const { return m_u_pdo; }
+ void u_pdo_w(const u32 data) { m_u_pdo = data & PDO_MASK; }
+ u32 fault_r() const { return m_fault; }
+ void fault_w(const u32 data) { m_fault = data; }
+ u32 control_r() const { return m_control; }
+ void control_w(const u32 data) { m_control = (m_control & CNTL_CID) | (data & ~CNTL_CID); }
+ void reset_w(const u32 data);
+
+ virtual bool get_alignment() const override { return m_control & CNTL_ATE; }
+ virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); }
+ virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override;
+ virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; }
+
+ virtual void set_fault(const u32 address, const exception_vector type) override { m_fault = address; m_exception_func(type); }
+
+ static const u8 protection_matrix[4][16];
+
+ // device state
+ std::vector<cammu_c3_device *> m_linked;
+
+ u32 m_s_pdo;
+ u32 m_u_pdo;
+ u32 m_fault;
+ u32 m_control;
+
+ tlb_set_t m_tlb[64];
+};
+
+// device type definitions
+DECLARE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device)
+DECLARE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device)
+DECLARE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device)
+
+#endif // MAME_MACHINE_CAMMU_H