summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Miodrag Milanović <mmicko@gmail.com>2016-02-07 08:23:34 +0100
committer Miodrag Milanović <mmicko@gmail.com>2016-02-07 08:23:34 +0100
commit88efd657dbd30fd509de64e8a3e87f04fd4f1638 (patch)
treed69685e02c93053693deef9fc6ca2c7704444ff1
parent2fda7e23f2ff096a27b316a2504e6d333c70640e (diff)
parent0d8df9d595aa49dd1ce77fa7ecd1db5b286a6f9f (diff)
Merge pull request #609 from ajrhacker/vtlb
Vtlb
-rw-r--r--scripts/src/cpu.lua9
-rw-r--r--scripts/src/emu.lua2
-rw-r--r--src/devices/cpu/i386/i386.cpp61
-rw-r--r--src/devices/cpu/i386/i386.h8
-rw-r--r--src/devices/cpu/i386/i386ops.inc2
-rw-r--r--src/devices/cpu/i386/i386priv.h4
-rw-r--r--src/devices/cpu/i386/i486ops.inc8
-rw-r--r--src/devices/cpu/mips/mips3.cpp67
-rw-r--r--src/devices/cpu/mips/mips3.h6
-rw-r--r--src/devices/cpu/mips/mips3com.cpp12
-rw-r--r--src/devices/cpu/mips/mips3com.h1
-rw-r--r--src/devices/cpu/mips/mips3drc.cpp6
-rw-r--r--src/devices/cpu/powerpc/ppc.h7
-rw-r--r--src/devices/cpu/powerpc/ppccom.cpp28
-rw-r--r--src/devices/cpu/powerpc/ppcdrc.cpp10
-rw-r--r--src/devices/cpu/vtlb.cpp310
-rw-r--r--src/devices/cpu/vtlb.h88
-rw-r--r--src/emu/dimemory.h18
-rw-r--r--src/emu/divtlb.cpp341
-rw-r--r--src/emu/divtlb.h89
20 files changed, 529 insertions, 548 deletions
diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua
index 0c2882df5e5..ed6378f93f8 100644
--- a/scripts/src/cpu.lua
+++ b/scripts/src/cpu.lua
@@ -10,14 +10,6 @@
---------------------------------------------------------------------------
--------------------------------------------------
--- Shared code
---------------------------------------------------
-
-files {
- MAME_DIR .. "src/devices/cpu/vtlb.cpp",
-}
-
---------------------------------------------------
-- Dynamic recompiler objects
--------------------------------------------------
@@ -43,7 +35,6 @@ if (CPUS["SH2"]~=null or CPUS["MIPS"]~=null or CPUS["POWERPC"]~=null or CPUS["RS
MAME_DIR .. "src/devices/cpu/drcbex64.cpp",
MAME_DIR .. "src/devices/cpu/drcbex64.h",
MAME_DIR .. "src/devices/cpu/drcumlsh.h",
- MAME_DIR .. "src/devices/cpu/vtlb.h",
MAME_DIR .. "src/devices/cpu/x86emit.h",
}
end
diff --git a/scripts/src/emu.lua b/scripts/src/emu.lua
index b49756676ce..e0358285114 100644
--- a/scripts/src/emu.lua
+++ b/scripts/src/emu.lua
@@ -117,6 +117,8 @@ files {
MAME_DIR .. "src/emu/distate.h",
MAME_DIR .. "src/emu/divideo.cpp",
MAME_DIR .. "src/emu/divideo.h",
+ MAME_DIR .. "src/emu/divtlb.cpp",
+ MAME_DIR .. "src/emu/divtlb.h",
MAME_DIR .. "src/emu/drawgfx.cpp",
MAME_DIR .. "src/emu/drawgfx.h",
MAME_DIR .. "src/emu/drawgfxm.h",
diff --git a/src/devices/cpu/i386/i386.cpp b/src/devices/cpu/i386/i386.cpp
index f0d57ada9a0..62a65155a59 100644
--- a/src/devices/cpu/i386/i386.cpp
+++ b/src/devices/cpu/i386/i386.cpp
@@ -41,23 +41,31 @@ const device_type PENTIUM4 = &device_creator<pentium4_device>;
i386_device::i386_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: cpu_device(mconfig, I386, "I386", tag, owner, clock, "i386", __FILE__)
+ , device_vtlb_interface(mconfig, *this, AS_PROGRAM)
, m_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0)
, m_io_config("io", ENDIANNESS_LITTLE, 32, 16, 0)
, m_smiact(*this)
{
m_program_config.m_logaddr_width = 32;
m_program_config.m_page_shift = 12;
+
+ // 32 unified
+ set_vtlb_dynamic_entries(32);
}
i386_device::i386_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source, int program_data_width, int program_addr_width, int io_data_width)
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, source)
+ , device_vtlb_interface(mconfig, *this, AS_PROGRAM)
, m_program_config("program", ENDIANNESS_LITTLE, program_data_width, program_addr_width, 0)
, m_io_config("io", ENDIANNESS_LITTLE, io_data_width, 16, 0)
, m_smiact(*this)
{
m_program_config.m_logaddr_width = 32;
m_program_config.m_page_shift = 12;
+
+ // 32 unified
+ set_vtlb_dynamic_entries(32);
}
i386SX_device::i386SX_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
@@ -73,11 +81,15 @@ i486_device::i486_device(const machine_config &mconfig, const char *tag, device_
pentium_device::pentium_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: i386_device(mconfig, PENTIUM, "PENTIUM", tag, owner, clock, "pentium", __FILE__)
{
+ // 64 dtlb small, 8 dtlb large, 32 itlb
+ set_vtlb_dynamic_entries(96);
}
pentium_device::pentium_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
: i386_device(mconfig, type, name, tag, owner, clock, shortname, source)
{
+ // 64 dtlb small, 8 dtlb large, 32 itlb
+ set_vtlb_dynamic_entries(96);
}
mediagx_device::mediagx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
@@ -93,21 +105,29 @@ pentium_pro_device::pentium_pro_device(const machine_config &mconfig, const char
pentium_mmx_device::pentium_mmx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: pentium_device(mconfig, PENTIUM_MMX, "Pentium MMX", tag, owner, clock, "pentium_mmx", __FILE__)
{
+ // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
+ set_vtlb_dynamic_entries(96);
}
pentium2_device::pentium2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: pentium_device(mconfig, PENTIUM2, "Pentium II", tag, owner, clock, "pentium2", __FILE__)
{
+ // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
+ set_vtlb_dynamic_entries(96);
}
pentium3_device::pentium3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: pentium_device(mconfig, PENTIUM3, "Pentium III", tag, owner, clock, "pentium3", __FILE__)
{
+ // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
+ set_vtlb_dynamic_entries(96);
}
pentium4_device::pentium4_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: pentium_device(mconfig, PENTIUM4, "Pentium 4", tag, owner, clock, "pentium4", __FILE__)
{
+ // 128 dtlb, 64 itlb
+ set_vtlb_dynamic_entries(196);
}
@@ -1306,7 +1326,7 @@ void i386_device::i386_task_switch(UINT16 selector, UINT8 nested)
}
m_cr[3] = READ32(tss+0x1c); // CR3 (PDBR)
if(oldcr3 != m_cr[3])
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
/* Set the busy bit in the new task's descriptor */
if(selector & 0x0004)
@@ -3178,7 +3198,7 @@ void i386_device::i386_postload()
CHANGE_PC(m_eip);
}
-void i386_device::i386_common_init(int tlbsize)
+void i386_device::i386_common_init()
{
int i, j;
static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
@@ -3211,7 +3231,6 @@ void i386_device::i386_common_init(int tlbsize)
m_program = &space(AS_PROGRAM);
m_direct = &m_program->direct();
m_io = &space(AS_IO);
- m_vtlb = vtlb_alloc(this, AS_PROGRAM, 0, tlbsize);
m_smi = false;
m_debugger_temp = 0;
m_lock = false;
@@ -3294,7 +3313,7 @@ void i386_device::i386_common_init(int tlbsize)
void i386_device::device_start()
{
- i386_common_init(32);
+ i386_common_init();
build_opcode_table(OP_I386);
m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386].get();
@@ -3698,7 +3717,6 @@ void i386_device::zero_state()
void i386_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -3890,7 +3908,7 @@ void i386_device::i386_set_a20_line(int state)
m_a20_mask = ~(1 << 20);
}
// TODO: how does A20M and the tlb interact
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
}
void i386_device::execute_run()
@@ -3976,7 +3994,7 @@ offs_t i386_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *opr
void i486_device::device_start()
{
- i386_common_init(32);
+ i386_common_init();
build_opcode_table(OP_I386 | OP_FPU | OP_I486);
build_x87_opcode_table();
@@ -3989,7 +4007,6 @@ void i486_device::device_start()
void i486_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4033,8 +4050,7 @@ void i486_device::device_reset()
void pentium_device::device_start()
{
- // 64 dtlb small, 8 dtlb large, 32 itlb
- i386_common_init(96);
+ i386_common_init();
register_state_i386_x87();
build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM);
@@ -4046,7 +4062,6 @@ void pentium_device::device_start()
void pentium_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4107,8 +4122,7 @@ void pentium_device::device_reset()
void mediagx_device::device_start()
{
- // probably 32 unified
- i386_common_init(32);
+ i386_common_init();
register_state_i386_x87();
build_x87_opcode_table();
@@ -4120,7 +4134,6 @@ void mediagx_device::device_start()
void mediagx_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4172,8 +4185,7 @@ void mediagx_device::device_reset()
void pentium_pro_device::device_start()
{
- // 64 dtlb small, 32 itlb
- i386_common_init(96);
+ i386_common_init();
register_state_i386_x87();
build_x87_opcode_table();
@@ -4185,7 +4197,6 @@ void pentium_pro_device::device_start()
void pentium_pro_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4247,8 +4258,7 @@ void pentium_pro_device::device_reset()
void pentium_mmx_device::device_start()
{
- // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
- i386_common_init(96);
+ i386_common_init();
register_state_i386_x87();
build_x87_opcode_table();
@@ -4260,7 +4270,6 @@ void pentium_mmx_device::device_start()
void pentium_mmx_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4320,8 +4329,7 @@ void pentium_mmx_device::device_reset()
void pentium2_device::device_start()
{
- // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
- i386_common_init(96);
+ i386_common_init();
register_state_i386_x87();
build_x87_opcode_table();
@@ -4333,7 +4341,6 @@ void pentium2_device::device_start()
void pentium2_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4387,8 +4394,7 @@ void pentium2_device::device_reset()
void pentium3_device::device_start()
{
- // 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
- i386_common_init(96);
+ i386_common_init();
register_state_i386_x87_xmm();
build_x87_opcode_table();
@@ -4400,7 +4406,6 @@ void pentium3_device::device_start()
void pentium3_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
@@ -4456,8 +4461,7 @@ void pentium3_device::device_reset()
void pentium4_device::device_start()
{
- // 128 dtlb, 64 itlb
- i386_common_init(196);
+ i386_common_init();
register_state_i386_x87_xmm();
build_x87_opcode_table();
@@ -4469,7 +4473,6 @@ void pentium4_device::device_start()
void pentium4_device::device_reset()
{
zero_state();
- vtlb_flush_dynamic(m_vtlb);
m_sreg[CS].selector = 0xf000;
m_sreg[CS].base = 0xffff0000;
diff --git a/src/devices/cpu/i386/i386.h b/src/devices/cpu/i386/i386.h
index c9ef38b4280..979aaf08f45 100644
--- a/src/devices/cpu/i386/i386.h
+++ b/src/devices/cpu/i386/i386.h
@@ -8,7 +8,7 @@
#include "softfloat/milieu.h"
#include "softfloat/softfloat.h"
#include "debug/debugcpu.h"
-#include "cpu/vtlb.h"
+#include "divtlb.h"
#define INPUT_LINE_A20 1
@@ -24,7 +24,7 @@
#define X86_NUM_CPUS 4
-class i386_device : public cpu_device
+class i386_device : public cpu_device, public device_vtlb_interface
{
public:
// construction/destruction
@@ -270,8 +270,6 @@ struct I386_CALL_GATE
UINT8 *m_cycle_table_pm;
UINT8 *m_cycle_table_rm;
- vtlb_state *m_vtlb;
-
bool m_smm;
bool m_smi;
bool m_smi_latched;
@@ -1411,7 +1409,7 @@ struct I386_CALL_GATE
void build_x87_opcode_table_df();
void build_x87_opcode_table();
void i386_postload();
- void i386_common_init(int tlbsize);
+ void i386_common_init();
void build_opcode_table(UINT32 features);
void pentium_smi();
void zero_state();
diff --git a/src/devices/cpu/i386/i386ops.inc b/src/devices/cpu/i386/i386ops.inc
index dc237c98469..ea15f9a5923 100644
--- a/src/devices/cpu/i386/i386ops.inc
+++ b/src/devices/cpu/i386/i386ops.inc
@@ -701,7 +701,7 @@ void i386_device::i386_mov_cr_r32() // Opcode 0x0f 22
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
case 3:
CYCLES(CYCLES_MOV_REG_CR3);
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
break;
case 4: CYCLES(1); break; // TODO
default:
diff --git a/src/devices/cpu/i386/i386priv.h b/src/devices/cpu/i386/i386priv.h
index fa7ae0d4945..339e630d1cd 100644
--- a/src/devices/cpu/i386/i386priv.h
+++ b/src/devices/cpu/i386/i386priv.h
@@ -486,7 +486,7 @@ int i386_device::translate_address(int pl, int type, UINT32 *address, UINT32 *er
if(!(m_cr[0] & 0x80000000)) // Some (very few) old OS's won't work with this
return TRUE;
- const vtlb_entry *table = vtlb_table(m_vtlb);
+ const vtlb_entry *table = vtlb_table();
UINT32 index = *address >> 12;
vtlb_entry entry = table[index];
if(type == TRANSLATE_FETCH)
@@ -506,7 +506,7 @@ int i386_device::translate_address(int pl, int type, UINT32 *address, UINT32 *er
*error |= 1;
return FALSE;
}
- vtlb_dynload(m_vtlb, index, *address, entry);
+ vtlb_dynload(index, *address, entry);
return TRUE;
}
if(!(entry & (1 << type)))
diff --git a/src/devices/cpu/i386/i486ops.inc b/src/devices/cpu/i386/i486ops.inc
index d22f6c079c3..8be406692d4 100644
--- a/src/devices/cpu/i386/i486ops.inc
+++ b/src/devices/cpu/i386/i486ops.inc
@@ -312,7 +312,7 @@ void i386_device::i486_group0F01_16() // Opcode 0x0f 01
}
ea = GetEA(modrm,-1);
CYCLES(25); // TODO: add to cycles.h
- vtlb_flush_address(m_vtlb, ea);
+ vtlb_flush_address(ea);
break;
}
default:
@@ -430,7 +430,7 @@ void i386_device::i486_group0F01_32() // Opcode 0x0f 01
}
ea = GetEA(modrm,-1);
CYCLES(25); // TODO: add to cycles.h
- vtlb_flush_address(m_vtlb, ea);
+ vtlb_flush_address(ea);
break;
}
default:
@@ -500,12 +500,12 @@ void i386_device::i486_mov_cr_r32() // Opcode 0x0f 22
case 0:
CYCLES(CYCLES_MOV_REG_CR0);
if((oldcr ^ m_cr[cr]) & 0x80010000)
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
break;
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
case 3:
CYCLES(CYCLES_MOV_REG_CR3);
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
break;
case 4: CYCLES(1); break; // TODO
default:
diff --git a/src/devices/cpu/mips/mips3.cpp b/src/devices/cpu/mips/mips3.cpp
index f4747b7304c..711b9c3edf4 100644
--- a/src/devices/cpu/mips/mips3.cpp
+++ b/src/devices/cpu/mips/mips3.cpp
@@ -120,8 +120,10 @@ const device_type RM7000BE = &device_creator<rm7000be_device>;
const device_type RM7000LE = &device_creator<rm7000le_device>;
+// VR4300 and VR5432 have 4 fewer PFN bits, and only 32 TLB entries
mips3_device::mips3_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, mips3_flavor flavor, endianness_t endianness)
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__)
+ , device_vtlb_interface(mconfig, *this, AS_PROGRAM)
, m_program_config("program", endianness, 32, 32, 0, 32, MIPS3_MIN_PAGE_SHIFT)
, m_flavor(flavor)
, m_core(nullptr)
@@ -134,7 +136,6 @@ mips3_device::mips3_device(const machine_config &mconfig, device_type type, cons
, m_ll_value(0)
, m_lld_value(0)
, m_badcop_value(0)
- , m_tlb_table(nullptr)
, m_lwl(endianness == ENDIANNESS_BIG ? &mips3_device::lwl_be : &mips3_device::lwl_le)
, m_lwr(endianness == ENDIANNESS_BIG ? &mips3_device::lwr_be : &mips3_device::lwr_le)
, m_swl(endianness == ENDIANNESS_BIG ? &mips3_device::swl_be : &mips3_device::swl_le)
@@ -144,14 +145,13 @@ mips3_device::mips3_device(const machine_config &mconfig, device_type type, cons
, m_sdl(endianness == ENDIANNESS_BIG ? &mips3_device::sdl_be : &mips3_device::sdl_le)
, m_sdr(endianness == ENDIANNESS_BIG ? &mips3_device::sdr_be : &mips3_device::sdr_le)
, c_system_clock(0)
- , m_pfnmask(0)
- , m_tlbentries(0)
+ , m_pfnmask(flavor == MIPS3_TYPE_VR4300 ? 0x000fffff : 0x00ffffff)
+ , m_tlbentries(flavor == MIPS3_TYPE_VR4300 ? 32 : MIPS3_MAX_TLB_ENTRIES)
, m_bigendian(endianness == ENDIANNESS_BIG)
, m_byte_xor(m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0))
, m_word_xor(m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0))
, c_icache_size(0)
, c_dcache_size(0)
- , m_vtlb(nullptr)
, m_fastram_select(0)
, m_debugger_temp(0)
, m_cache(CACHE_SIZE + sizeof(internal_mips3_state))
@@ -190,17 +190,14 @@ mips3_device::mips3_device(const machine_config &mconfig, device_type type, cons
}
memset(m_fastram, 0, sizeof(m_fastram));
memset(m_hotspot, 0, sizeof(m_hotspot));
+
+ // configure the virtual TLB
+ set_vtlb_fixed_entries(2 * m_tlbentries + 2);
}
void mips3_device::device_stop()
{
- if (m_vtlb != nullptr)
- {
- vtlb_free(m_vtlb);
- m_vtlb = nullptr;
- }
-
if (m_drcfe != nullptr)
{
m_drcfe = nullptr;
@@ -331,28 +328,12 @@ void mips3_device::device_start()
m_program = &space(AS_PROGRAM);
m_direct = &m_program->direct();
- /* configure flavor-specific parameters */
- m_pfnmask = 0x00ffffff;
- m_tlbentries = MIPS3_MAX_TLB_ENTRIES;
-
- /* VR4300 and VR5432 have 4 fewer PFN bits, and only 32 TLB entries */
- if (m_flavor == MIPS3_TYPE_VR4300)
- {
- m_pfnmask = 0x000fffff;
- m_tlbentries = 32;
- }
-
/* set up the endianness */
m_program->accessors(m_memory);
- /* allocate the virtual TLB */
- m_vtlb = vtlb_alloc(this, AS_PROGRAM, 2 * m_tlbentries + 2, 0);
-
/* allocate a timer for the compare interrupt */
m_compare_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mips3_device::compare_int_callback), this));
- m_tlb_table = vtlb_table(m_vtlb);
-
UINT32 flags = 0;
/* initialize the UML generator */
m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 8, 32, 2);
@@ -950,13 +931,13 @@ void mips3_device::device_reset()
entry->entry_hi = 0xffffffff;
entry->entry_lo[0] = 0xfffffff8;
entry->entry_lo[1] = 0xfffffff8;
- vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0);
- vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 1, 0, 0, 0);
}
/* load the fixed TLB range */
- vtlb_load(m_vtlb, 2 * m_tlbentries + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
- vtlb_load(m_vtlb, 2 * m_tlbentries + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
+ vtlb_load(2 * m_tlbentries + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
+ vtlb_load(2 * m_tlbentries + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
m_core->mode = (MODE_KERNEL << 1) | 0;
m_cache_dirty = TRUE;
@@ -969,7 +950,7 @@ bool mips3_device::memory_translate(address_spacenum spacenum, int intention, of
/* only applies to the program address space */
if (spacenum == AS_PROGRAM)
{
- const vtlb_entry *table = vtlb_table(m_vtlb);
+ const vtlb_entry *table = vtlb_table();
vtlb_entry entry = table[address >> MIPS3_MIN_PAGE_SHIFT];
if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0)
return false;
@@ -998,7 +979,7 @@ offs_t mips3_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *op
inline bool mips3_device::RBYTE(offs_t address, UINT32 *result)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1031,7 +1012,7 @@ inline bool mips3_device::RBYTE(offs_t address, UINT32 *result)
inline bool mips3_device::RHALF(offs_t address, UINT32 *result)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1064,7 +1045,7 @@ inline bool mips3_device::RHALF(offs_t address, UINT32 *result)
inline bool mips3_device::RWORD(offs_t address, UINT32 *result)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1097,7 +1078,7 @@ inline bool mips3_device::RWORD(offs_t address, UINT32 *result)
inline bool mips3_device::RWORD_MASKED(offs_t address, UINT32 *result, UINT32 mem_mask)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
*result = (*m_memory.read_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
@@ -1120,7 +1101,7 @@ inline bool mips3_device::RWORD_MASKED(offs_t address, UINT32 *result, UINT32 me
inline bool mips3_device::RDOUBLE(offs_t address, UINT64 *result)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
*result = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff));
@@ -1143,7 +1124,7 @@ inline bool mips3_device::RDOUBLE(offs_t address, UINT64 *result)
inline bool mips3_device::RDOUBLE_MASKED(offs_t address, UINT64 *result, UINT64 mem_mask)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_READ_ALLOWED)
{
*result = (*m_memory.read_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
@@ -1166,7 +1147,7 @@ inline bool mips3_device::RDOUBLE_MASKED(offs_t address, UINT64 *result, UINT64
inline void mips3_device::WBYTE(offs_t address, UINT8 data)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1200,7 +1181,7 @@ inline void mips3_device::WBYTE(offs_t address, UINT8 data)
inline void mips3_device::WHALF(offs_t address, UINT16 data)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1234,7 +1215,7 @@ inline void mips3_device::WHALF(offs_t address, UINT16 data)
inline void mips3_device::WWORD(offs_t address, UINT32 data)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
@@ -1268,7 +1249,7 @@ inline void mips3_device::WWORD(offs_t address, UINT32 data)
inline void mips3_device::WWORD_MASKED(offs_t address, UINT32 data, UINT32 mem_mask)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
(*m_memory.write_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
@@ -1292,7 +1273,7 @@ inline void mips3_device::WWORD_MASKED(offs_t address, UINT32 data, UINT32 mem_m
inline void mips3_device::WDOUBLE(offs_t address, UINT64 data)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
(*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data);
@@ -1316,7 +1297,7 @@ inline void mips3_device::WDOUBLE(offs_t address, UINT64 data)
inline void mips3_device::WDOUBLE_MASKED(offs_t address, UINT64 data, UINT64 mem_mask)
{
- const UINT32 tlbval = m_tlb_table[address >> 12];
+ const UINT32 tlbval = vtlb_table()[address >> 12];
if (tlbval & VTLB_WRITE_ALLOWED)
{
(*m_memory.write_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
diff --git a/src/devices/cpu/mips/mips3.h b/src/devices/cpu/mips/mips3.h
index 9e0de9ed419..1715861bb89 100644
--- a/src/devices/cpu/mips/mips3.h
+++ b/src/devices/cpu/mips/mips3.h
@@ -15,7 +15,7 @@
#define __MIPS3_H__
-#include "cpu/vtlb.h"
+#include "divtlb.h"
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
@@ -245,7 +245,7 @@ struct compiler_state
class mips3_frontend;
-class mips3_device : public cpu_device
+class mips3_device : public cpu_device, public device_vtlb_interface
{
friend class mips3_frontend;
@@ -355,7 +355,6 @@ private:
UINT32 m_ll_value;
UINT64 m_lld_value;
UINT32 m_badcop_value;
- const vtlb_entry *m_tlb_table;
/* endian-dependent load/store */
typedef void (mips3_device::*loadstore_func)(UINT32 op);
@@ -389,7 +388,6 @@ private:
size_t c_dcache_size;
/* MMU */
- vtlb_state * m_vtlb;
mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES];
/* fast RAM */
diff --git a/src/devices/cpu/mips/mips3com.cpp b/src/devices/cpu/mips/mips3com.cpp
index bcd6f6f349a..2fcf8de1844 100644
--- a/src/devices/cpu/mips/mips3com.cpp
+++ b/src/devices/cpu/mips/mips3com.cpp
@@ -325,8 +325,8 @@ void mips3_device::tlb_map_entry(int tlbindex)
/* the ASID doesn't match the current ASID, and if the page isn't global, unmap it from the TLB */
if (!tlb_entry_matches_asid(entry, current_asid) && !tlb_entry_is_global(entry))
{
- vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0);
- vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 1, 0, 0, 0);
return;
}
@@ -334,8 +334,8 @@ void mips3_device::tlb_map_entry(int tlbindex)
vpn = ((entry->entry_hi >> 13) & 0x07ffffff) << 1;
if (vpn >= (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
{
- vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0);
- vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(2 * tlbindex + 1, 0, 0, 0);
return;
}
@@ -369,9 +369,9 @@ void mips3_device::tlb_map_entry(int tlbindex)
/* load the virtual TLB with the corresponding entries */
if ((effvpn + count) <= (0x80000000 >> MIPS3_MIN_PAGE_SHIFT) || effvpn >= (0xc0000000 >> MIPS3_MIN_PAGE_SHIFT))
- vtlb_load(m_vtlb, 2 * tlbindex + which, count, effvpn << MIPS3_MIN_PAGE_SHIFT, (pfn << MIPS3_MIN_PAGE_SHIFT) | flags);
+ vtlb_load(2 * tlbindex + which, count, effvpn << MIPS3_MIN_PAGE_SHIFT, (pfn << MIPS3_MIN_PAGE_SHIFT) | flags);
else
- vtlb_load(m_vtlb, 2 * tlbindex + which, 0, 0, 0);
+ vtlb_load(2 * tlbindex + which, 0, 0, 0);
}
}
diff --git a/src/devices/cpu/mips/mips3com.h b/src/devices/cpu/mips/mips3com.h
index 86d7f0c7a05..20facae78d0 100644
--- a/src/devices/cpu/mips/mips3com.h
+++ b/src/devices/cpu/mips/mips3com.h
@@ -14,7 +14,6 @@
#define __MIPS3COM_H__
#include "mips3.h"
-#include "cpu/vtlb.h"
/***************************************************************************
diff --git a/src/devices/cpu/mips/mips3drc.cpp b/src/devices/cpu/mips/mips3drc.cpp
index 4e6e9771a38..7b6da3a1626 100644
--- a/src/devices/cpu/mips/mips3drc.cpp
+++ b/src/devices/cpu/mips/mips3drc.cpp
@@ -667,7 +667,7 @@ void mips3_device::static_generate_tlb_mismatch()
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
UML_SHR(block, I1, I0, 12); // shr i1,i0,12
- UML_LOAD(block, I1, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4);// load i1,[vtlb_table],i1,dword
+ UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4);// load i1,[vtlb_table],i1,dword
if (PRINTF_MMU)
{
static const char text[] = "TLB mismatch @ %08X (ent=%08X)\n";
@@ -839,7 +839,7 @@ void mips3_device::static_generate_memory_accessor(int mode, int size, int iswri
/* general case: assume paging and perform a translation */
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
- UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb_table],i3,dword
+ UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb_table],i3,dword
UML_TEST(block, I3, iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED);// test i3,iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
@@ -1226,7 +1226,7 @@ void mips3_device::generate_sequence_instruction(drcuml_block *block, compiler_s
/* validate our TLB entry at this PC; if we fail, we need to handle it */
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
{
- const vtlb_entry *tlbtable = vtlb_table(m_vtlb);
+ const vtlb_entry *tlbtable = vtlb_table();
/* if we currently have a valid TLB read entry, we just verify */
if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
diff --git a/src/devices/cpu/powerpc/ppc.h b/src/devices/cpu/powerpc/ppc.h
index 5e40ee88249..450b4ca2257 100644
--- a/src/devices/cpu/powerpc/ppc.h
+++ b/src/devices/cpu/powerpc/ppc.h
@@ -14,7 +14,7 @@
#ifndef __PPC_H__
#define __PPC_H__
-#include "cpu/vtlb.h"
+#include "divtlb.h"
#include "cpu/drcfe.h"
#include "cpu/drcuml.h"
#include "cpu/drcumlsh.h"
@@ -171,7 +171,7 @@ enum
class ppc_frontend;
-class ppc_device : public cpu_device
+class ppc_device : public cpu_device, public device_vtlb_interface
{
friend class ppc_frontend;
@@ -462,9 +462,6 @@ protected:
UINT32 m_sebr;
UINT32 m_ser;
- /* MMU */
- vtlb_state *m_vtlb;
-
/* architectural distinctions */
powerpc_flavor m_flavor;
UINT32 m_cap;
diff --git a/src/devices/cpu/powerpc/ppccom.cpp b/src/devices/cpu/powerpc/ppccom.cpp
index 9036ff2c794..a9a26b29a5c 100644
--- a/src/devices/cpu/powerpc/ppccom.cpp
+++ b/src/devices/cpu/powerpc/ppccom.cpp
@@ -209,11 +209,11 @@ const device_type PPC405GP = &device_creator<ppc405gp_device>;
ppc_device::ppc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, int address_bits, int data_bits, powerpc_flavor flavor, UINT32 cap, UINT32 tb_divisor, address_map_constructor internal_map)
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, __FILE__)
+ , device_vtlb_interface(mconfig, *this, AS_PROGRAM)
, m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map)
, c_bus_frequency(0)
, m_core(nullptr)
, m_bus_freq_multiplier(1)
- , m_vtlb(nullptr)
, m_flavor(flavor)
, m_cap(cap)
, m_tb_divisor(tb_divisor)
@@ -224,6 +224,11 @@ ppc_device::ppc_device(const machine_config &mconfig, device_type type, const ch
{
m_program_config.m_logaddr_width = 32;
m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT;
+
+ // configure the virtual TLB
+ set_vtlb_dynamic_entries(POWERPC_TLB_ENTRIES);
+ if (m_cap & PPCCAP_603_MMU)
+ set_vtlb_fixed_entries(PPC603_FIXED_TLB_ENTRIES);
}
//ppc403_device::ppc403_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
@@ -708,9 +713,6 @@ void ppc_device::device_start()
if (!(m_cap & PPCCAP_4XX) && space_config()->m_endianness != ENDIANNESS_NATIVE)
m_codexor = 4;
- /* allocate the virtual TLB */
- m_vtlb = vtlb_alloc(this, AS_PROGRAM, (m_cap & PPCCAP_603_MMU) ? PPC603_FIXED_TLB_ENTRIES : 0, POWERPC_TLB_ENTRIES);
-
/* allocate a timer for the compare interrupt */
if ((m_cap & PPCCAP_OEA) && (m_tb_divisor))
m_decrementer_int_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ppc_device::decrementer_int_callback), this));
@@ -1148,9 +1150,6 @@ void ppc_device::state_string_export(const device_state_entry &entry, std::strin
void ppc_device::device_stop()
{
- if (m_vtlb != nullptr)
- vtlb_free(m_vtlb);
- m_vtlb = nullptr;
}
@@ -1199,12 +1198,11 @@ void ppc_device::device_reset()
m_core->irq_pending = 0;
/* flush the TLB */
- vtlb_flush_dynamic(m_vtlb);
if (m_cap & PPCCAP_603_MMU)
{
for (int tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++)
{
- vtlb_load(m_vtlb, tlbindex, 0, 0, 0);
+ vtlb_load(tlbindex, 0, 0, 0);
}
}
@@ -1385,7 +1383,7 @@ UINT32 ppc_device::ppccom_translate_address_internal(int intention, offs_t &addr
/* if we're simulating the 603 MMU, fill in the data and stop here */
if (m_cap & PPCCAP_603_MMU)
{
- UINT32 entry = vtlb_table(m_vtlb)[address >> 12];
+ UINT32 entry = vtlb_table()[address >> 12];
m_core->mmu603_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f);
m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask);
m_core->mmu603_hash[1] = hashbase | ((~hash << 6) & hashmask);
@@ -1465,7 +1463,7 @@ bool ppc_device::memory_translate(address_spacenum spacenum, int intention, offs
void ppc_device::ppccom_tlb_fill()
{
- vtlb_fill(m_vtlb, m_core->param0, m_core->param1);
+ vtlb_fill(m_core->param0, m_core->param1);
}
@@ -1476,7 +1474,7 @@ void ppc_device::ppccom_tlb_fill()
void ppc_device::ppccom_tlb_flush()
{
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
}
@@ -1492,7 +1490,7 @@ void ppc_device::ppccom_tlb_flush()
void ppc_device::ppccom_execute_tlbie()
{
- vtlb_flush_address(m_vtlb, m_core->param0);
+ vtlb_flush_address(m_core->param0);
}
@@ -1503,7 +1501,7 @@ void ppc_device::ppccom_execute_tlbie()
void ppc_device::ppccom_execute_tlbia()
{
- vtlb_flush_dynamic(m_vtlb);
+ vtlb_flush_dynamic();
}
@@ -1530,7 +1528,7 @@ void ppc_device::ppccom_execute_tlbl()
flags |= VTLB_FETCH_ALLOWED;
/* load the entry */
- vtlb_load(m_vtlb, entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags);
+ vtlb_load(entrynum, 1, address, (m_core->spr[SPR603_RPA] & 0xfffff000) | flags);
}
diff --git a/src/devices/cpu/powerpc/ppcdrc.cpp b/src/devices/cpu/powerpc/ppcdrc.cpp
index ed502d344de..35b984d240d 100644
--- a/src/devices/cpu/powerpc/ppcdrc.cpp
+++ b/src/devices/cpu/powerpc/ppcdrc.cpp
@@ -743,11 +743,11 @@ void ppc_device::static_generate_tlb_mismatch()
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
UML_SHR(block, I1, I0, 12); // shr i1,i0,12
- UML_LOAD(block, I2, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword
+ UML_LOAD(block, I2, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i2,[vtlb],i1,dword
UML_MOV(block, mem(&m_core->param0), I0); // mov [param0],i0
UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH
UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
- UML_LOAD(block, I1, (void *)vtlb_table(m_vtlb), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword
+ UML_LOAD(block, I1, (void *)vtlb_table(), I1, SIZE_DWORD, SCALE_x4); // load i1,[vtlb],i1,dword
UML_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z
UML_CMP(block, I2, 0); // cmp i2,0
@@ -1021,7 +1021,7 @@ void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite
if (((m_cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (m_cap & PPCCAP_4XX) && (mode & MODE_PROTECTION)))
{
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
- UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword
+ UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword
UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_LABEL(block, tlbreturn = label++); // tlbreturn:
@@ -1338,7 +1338,7 @@ void ppc_device::static_generate_memory_accessor(int mode, int size, int iswrite
UML_MOV(block, mem(&m_core->param1), translate_type); // mov [param1],translate_type
UML_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
- UML_LOAD(block, I3, (void *)vtlb_table(m_vtlb), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword
+ UML_LOAD(block, I3, (void *)vtlb_table(), I3, SIZE_DWORD, SCALE_x4);// load i3,[vtlb],i3,dword
UML_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type
UML_JMPc(block, COND_NZ, tlbreturn); // jmp tlbreturn,nz
@@ -1703,7 +1703,7 @@ void ppc_device::generate_sequence_instruction(drcuml_block *block, compiler_sta
/* validate our TLB entry at this PC; if we fail, we need to handle it */
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (m_core->mode & MODE_DATA_TRANSLATION))
{
- const vtlb_entry *tlbtable = vtlb_table(m_vtlb);
+ const vtlb_entry *tlbtable = vtlb_table();
/* if we currently have a valid TLB read entry, we just verify */
if (tlbtable[desc->pc >> 12] != 0)
diff --git a/src/devices/cpu/vtlb.cpp b/src/devices/cpu/vtlb.cpp
deleted file mode 100644
index 4c9a9a2f311..00000000000
--- a/src/devices/cpu/vtlb.cpp
+++ /dev/null
@@ -1,310 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- vtlb.c
-
- Generic virtual TLB implementation.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "vtlb.h"
-
-
-
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
-
-#define PRINTF_TLB (0)
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* VTLB state */
-struct vtlb_state
-{
- cpu_device * cpudevice; /* CPU device */
- address_spacenum space; /* address space */
- int dynamic; /* number of dynamic entries */
- int fixed; /* number of fixed entries */
- int dynindex; /* index of next dynamic entry */
- int pageshift; /* bits to shift to get page index */
- int addrwidth; /* logical address bus width */
- std::vector<offs_t> live; /* array of live entries by table index */
- std::vector<int> fixedpages; /* number of pages each fixed entry covers */
- std::vector<vtlb_entry> table; /* table of entries by address */
-};
-
-
-
-/***************************************************************************
- INITIALIZATION/TEARDOWN
-***************************************************************************/
-
-/*-------------------------------------------------
- vtlb_alloc - allocate a new VTLB for the
- given CPU
--------------------------------------------------*/
-
-vtlb_state *vtlb_alloc(device_t *cpu, address_spacenum space, int fixed_entries, int dynamic_entries)
-{
- vtlb_state *vtlb;
-
- /* allocate memory for the core structure */
- vtlb = auto_alloc_clear(cpu->machine(), <vtlb_state>());
-
- /* fill in CPU information */
- vtlb->cpudevice = downcast<cpu_device *>(cpu);
- vtlb->space = space;
- vtlb->dynamic = dynamic_entries;
- vtlb->fixed = fixed_entries;
- const address_space_config *spaceconfig = device_get_space_config(*cpu, space);
- assert(spaceconfig != nullptr);
- vtlb->pageshift = spaceconfig->m_page_shift;
- vtlb->addrwidth = spaceconfig->m_logaddr_width;
-
- /* validate CPU information */
- assert((1 << vtlb->pageshift) > VTLB_FLAGS_MASK);
- assert(vtlb->addrwidth > vtlb->pageshift);
-
- /* allocate the entry array */
- vtlb->live.resize(fixed_entries + dynamic_entries);
- memset(&vtlb->live[0], 0, vtlb->live.size()*sizeof(vtlb->live[0]));
- cpu->save_item(NAME(vtlb->live));
-
- /* allocate the lookup table */
- vtlb->table.resize((size_t) 1 << (vtlb->addrwidth - vtlb->pageshift));
- memset(&vtlb->table[0], 0, vtlb->table.size()*sizeof(vtlb->table[0]));
- cpu->save_item(NAME(vtlb->table));
-
- /* allocate the fixed page count array */
- if (fixed_entries > 0)
- {
- vtlb->fixedpages.resize(fixed_entries);
- memset(&vtlb->fixedpages[0], 0, fixed_entries*sizeof(vtlb->fixedpages[0]));
- cpu->save_item(NAME(vtlb->fixedpages));
- }
- return vtlb;
-}
-
-
-/*-------------------------------------------------
- vtlb_free - free an allocated VTLB
--------------------------------------------------*/
-
-void vtlb_free(vtlb_state *vtlb)
-{
- auto_free(vtlb->cpudevice->machine(), vtlb);
-}
-
-
-
-/***************************************************************************
- FILLING
-***************************************************************************/
-
-/*-------------------------------------------------
- vtlb_fill - rcalled by the CPU core in
- response to an unmapped access
--------------------------------------------------*/
-
-int vtlb_fill(vtlb_state *vtlb, offs_t address, int intention)
-{
- offs_t tableindex = address >> vtlb->pageshift;
- vtlb_entry entry = vtlb->table[tableindex];
- offs_t taddress;
-
- if (PRINTF_TLB)
- printf("vtlb_fill: %08X(%X) ... ", address, intention);
-
- /* should not be called here if the entry is in the table already */
-// assert((entry & (1 << intention)) == 0);
-
- /* if we have no dynamic entries, we always fail */
- if (vtlb->dynamic == 0)
- {
- if (PRINTF_TLB)
- printf("failed: no dynamic entries\n");
- return FALSE;
- }
-
- /* ask the CPU core to translate for us */
- taddress = address;
- if (!vtlb->cpudevice->translate(vtlb->space, intention, taddress))
- {
- if (PRINTF_TLB)
- printf("failed: no translation\n");
- return FALSE;
- }
-
- /* if this is the first successful translation for this address, allocate a new entry */
- if ((entry & VTLB_FLAGS_MASK) == 0)
- {
- int liveindex = vtlb->dynindex++ % vtlb->dynamic;
-
- /* if an entry already exists at this index, free it */
- if (vtlb->live[liveindex] != 0)
- vtlb->table[vtlb->live[liveindex] - 1] = 0;
-
- /* claim this new entry */
- vtlb->live[liveindex] = tableindex + 1;
-
- /* form a new blank entry */
- entry = (taddress >> vtlb->pageshift) << vtlb->pageshift;
- entry |= VTLB_FLAG_VALID;
-
- if (PRINTF_TLB)
- printf("success (%08X), new entry\n", taddress);
- }
-
- /* otherwise, ensure that different intentions do not produce different addresses */
- else
- {
- assert((entry >> vtlb->pageshift) == (taddress >> vtlb->pageshift));
- assert(entry & VTLB_FLAG_VALID);
-
- if (PRINTF_TLB)
- printf("success (%08X), existing entry\n", taddress);
- }
-
- /* add the intention to the list of valid intentions and store */
- entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK));
- vtlb->table[tableindex] = entry;
- return TRUE;
-}
-
-
-/*-------------------------------------------------
- vtlb_load - load a fixed VTLB entry
--------------------------------------------------*/
-
-void vtlb_load(vtlb_state *vtlb, int entrynum, int numpages, offs_t address, vtlb_entry value)
-{
- offs_t tableindex = address >> vtlb->pageshift;
- int liveindex = vtlb->dynamic + entrynum;
- int pagenum;
-
- /* must be in range */
- assert(entrynum >= 0 && entrynum < vtlb->fixed);
-
- if (PRINTF_TLB)
- printf("vtlb_load %d for %d pages at %08X == %08X\n", entrynum, numpages, address, value);
-
- /* if an entry already exists at this index, free it */
- if (vtlb->live[liveindex] != 0)
- {
- int pagecount = vtlb->fixedpages[entrynum];
- int oldtableindex = vtlb->live[liveindex] - 1;
- for (pagenum = 0; pagenum < pagecount; pagenum++)
- vtlb->table[oldtableindex + pagenum] = 0;
- }
-
- /* claim this new entry */
- vtlb->live[liveindex] = tableindex + 1;
-
- /* store the raw value, making sure the "fixed" flag is set */
- value |= VTLB_FLAG_FIXED;
- vtlb->fixedpages[entrynum] = numpages;
- for (pagenum = 0; pagenum < numpages; pagenum++)
- vtlb->table[tableindex + pagenum] = value + (pagenum << vtlb->pageshift);
-}
-
-/*-------------------------------------------------
- vtlb_dynload - load a dynamic VTLB entry
--------------------------------------------------*/
-
-void vtlb_dynload(vtlb_state *vtlb, UINT32 index, offs_t address, vtlb_entry value)
-{
- vtlb_entry entry = vtlb->table[index];
-
- if (vtlb->dynamic == 0)
- {
- if (PRINTF_TLB)
- printf("failed: no dynamic entries\n");
- return;
- }
-
- int liveindex = vtlb->dynindex++ % vtlb->dynamic;
- /* is entry already live? */
- if (!(entry & VTLB_FLAG_VALID))
- {
- /* if an entry already exists at this index, free it */
- if (vtlb->live[liveindex] != 0)
- vtlb->table[vtlb->live[liveindex] - 1] = 0;
-
- /* claim this new entry */
- vtlb->live[liveindex] = index + 1;
- }
- /* form a new blank entry */
- entry = (address >> vtlb->pageshift) << vtlb->pageshift;
- entry |= VTLB_FLAG_VALID | value;
-
- if (PRINTF_TLB)
- printf("success (%08X), new entry\n", address);
-
- vtlb->table[index] = entry;
-}
-
-/***************************************************************************
- FLUSHING
-***************************************************************************/
-
-/*-------------------------------------------------
- vtlb_flush_dynamic - flush all knowledge
- from the dynamic part of the VTLB
--------------------------------------------------*/
-
-void vtlb_flush_dynamic(vtlb_state *vtlb)
-{
- int liveindex;
-
- if (PRINTF_TLB)
- printf("vtlb_flush_dynamic\n");
-
- /* loop over live entries and release them from the table */
- for (liveindex = 0; liveindex < vtlb->dynamic; liveindex++)
- if (vtlb->live[liveindex] != 0)
- {
- offs_t tableindex = vtlb->live[liveindex] - 1;
- vtlb->table[tableindex] = 0;
- vtlb->live[liveindex] = 0;
- }
-}
-
-
-/*-------------------------------------------------
- vtlb_flush_address - flush knowledge of a
- particular address from the VTLB
--------------------------------------------------*/
-
-void vtlb_flush_address(vtlb_state *vtlb, offs_t address)
-{
- offs_t tableindex = address >> vtlb->pageshift;
-
- if (PRINTF_TLB)
- printf("vtlb_flush_address %08X\n", address);
-
- /* free the entry in the table; for speed, we leave the entry in the live array */
- vtlb->table[tableindex] = 0;
-}
-
-
-
-/***************************************************************************
- ACCESSORS
-***************************************************************************/
-
-/*-------------------------------------------------
- vtlb_table - return a pointer to the base of
- the linear VTLB lookup table
--------------------------------------------------*/
-
-const vtlb_entry *vtlb_table(vtlb_state *vtlb)
-{
- return &vtlb->table[0];
-}
diff --git a/src/devices/cpu/vtlb.h b/src/devices/cpu/vtlb.h
deleted file mode 100644
index f63a0ac50f6..00000000000
--- a/src/devices/cpu/vtlb.h
+++ /dev/null
@@ -1,88 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- vtlb.h
-
- Generic virtual TLB implementation.
-
-***************************************************************************/
-
-#pragma once
-
-#ifndef __VTLB_H__
-#define __VTLB_H__
-
-
-
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-#define VTLB_FLAGS_MASK 0xff
-
-#define VTLB_READ_ALLOWED 0x01 /* (1 << TRANSLATE_READ) */
-#define VTLB_WRITE_ALLOWED 0x02 /* (1 << TRANSLATE_WRITE) */
-#define VTLB_FETCH_ALLOWED 0x04 /* (1 << TRANSLATE_FETCH) */
-#define VTLB_FLAG_VALID 0x08
-#define VTLB_USER_READ_ALLOWED 0x10 /* (1 << TRANSLATE_READ_USER) */
-#define VTLB_USER_WRITE_ALLOWED 0x20 /* (1 << TRANSLATE_WRITE_USER) */
-#define VTLB_USER_FETCH_ALLOWED 0x40 /* (1 << TRANSLATE_FETCH_USER) */
-#define VTLB_FLAG_FIXED 0x80
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-/* represents an entry in the VTLB */
-typedef UINT32 vtlb_entry;
-
-
-/* opaque structure describing VTLB state */
-struct vtlb_state;
-
-
-
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-
-/* ----- initialization/teardown ----- */
-
-/* allocate a new VTLB for the given CPU */
-vtlb_state *vtlb_alloc(device_t *cpu, address_spacenum space, int fixed_entries, int dynamic_entries);
-
-/* free an allocated VTLB */
-void vtlb_free(vtlb_state *vtlb);
-
-
-/* ----- filling ----- */
-
-/* called by the CPU core in response to an unmapped access */
-int vtlb_fill(vtlb_state *vtlb, offs_t address, int intention);
-
-/* load a fixed VTLB entry */
-void vtlb_load(vtlb_state *vtlb, int entrynum, int numpages, offs_t address, vtlb_entry value);
-
-/* load a dynamic VTLB entry */
-void vtlb_dynload(vtlb_state *vtlb, UINT32 index, offs_t address, vtlb_entry value);
-
-/* ----- flushing ----- */
-
-/* flush all knowledge from the dynamic part of the VTLB */
-void vtlb_flush_dynamic(vtlb_state *vtlb);
-
-/* flush knowledge of a particular address from the VTLB */
-void vtlb_flush_address(vtlb_state *vtlb, offs_t address);
-
-
-/* ----- accessors ----- */
-
-/* return a pointer to the base of the linear VTLB lookup table */
-const vtlb_entry *vtlb_table(vtlb_state *vtlb);
-
-
-#endif /* __VTLB_H__ */
diff --git a/src/emu/dimemory.h b/src/emu/dimemory.h
index 66561b5a5cf..0998fd4ae9a 100644
--- a/src/emu/dimemory.h
+++ b/src/emu/dimemory.h
@@ -131,22 +131,4 @@ typedef device_interface_iterator<device_memory_interface> memory_interface_iter
-//**************************************************************************
-// INLINE HELPERS
-//**************************************************************************
-
-//-------------------------------------------------
-// device_get_space_config - return a pointer
-// to sthe given address space's configuration
-//-------------------------------------------------
-
-inline const address_space_config *device_get_space_config(const device_t &device, address_spacenum spacenum = AS_0)
-{
- const device_memory_interface *intf;
- if (!device.interface(intf))
- throw emu_fatalerror("Device '%s' does not have memory interface", device.tag());
- return intf->space_config(spacenum);
-}
-
-
#endif /* __DIMEMORY_H__ */
diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp
new file mode 100644
index 00000000000..01be30919cb
--- /dev/null
+++ b/src/emu/divtlb.cpp
@@ -0,0 +1,341 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ divtlb.c
+
+ Device generic virtual TLB interface.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "divtlb.h"
+#include "validity.h"
+
+
+
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
+
+#define PRINTF_TLB (0)
+
+
+
+//**************************************************************************
+// DEVICE VTLB INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_vtlb_interface - constructor
+//-------------------------------------------------
+
+device_vtlb_interface::device_vtlb_interface(const machine_config &mconfig, device_t &device, address_spacenum space)
+ : device_interface(device, "vtlb"),
+ m_space(space),
+ m_dynamic(0),
+ m_fixed(0),
+ m_dynindex(0),
+ m_pageshift(0),
+ m_addrwidth(0)
+{
+}
+
+
+//-------------------------------------------------
+// device_vtlb_interface - destructor
+//-------------------------------------------------
+
+device_vtlb_interface::~device_vtlb_interface()
+{
+}
+
+
+//-------------------------------------------------
+// interface_validity_check - validation for a
+// device after the configuration has been
+// constructed
+//-------------------------------------------------
+
+void device_vtlb_interface::interface_validity_check(validity_checker &valid) const
+{
+ const device_memory_interface *intf;
+ if (!device().interface(intf))
+ osd_printf_error("Device does not have memory interface\n");
+ else
+ {
+ // validate CPU information
+ const address_space_config *spaceconfig = intf->space_config(m_space);
+ if (spaceconfig == nullptr)
+ osd_printf_error("No memory address space configuration found for space %d\n", m_space);
+ else if ((1 << spaceconfig->m_page_shift) <= VTLB_FLAGS_MASK || spaceconfig->m_logaddr_width <= spaceconfig->m_page_shift)
+ osd_printf_error("Invalid page shift %d for VTLB\n", spaceconfig->m_page_shift);
+ }
+}
+
+
+//-------------------------------------------------
+// interface_pre_start - work to be done prior to
+// actually starting a device
+//-------------------------------------------------
+
+void device_vtlb_interface::interface_pre_start()
+{
+ // fill in CPU information
+ const address_space_config *spaceconfig = device().memory().space_config(m_space);
+ m_pageshift = spaceconfig->m_page_shift;
+ m_addrwidth = spaceconfig->m_logaddr_width;
+
+ // allocate the entry array
+ m_live.resize(m_fixed + m_dynamic);
+ memset(&m_live[0], 0, m_live.size()*sizeof(m_live[0]));
+
+ // allocate the lookup table
+ m_table.resize((size_t) 1 << (m_addrwidth - m_pageshift));
+ memset(&m_table[0], 0, m_table.size()*sizeof(m_table[0]));
+
+ // allocate the fixed page count array
+ if (m_fixed > 0)
+ {
+ m_fixedpages.resize(m_fixed);
+ memset(&m_fixedpages[0], 0, m_fixed*sizeof(m_fixedpages[0]));
+ }
+}
+
+
+//-------------------------------------------------
+// interface_post_start - work to be done after
+// actually starting a device
+//-------------------------------------------------
+
+void device_vtlb_interface::interface_post_start()
+{
+ device().save_item(NAME(m_live));
+ device().save_item(NAME(m_table));
+ if (m_fixed > 0)
+ device().save_item(NAME(m_fixedpages));
+}
+
+
+//-------------------------------------------------
+// interface_pre_reset - work to be done prior to
+// actually resetting a device
+//-------------------------------------------------
+
+void device_vtlb_interface::interface_pre_reset()
+{
+ vtlb_flush_dynamic();
+}
+
+
+//**************************************************************************
+// FILLING
+//**************************************************************************
+
+//-------------------------------------------------
+// vtlb_fill - called by the CPU core in
+// response to an unmapped access
+//-------------------------------------------------
+
+int device_vtlb_interface::vtlb_fill(offs_t address, int intention)
+{
+ offs_t tableindex = address >> m_pageshift;
+ vtlb_entry entry = m_table[tableindex];
+ offs_t taddress;
+
+#if PRINTF_TLB
+ osd_printf_debug("vtlb_fill: %08X(%X) ... ", address, intention);
+#endif
+
+ // should not be called here if the entry is in the table already
+// assert((entry & (1 << intention)) == 0);
+
+ // if we have no dynamic entries, we always fail
+ if (m_dynamic == 0)
+ {
+#if PRINTF_TLB
+ osd_printf_debug("failed: no dynamic entries\n");
+#endif
+ return FALSE;
+ }
+
+ // ask the CPU core to translate for us
+ taddress = address;
+ if (!device().memory().translate(m_space, intention, taddress))
+ {
+#if PRINTF_TLB
+ osd_printf_debug("failed: no translation\n");
+#endif
+ return FALSE;
+ }
+
+ // if this is the first successful translation for this address, allocate a new entry
+ if ((entry & VTLB_FLAGS_MASK) == 0)
+ {
+ int liveindex = m_dynindex++ % m_dynamic;
+
+ // if an entry already exists at this index, free it
+ if (m_live[liveindex] != 0)
+ m_table[m_live[liveindex] - 1] = 0;
+
+ // claim this new entry
+ m_live[liveindex] = tableindex + 1;
+
+ // form a new blank entry
+ entry = (taddress >> m_pageshift) << m_pageshift;
+ entry |= VTLB_FLAG_VALID;
+
+#if PRINTF_TLB
+ osd_printf_debug("success (%08X), new entry\n", taddress);
+#endif
+ }
+
+ // otherwise, ensure that different intentions do not produce different addresses
+ else
+ {
+ assert((entry >> m_pageshift) == (taddress >> m_pageshift));
+ assert(entry & VTLB_FLAG_VALID);
+
+#if PRINTF_TLB
+ osd_printf_debug("success (%08X), existing entry\n", taddress);
+#endif
+ }
+
+ // add the intention to the list of valid intentions and store
+ entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK));
+ m_table[tableindex] = entry;
+ return TRUE;
+}
+
+
+//-------------------------------------------------
+// vtlb_load - load a fixed VTLB entry
+//-------------------------------------------------
+
+void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value)
+{
+ offs_t tableindex = address >> m_pageshift;
+ int liveindex = m_dynamic + entrynum;
+ int pagenum;
+
+ // must be in range
+ assert(entrynum >= 0 && entrynum < m_fixed);
+
+#if PRINTF_TLB
+ osd_printf_debug("vtlb_load %d for %d pages at %08X == %08X\n", entrynum, numpages, address, value);
+#endif
+
+ // if an entry already exists at this index, free it
+ if (m_live[liveindex] != 0)
+ {
+ int pagecount = m_fixedpages[entrynum];
+ int oldtableindex = m_live[liveindex] - 1;
+ for (pagenum = 0; pagenum < pagecount; pagenum++)
+ m_table[oldtableindex + pagenum] = 0;
+ }
+
+ // claim this new entry
+ m_live[liveindex] = tableindex + 1;
+
+ // store the raw value, making sure the "fixed" flag is set
+ value |= VTLB_FLAG_FIXED;
+ m_fixedpages[entrynum] = numpages;
+ for (pagenum = 0; pagenum < numpages; pagenum++)
+ m_table[tableindex + pagenum] = value + (pagenum << m_pageshift);
+}
+
+//-------------------------------------------------
+// vtlb_dynload - load a dynamic VTLB entry
+//-------------------------------------------------
+
+void device_vtlb_interface::vtlb_dynload(UINT32 index, offs_t address, vtlb_entry value)
+{
+ vtlb_entry entry = m_table[index];
+
+ if (m_dynamic == 0)
+ {
+#if PRINTF_TLB
+ osd_printf_debug("failed: no dynamic entries\n");
+#endif
+ return;
+ }
+
+ int liveindex = m_dynindex++ % m_dynamic;
+ // is entry already live?
+ if (!(entry & VTLB_FLAG_VALID))
+ {
+ // if an entry already exists at this index, free it
+ if (m_live[liveindex] != 0)
+ m_table[m_live[liveindex] - 1] = 0;
+
+ // claim this new entry
+ m_live[liveindex] = index + 1;
+ }
+ // form a new blank entry
+ entry = (address >> m_pageshift) << m_pageshift;
+ entry |= VTLB_FLAG_VALID | value;
+
+#if PRINTF_TLB
+ osd_printf_debug("success (%08X), new entry\n", address);
+#endif
+ m_table[index] = entry;
+}
+
+//**************************************************************************
+// FLUSHING
+//**************************************************************************
+
+//-------------------------------------------------
+// vtlb_flush_dynamic - flush all knowledge
+// from the dynamic part of the VTLB
+//-------------------------------------------------
+
+void device_vtlb_interface::vtlb_flush_dynamic()
+{
+#if PRINTF_TLB
+ osd_printf_debug("vtlb_flush_dynamic\n");
+#endif
+
+ // loop over live entries and release them from the table
+ for (int liveindex = 0; liveindex < m_dynamic; liveindex++)
+ if (m_live[liveindex] != 0)
+ {
+ offs_t tableindex = m_live[liveindex] - 1;
+ m_table[tableindex] = 0;
+ m_live[liveindex] = 0;
+ }
+}
+
+
+//-------------------------------------------------
+// vtlb_flush_address - flush knowledge of a
+// particular address from the VTLB
+//-------------------------------------------------
+
+void device_vtlb_interface::vtlb_flush_address(offs_t address)
+{
+ offs_t tableindex = address >> m_pageshift;
+
+#if PRINTF_TLB
+ osd_printf_debug("vtlb_flush_address %08X\n", address);
+#endif
+
+ // free the entry in the table; for speed, we leave the entry in the live array
+ m_table[tableindex] = 0;
+}
+
+
+
+//**************************************************************************
+// ACCESSORS
+//**************************************************************************
+
+//-------------------------------------------------
+// vtlb_table - return a pointer to the base of
+// the linear VTLB lookup table
+//-------------------------------------------------
+
+const vtlb_entry *device_vtlb_interface::vtlb_table() const
+{
+ return &m_table[0];
+}
diff --git a/src/emu/divtlb.h b/src/emu/divtlb.h
new file mode 100644
index 00000000000..eccd2947da3
--- /dev/null
+++ b/src/emu/divtlb.h
@@ -0,0 +1,89 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ divtlb.h
+
+ Generic virtual TLB implementation.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __DIVTLB_H__
+#define __DIVTLB_H__
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define VTLB_FLAGS_MASK 0xff
+
+#define VTLB_READ_ALLOWED 0x01 /* (1 << TRANSLATE_READ) */
+#define VTLB_WRITE_ALLOWED 0x02 /* (1 << TRANSLATE_WRITE) */
+#define VTLB_FETCH_ALLOWED 0x04 /* (1 << TRANSLATE_FETCH) */
+#define VTLB_FLAG_VALID 0x08
+#define VTLB_USER_READ_ALLOWED 0x10 /* (1 << TRANSLATE_READ_USER) */
+#define VTLB_USER_WRITE_ALLOWED 0x20 /* (1 << TRANSLATE_WRITE_USER) */
+#define VTLB_USER_FETCH_ALLOWED 0x40 /* (1 << TRANSLATE_FETCH_USER) */
+#define VTLB_FLAG_FIXED 0x80
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* represents an entry in the VTLB */
+typedef UINT32 vtlb_entry;
+
+
+// ======================> device_vtlb_interface
+
+class device_vtlb_interface : public device_interface
+{
+public:
+ // construction/destruction
+ device_vtlb_interface(const machine_config &mconfig, device_t &device, address_spacenum space);
+ virtual ~device_vtlb_interface();
+
+ // configuration helpers
+ void set_vtlb_dynamic_entries(int entries) { m_dynamic = entries; }
+ void set_vtlb_fixed_entries(int entries) { m_fixed = entries; }
+
+ // filling
+ int vtlb_fill(offs_t address, int intention);
+ void vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value);
+ void vtlb_dynload(UINT32 index, offs_t address, vtlb_entry value);
+
+ // flushing
+ void vtlb_flush_dynamic();
+ void vtlb_flush_address(offs_t address);
+
+ // accessors
+ const vtlb_entry *vtlb_table() const;
+
+protected:
+ // interface-level overrides
+ virtual void interface_validity_check(validity_checker &valid) const override;
+ virtual void interface_pre_start() override;
+ virtual void interface_post_start() override;
+ virtual void interface_pre_reset() override;
+
+private:
+ // private state
+ address_spacenum m_space; // address space
+ int m_dynamic; // number of dynamic entries
+ int m_fixed; // number of fixed entries
+ int m_dynindex; // index of next dynamic entry
+ int m_pageshift; // bits to shift to get page index
+ int m_addrwidth; // logical address bus width
+ std::vector<offs_t> m_live; // array of live entries by table index
+ std::vector<int> m_fixedpages; // number of pages each fixed entry covers
+ std::vector<vtlb_entry> m_table; // table of entries by address
+};
+
+
+#endif /* __VTLB_H__ */