1 // license:BSD-3-Clause 2 // copyright-holders:Patrick Mackinlay 3 4 #ifndef MAME_MACHINE_CAMMU_H 5 #define MAME_MACHINE_CAMMU_H 6 7 #pragma once 8 9 #include "cpu/clipper/common.h" 10 11 class cammu_device : public device_t 12 { 13 public: exception_callback()14 auto exception_callback() { return m_exception_func.bind(); } 15 16 static const u32 CAMMU_PAGE_SIZE = 0x1000; 17 static const u32 CAMMU_PAGE_MASK = (CAMMU_PAGE_SIZE - 1); 18 19 enum pdo_mask : u32 20 { 21 PDO_MASK = 0xfffff000 22 }; 23 24 enum ptde_mask : u32 25 { 26 PTDE_F = 0x00000001, // page fault 27 PTDE_PTO = 0xfffff000 // page table origin 28 }; 29 30 enum pte_mask : u32 31 { 32 PTE_F = 0x00000001, // page fault 33 PTE_R = 0x00000002, // referenced flag 34 PTE_D = 0x00000004, // dirty flag 35 PTE_PL = 0x00000078, // protection level 36 PTE_S = 0x00000180, // system reserved 37 PTE_ST = 0x00000e00, // system tag 38 PTE_RA = 0xfffff000, // real address 39 40 PTE_CW = 0x00000040, // copy on write (c400) 41 PTE_NDREF = 0x00000080, // secondary reference (software) / copy on write (fault)? 42 PTE_LOCK = 0x00000100 // page lock (software) 43 }; 44 45 static constexpr int PL_SHIFT = 3; 46 static constexpr int ST_SHIFT = 9; 47 48 enum va_mask : u32 49 { 50 VA_POFS = 0x00000fff, // page offset 51 VA_PTI = 0x003ff000, // page table index 52 VA_PTDI = 0xffc00000 // page table directory index 53 }; 54 55 enum system_tag_t : u8 56 { 57 ST0 = 0, // private, write-through, main memory space 58 ST1 = 1, // shared, write-through, main memory space 59 ST2 = 2, // private, copy-back, main memory space 60 ST3 = 3, // noncacheable, main memory space 61 ST4 = 4, // noncacheable, i/o space 62 ST5 = 5, // noncacheable, boot space 63 ST6 = 6, // cache purge 64 ST7 = 7 // slave i/o 65 }; 66 67 void set_spaces(address_space &main_space, address_space &io_space, address_space &boot_space); 68 69 // translation lookaside buffer and register access 70 virtual u32 cammu_r(const u32 address) = 0; 71 virtual void cammu_w(const u32 address, const u32 data) = 0; 72 load(const u32 ssw,const u32 address,U && apply)73 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) 74 { 75 // check for cammu access 76 if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800)) 77 { 78 translated_t t = translate_address(ssw, address, access_size(sizeof(T)), READ); 79 80 if (!t.cache) 81 return false; 82 83 switch (sizeof(T)) 84 { 85 case 1: apply(T(t.cache->read_byte(t.address))); break; 86 case 2: apply(T(t.cache->read_word(t.address))); break; 87 case 4: apply(T(t.cache->read_dword(t.address))); break; 88 case 8: apply(T(t.cache->read_qword(t.address))); break; 89 default: 90 fatalerror("unhandled load 0x%08x size %d (%s)", 91 address, access_size(sizeof(T)), machine().describe_context().c_str()); 92 } 93 } 94 else if (sizeof(T) == 4) 95 apply(cammu_r(address)); 96 else 97 fatalerror("unhandled cammu load 0x%08x size %d (%s)", 98 address, access_size(sizeof(T)), machine().describe_context().c_str()); 99 100 return true; 101 } 102 store(const u32 ssw,const u32 address,U data)103 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) 104 { 105 // check for cammu access 106 if ((ssw & (SSW_UU | SSW_U)) || ((address & ~0x7ff) != 0x00004800)) 107 { 108 translated_t t = translate_address(ssw, address, access_size(sizeof(T)), WRITE); 109 110 if (!t.cache) 111 return false; 112 113 switch (sizeof(T)) 114 { 115 case 1: t.cache->write_byte(t.address, T(data)); break; 116 case 2: t.cache->write_word(t.address, T(data)); break; 117 case 4: t.cache->write_dword(t.address, T(data)); break; 118 case 8: t.cache->write_qword(t.address, T(data)); break; 119 default: 120 fatalerror("unhandled store 0x%08x size %d (%s)", 121 address, access_size(sizeof(T)), machine().describe_context().c_str()); 122 } 123 } 124 else if (sizeof(T) == 4) 125 cammu_w(address, data); 126 else 127 fatalerror("unhandled cammu store 0x%08x size %d (%s)", 128 address, access_size(sizeof(T)), machine().describe_context().c_str()); 129 130 return true; 131 } 132 modify(const u32 ssw,const u32 address,U && apply)133 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) 134 { 135 translated_t t = translate_address(ssw, address, access_size(sizeof(T)), access_type(READ | WRITE)); 136 137 if (!t.cache) 138 return false; 139 140 switch (sizeof(T)) 141 { 142 case 4: t.cache->write_dword(t.address, apply(T(t.cache->read_dword(t.address)))); break; 143 default: 144 fatalerror("unhandled modify 0x%08x size %d (%s)", 145 address, access_size(sizeof(T)), machine().describe_context().c_str()); 146 } 147 148 return true; 149 } 150 fetch(const u32 ssw,const u32 address,U && apply)151 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) 152 { 153 translated_t t = translate_address(ssw, address, access_size(sizeof(T)), EXECUTE); 154 155 if (!t.cache) 156 return false; 157 158 switch (sizeof(T)) 159 { 160 case 2: apply(T(t.cache->read_word(t.address))); break; 161 case 4: 162 { 163 // check for unaligned access 164 if (address & 0x2) 165 { 166 // check for page span 167 if ((address & CAMMU_PAGE_MASK) == (CAMMU_PAGE_SIZE - 2)) 168 { 169 translated_t u = translate_address(ssw, address + 2, access_size(sizeof(u16)), EXECUTE); 170 if (u.cache) 171 { 172 const u16 lsw = t.cache->read_word(t.address); 173 const u16 msw = t.cache->read_word(u.address); 174 175 apply((T(msw) << 16) | lsw); 176 } 177 else 178 return false; 179 } 180 else 181 apply(T(t.cache->read_dword_unaligned(t.address))); 182 } 183 else 184 apply(T(t.cache->read_dword(t.address))); 185 } 186 break; 187 default: 188 fatalerror("unhandled fetch 0x%08x size %d (%s)\n", 189 address, access_size(sizeof(T)), machine().describe_context().c_str()); 190 } 191 192 return true; 193 } 194 195 // address translation for debugger 196 bool memory_translate(const u32 ssw, const int spacenum, const int intention, offs_t &address); 197 198 protected: 199 cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); 200 201 // device-level overrides 202 virtual void device_start() override; 203 virtual void device_reset() override; 204 205 enum access_size : u8 206 { 207 BYTE = 1, 208 WORD = 2, 209 DWORD = 4, 210 QWORD = 8 211 }; 212 213 enum access_type : u8 214 { 215 READ = 1, 216 WRITE = 2, 217 EXECUTE = 4, 218 219 // matrix abbreviations and combinations 220 N = 0, 221 R = READ, 222 W = WRITE, 223 RW = READ | WRITE, 224 RE = READ | EXECUTE, 225 RWE = READ | WRITE | EXECUTE, 226 }; 227 228 struct translated_t 229 { 230 memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache *const cache; 231 const u32 address; 232 }; 233 234 struct pte_t 235 { 236 u32 entry; 237 u32 address; 238 }; 239 240 struct memory_t 241 { 242 address_space *space = nullptr; 243 memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache; 244 }; 245 246 // address translation 247 virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode); 248 pte_t get_pte(const u32 va, const bool user); 249 250 // helpers 251 virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const = 0; 252 virtual bool get_alignment() const = 0; 253 virtual u32 get_pdo(const bool user) const = 0; 254 virtual system_tag_t get_ust_space() const = 0; 255 virtual void set_fault(const u32 address, const exception_vector type) = 0; 256 257 // device state 258 devcb_write16 m_exception_func; 259 memory_t m_memory[8]; 260 }; 261 262 class cammu_c4_device : public cammu_device 263 { 264 public: 265 // TODO: translation lookaside buffer and register access 266 virtual void map(address_map &map) = 0; cammu_r(const u32 address)267 virtual u32 cammu_r(const u32 address) override { return 0; } cammu_w(const u32 address,const u32 data)268 virtual void cammu_w(const u32 address, const u32 data) override {} 269 set_cammu_id(const u32 cammu_id)270 void set_cammu_id(const u32 cammu_id) { m_control = cammu_id; } 271 s_pdo_r()272 u32 s_pdo_r() { return m_s_pdo; } 273 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; } u_pdo_r()274 u32 u_pdo_r() { return m_u_pdo; } 275 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; } 276 277 virtual u32 control_r() = 0; 278 virtual void control_w(offs_t offset, u32 data, u32 mem_mask = ~0) = 0; 279 i_fault_r()280 u32 i_fault_r() { return m_i_fault; } i_fault_w(u32 data)281 void i_fault_w(u32 data) { m_i_fault = data; } fault_address_1_r()282 u32 fault_address_1_r() { return m_fault_address_1; } fault_address_1_w(u32 data)283 void fault_address_1_w(u32 data) { m_fault_address_1 = data; } fault_address_2_r()284 u32 fault_address_2_r() { return m_fault_address_2; } fault_address_2_w(u32 data)285 void fault_address_2_w(u32 data) { m_fault_address_2 = data; } fault_data_1_lo_r()286 u32 fault_data_1_lo_r() { return m_fault_data_1_lo; } fault_data_1_lo_w(u32 data)287 void fault_data_1_lo_w(u32 data) { m_fault_data_1_lo = data; } fault_data_1_hi_r()288 u32 fault_data_1_hi_r() { return m_fault_data_1_hi; } fault_data_1_hi_w(u32 data)289 void fault_data_1_hi_w(u32 data) { m_fault_data_1_hi = data; } fault_data_2_lo_r()290 u32 fault_data_2_lo_r() { return m_fault_data_2_lo; } fault_data_2_lo_w(u32 data)291 void fault_data_2_lo_w(u32 data) { m_fault_data_2_lo = data; } fault_data_2_hi_r()292 u32 fault_data_2_hi_r() { return m_fault_data_2_hi; } fault_data_2_hi_w(u32 data)293 void fault_data_2_hi_w(u32 data) { m_fault_data_2_hi = data; } 294 295 protected: 296 cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); 297 298 virtual void device_start() override; 299 300 virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override; get_pdo(const bool user)301 virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; } 302 set_fault(const u32 address,const exception_vector type)303 virtual void set_fault(const u32 address, const exception_vector type) override { m_fault_address_1 = address; m_exception_func(type); } 304 305 u32 m_s_pdo; 306 u32 m_u_pdo; 307 u32 m_control; 308 309 u32 m_i_fault; 310 u32 m_fault_address_1; 311 u32 m_fault_address_2; 312 u32 m_fault_data_1_lo; 313 u32 m_fault_data_1_hi; 314 u32 m_fault_data_2_lo; 315 u32 m_fault_data_2_hi; 316 }; 317 318 class cammu_c4t_device : public cammu_c4_device 319 { 320 public: 321 cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 322 323 virtual void map(address_map &map) override; 324 ram_line_r()325 u32 ram_line_r() { return m_ram_line; } ram_line_w(u32 data)326 void ram_line_w(u32 data) { m_ram_line = data; } 327 htlb_offset_r()328 u32 htlb_offset_r() { return m_htlb_offset; } htlb_offset_w(u32 data)329 void htlb_offset_w(u32 data) { m_htlb_offset = data; } 330 c4_bus_poll_r()331 u32 c4_bus_poll_r() { return m_c4_bus_poll; } c4_bus_poll_w(u32 data)332 void c4_bus_poll_w(u32 data) { m_c4_bus_poll = data; } 333 334 enum control_mask : u32 335 { 336 CNTL_RUV = 0x00000001, // reset user valid 337 CNTL_RSV = 0x00000002, // reset supervisor valid 338 CNTL_DBWR = 0x00000004, // disable bus watch read 339 CNTL_ATD = 0x00000008, // alignment trap disable 340 CNTL_UST = 0x00000030, // unmapped system tag 341 CNTL_IOTS = 0x00000040, // i/o tag select 342 CNTL_UVS = 0x00000080, // user valid status 343 CNTL_PB = 0x00000100, // purge busy 344 CNTL_CICT = 0x00000200, // clear i-side cache tags 345 CNTL_CFR = 0x00000400, // clear trap registers 346 CNTL_HTLBD = 0x00000800, // htlb disable 347 CNTL_CDCT = 0x00001000, // clear d-side cache tags 348 CNTL_CID = 0xff000000 // cammu id 349 }; 350 351 enum control_ust_mask : u32 352 { 353 UST_NCA = 0x00, // unmapped system tag, noncacheable 354 UST_PWT = 0x10, // unmapped system tag, write through 355 UST_PCB = 0x20, // unmapped system tag, copy back 356 UST_PGE = 0x30 // unmapped system tag, purge mode 357 }; 358 359 enum control_cid_mask : u32 360 { 361 CID_C4T = 0x00000000 // unknown 362 }; 363 control_r()364 virtual u32 control_r() override { return m_control; } 365 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))); } bio_control_r()366 u32 bio_control_r() { return m_bio_control; } bio_control_w(u32 data)367 void bio_control_w(u32 data) { m_bio_control = data; } bio_address_tag_r()368 u32 bio_address_tag_r() { return m_bio_address_tag; } bio_address_tag_w(u32 data)369 void bio_address_tag_w(u32 data) { m_bio_address_tag = data; } 370 cache_data_lo_r()371 u32 cache_data_lo_r() { return m_cache_data_lo; } cache_data_lo_w(u32 data)372 void cache_data_lo_w(u32 data) { m_cache_data_lo = data; } cache_data_hi_r()373 u32 cache_data_hi_r() { return m_cache_data_hi; } cache_data_hi_w(u32 data)374 void cache_data_hi_w(u32 data) { m_cache_data_hi = data; } cache_cpu_tag_r()375 u32 cache_cpu_tag_r() { return m_cache_cpu_tag; } cache_cpu_tag_w(u32 data)376 void cache_cpu_tag_w(u32 data) { m_cache_cpu_tag = data; } cache_system_tag_valid_r()377 u32 cache_system_tag_valid_r() { return m_cache_system_tag_valid; } cache_system_tag_valid_w(u32 data)378 void cache_system_tag_valid_w(u32 data) { m_cache_system_tag_valid = data; } cache_system_tag_r()379 u32 cache_system_tag_r() { return m_cache_system_tag; } cache_system_tag_w(u32 data)380 void cache_system_tag_w(u32 data) { m_cache_system_tag = data; } tlb_va_line_r()381 u32 tlb_va_line_r() { return m_tlb_va_line; } tlb_va_line_w(u32 data)382 void tlb_va_line_w(u32 data) { m_tlb_va_line = data; } tlb_ra_line_r()383 u32 tlb_ra_line_r() { return m_tlb_ra_line; } tlb_ra_line_w(u32 data)384 void tlb_ra_line_w(u32 data) { m_tlb_ra_line = data; } 385 386 protected: 387 virtual void device_start() override; 388 get_alignment()389 virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; } get_ust_space()390 virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & (CNTL_IOTS | CNTL_UST)) >> 4); } 391 392 private: 393 u32 m_ram_line; 394 u32 m_htlb_offset; 395 u32 m_c4_bus_poll; 396 u32 m_bio_control; 397 u32 m_bio_address_tag; 398 399 u32 m_cache_data_lo; 400 u32 m_cache_data_hi; 401 u32 m_cache_cpu_tag; 402 u32 m_cache_system_tag_valid; 403 u32 m_cache_system_tag; 404 u32 m_tlb_va_line; 405 u32 m_tlb_ra_line; 406 }; 407 408 class cammu_c4i_device : public cammu_c4_device 409 { 410 public: 411 cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 412 413 virtual void map(address_map &map) override; 414 415 enum control_mask : u32 416 { 417 CNTL_LRAS = 0x00000001, // tlb line replacement 418 CNTL_BWWD = 0x00000002, // buswatch write disable 419 CNTL_BWRD = 0x00000004, // buswatch read disable 420 CNTL_FSR = 0x00000010, // fake system response 421 CNTL_ATD = 0x00000100, // alignment trap disable 422 CNTL_UMM = 0x00003000, // unmapped mode address space select 423 CNTL_POLL = 0x00030000, // poll bus signals 424 CNTL_BM = 0x00040000, // burst mode address space select 425 CNTL_PZBS = 0x00080000, // page 0 boot select 426 CNTL_CRR = 0x00700000, // cache memory refresh rate 427 CNTL_CID = 0xff000000 // cammu identification 428 }; 429 430 enum control_umm_mask : u32 431 { 432 UMM_MM = 0x00000000, // mm space, noncacheable 433 UMM_MMRIO = 0x00001000, // mm or i/o space, noncacheable 434 UMM_IO = 0x00002000 // i/o space noncacheable 435 }; 436 437 enum control_crr_mask : u32 438 { 439 CRR_GT131 = 0x00000000, // clock rate over 131 MHz 440 CRR_GT66 = 0x00100000, // clock rate over 66 MHz 441 CRR_GT33 = 0x00200000, // clock rate over 33 MHz 442 CRR_GT8 = 0x00300000, // clock rate over 8 MHz 443 CRR_GT2 = 0x00400000, // clock rate over 2 MHz 444 CRR_GT1 = 0x00500000, // clock rate over 1 MHz 445 CRR_GTHALF = 0x00600000, // clock rate over 0.5 MHz 446 CRR_OFF = 0x00700000, // refresh off 447 }; 448 449 // c4i cammu identification (rev 2 and rev 3 known to have existed) 450 enum control_cid_mask : u32 451 { 452 CID_C4IR0 = 0x00000000, 453 CID_C4IR2 = 0x02000000 454 }; 455 control_r()456 virtual u32 control_r() override { return m_control; } control_w(offs_t offset,u32 data,u32 mem_mask)457 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))); } 458 459 enum reset_mask : u32 460 { 461 RESET_CDCT = 0x00000001, // clear data cache tags 462 RESET_RDUV = 0x00000100, // reset all d-side uv flags 463 RESET_RDSV = 0x00001000, // reset all d-side sv flags 464 RESET_CICT = 0x00010000, // clear ins. cache tags 465 RESET_RIUV = 0x01000000, // reset all i-side uv flags 466 RESET_RISV = 0x10000000, // reset all i-side sv flags 467 RESET_FLUSH = 0x40000000, // flush out burst io buffer 468 RESET_CFR = 0x80000000 // clear fault registers 469 }; reset_r()470 u32 reset_r() { return m_reset; } reset_w(u32 data)471 void reset_w(u32 data) { m_reset = data; } 472 clr_s_data_tlb_r()473 u32 clr_s_data_tlb_r() { return m_clr_s_data_tlb; } clr_s_data_tlb_w(u32 data)474 void clr_s_data_tlb_w(u32 data) { m_clr_s_data_tlb = data; } clr_u_data_tlb_r()475 u32 clr_u_data_tlb_r() { return m_clr_u_data_tlb; } clr_u_data_tlb_w(u32 data)476 void clr_u_data_tlb_w(u32 data) { m_clr_u_data_tlb = data; } clr_s_insn_tlb_r()477 u32 clr_s_insn_tlb_r() { return m_clr_s_insn_tlb; } clr_s_insn_tlb_w(u32 data)478 void clr_s_insn_tlb_w(u32 data) { m_clr_s_insn_tlb = data; } clr_u_insn_tlb_r()479 u32 clr_u_insn_tlb_r() { return m_clr_u_insn_tlb; } clr_u_insn_tlb_w(u32 data)480 void clr_u_insn_tlb_w(u32 data) { m_clr_u_insn_tlb = data; } 481 test_data_r()482 u32 test_data_r() { return m_test_data; } test_data_w(u32 data)483 void test_data_w(u32 data) { m_test_data = data; } 484 test_address_r()485 u32 test_address_r() { return m_test_address; } test_address_w(u32 data)486 void test_address_w(u32 data) { m_test_address = data; } 487 488 protected: 489 virtual void device_start() override; 490 get_alignment()491 virtual bool get_alignment() const override { return (m_control & CNTL_ATD) == 0; } 492 // FIXME: don't really know how unmapped mode works on c4i get_ust_space()493 virtual system_tag_t get_ust_space() const override { return (m_control & UMM_IO) ? ST4 : ST3; } 494 495 private: 496 u32 m_reset; 497 u32 m_clr_s_data_tlb; 498 u32 m_clr_u_data_tlb; 499 u32 m_clr_s_insn_tlb; 500 u32 m_clr_u_insn_tlb; 501 u32 m_test_data; 502 u32 m_test_address; 503 }; 504 505 class cammu_c3_device : public cammu_device 506 { 507 public: 508 cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); 509 add_linked(cammu_c3_device * child)510 void add_linked(cammu_c3_device *child) { m_linked.push_back(child); } 511 512 protected: 513 // device-level overrides 514 virtual void device_reset() override; 515 virtual void device_start() override; 516 517 // translation lookaside buffer and register access 518 virtual u32 cammu_r(const u32 address) override; 519 virtual void cammu_w(const u32 address, const u32 data) override; 520 521 // address translation 522 virtual translated_t translate_address(const u32 ssw, const u32 virtual_address, const access_size size, const access_type mode) override; 523 524 private: 525 enum cammu_address_mask : u32 526 { 527 CAMMU_TLB_VA = 0x00000001, // tlb va/ra select 528 CAMMU_TLB_X = 0x00000002, // tlb x/w line select 529 CAMMU_TLB_SET = 0x000000fc, // tlb set select 530 CAMMU_REG = 0x000000ff, // register select 531 CAMMU_SELECT = 0x00000700, // cammu select 532 }; 533 enum tlb_ra_mask : u32 534 { 535 TLB_RA_U = 0x00000001, // used flag 536 TLB_RA_R = 0x00000002, // referenced flag 537 TLB_RA_D = 0x00000004, // dirty flag 538 TLB_RA_PL = 0x00000078, // protection level 539 TLB_RA_ST = 0x00000e00, // system tag 540 TLB_RA_RA = 0xfffff000, // real address 541 }; 542 enum tlb_va_mask : u32 543 { 544 TLB_VA_UV = 0x00000002, // user valid flag 545 TLB_VA_SV = 0x00000004, // supervisor valid flag 546 TLB_VA_VA = 0xfffc0000, // virtual address tag 547 }; 548 549 /* 550 * The C1/C3 CAMMU has 64-entry, two-way set associative TLB, with lines 551 * grouped into W and X compartments. The associated U flag is set to 552 * indicate that the W line of the set was most recently accessed, and 553 * cleared when the X line was most recently accessed. On TLB miss, the 554 * least recently used line as indicated by this flag is replaced. 555 * 556 * Each line consists of a real address field and a virtual address field. 557 * The real address field format is practically identical to the page table 558 * entry format. 559 */ 560 struct tlb_line_t 561 { 562 u32 ra; // real address field 563 u32 va; // virtual address field 564 565 memory_access<32, 2, 0, ENDIANNESS_LITTLE>::cache cache; 566 }; 567 struct tlb_set_t 568 { 569 tlb_line_t w; 570 tlb_line_t x; 571 bool u; 572 }; 573 574 enum cammu_select_mask : u32 575 { 576 CAMMU_D_TLB = 0x000, // d-cammu tlb 577 CAMMU_D_REG = 0x100, // d-cammu register 578 CAMMU_I_TLB = 0x200, // i-cammu tlb 579 CAMMU_I_REG = 0x300, // i-cammu register 580 CAMMU_G_TLB = 0x400, // global tlb 581 CAMMU_G_REG = 0x500, // global register 582 }; 583 enum cammu_register_mask : u8 584 { 585 CAMMU_REG_SPDO = 0x04, // supervisor pdo register 586 CAMMU_REG_UPDO = 0x08, // user pdo register 587 CAMMU_REG_FAULT = 0x10, // fault register 588 CAMMU_REG_CONTROL = 0x40, // control register 589 CAMMU_REG_RESET = 0x80, // reset register 590 }; 591 592 enum control_mask : u32 593 { 594 CNTL_EP = 0x00000001, // enable prefetch 595 CNTL_EWCW = 0x00000002, // enable watch cpu writes 596 CNTL_EWIW = 0x00000004, // enable watch i/o writes 597 CNTL_EWIR = 0x00000008, // enable watch i/o reads 598 CNTL_UST = 0x00000030, // unmapped system tag 599 CNTL_CV = 0x00000100, // clear valid 600 CNTL_ATE = 0x00000200, // alignment trap enable 601 CNTL_CID = 0xff000000 // cammu id 602 }; 603 enum control_ust_mask : u32 604 { 605 UST_0 = 0x00000000, // private, write-through, main memory space 606 UST_1 = 0x00000010, // shared, write-through, main memory space 607 UST_2 = 0x00000020, // private, copy-back, main memory space 608 UST_3 = 0x00000030 // noncacheable, main memory space 609 }; 610 enum control_cid_mask : u32 611 { 612 CID_C3 = 0x00000000 // unknown 613 }; 614 615 enum reset_mask : u32 616 { 617 RESET_RLVW = 0x00000001, // reset all W line LV flags in cache 618 RESET_RLVX = 0x00000002, // reset all X line LV flags in cache 619 RESET_RSV = 0x00000004, // reset all SV flags in tlb 620 RESET_RUV = 0x00000008, // reset all UV flags in tlb 621 RESET_RD = 0x00000010, // reset all D flags in tlb 622 RESET_RR = 0x00000020, // reset all R flags in tlb 623 RESET_RU = 0x00000040, // reset all U flags in cache 624 }; 625 626 u32 tlb_r(const u8 address) const; 627 void tlb_w(const u8 address, const u32 data); 628 tlb_line_t &tlb_lookup(const bool user, const u32 virtual_address, const access_type mode); 629 s_pdo_r()630 u32 s_pdo_r() const { return m_s_pdo; } s_pdo_w(const u32 data)631 void s_pdo_w(const u32 data) { m_s_pdo = data & PDO_MASK; } u_pdo_r()632 u32 u_pdo_r() const { return m_u_pdo; } u_pdo_w(const u32 data)633 void u_pdo_w(const u32 data) { m_u_pdo = data & PDO_MASK; } fault_r()634 u32 fault_r() const { return m_fault; } fault_w(const u32 data)635 void fault_w(const u32 data) { m_fault = data; } control_r()636 u32 control_r() const { return m_control; } control_w(const u32 data)637 void control_w(const u32 data) { m_control = (m_control & CNTL_CID) | (data & ~CNTL_CID); } 638 void reset_w(const u32 data); 639 get_alignment()640 virtual bool get_alignment() const override { return m_control & CNTL_ATE; } get_ust_space()641 virtual system_tag_t get_ust_space() const override { return system_tag_t((m_control & CNTL_UST) >> 4); } 642 virtual bool get_access(const access_type mode, const u32 pte, const u32 ssw) const override; get_pdo(const bool user)643 virtual u32 get_pdo(const bool user) const override { return user ? m_u_pdo : m_s_pdo; } 644 set_fault(const u32 address,const exception_vector type)645 virtual void set_fault(const u32 address, const exception_vector type) override { m_fault = address; m_exception_func(type); } 646 647 static const u8 protection_matrix[4][16]; 648 649 // device state 650 std::vector<cammu_c3_device *> m_linked; 651 652 u32 m_s_pdo; 653 u32 m_u_pdo; 654 u32 m_fault; 655 u32 m_control; 656 657 tlb_set_t m_tlb[64]; 658 }; 659 660 // device type definitions 661 DECLARE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device) 662 DECLARE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device) 663 DECLARE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device) 664 665 #endif // MAME_MACHINE_CAMMU_H 666