Merge pull request #609 from ajrhacker/vtlb

Vtlb
This commit is contained in:
Miodrag Milanović 2016-02-07 08:23:34 +01:00
commit 88efd657db
20 changed files with 529 additions and 548 deletions

View File

@ -9,14 +9,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

View File

@ -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",

View File

@ -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;

View File

@ -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();

View File

@ -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:

View File

@ -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)))

View File

@ -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:

View File

@ -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);

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -14,7 +14,6 @@
#define __MIPS3COM_H__
#include "mips3.h"
#include "cpu/vtlb.h"
/***************************************************************************

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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];
}

View File

@ -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__ */

View File

@ -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__ */

341
src/emu/divtlb.cpp Normal file
View File

@ -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];
}

89
src/emu/divtlb.h Normal file
View File

@ -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__ */