mirror of
https://github.com/holub/mame
synced 2025-06-10 06:47:18 +03:00
commit
88efd657db
@ -9,14 +9,6 @@
|
|||||||
--
|
--
|
||||||
---------------------------------------------------------------------------
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
--------------------------------------------------
|
|
||||||
-- Shared code
|
|
||||||
--------------------------------------------------
|
|
||||||
|
|
||||||
files {
|
|
||||||
MAME_DIR .. "src/devices/cpu/vtlb.cpp",
|
|
||||||
}
|
|
||||||
|
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
-- Dynamic recompiler objects
|
-- 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.cpp",
|
||||||
MAME_DIR .. "src/devices/cpu/drcbex64.h",
|
MAME_DIR .. "src/devices/cpu/drcbex64.h",
|
||||||
MAME_DIR .. "src/devices/cpu/drcumlsh.h",
|
MAME_DIR .. "src/devices/cpu/drcumlsh.h",
|
||||||
MAME_DIR .. "src/devices/cpu/vtlb.h",
|
|
||||||
MAME_DIR .. "src/devices/cpu/x86emit.h",
|
MAME_DIR .. "src/devices/cpu/x86emit.h",
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -117,6 +117,8 @@ files {
|
|||||||
MAME_DIR .. "src/emu/distate.h",
|
MAME_DIR .. "src/emu/distate.h",
|
||||||
MAME_DIR .. "src/emu/divideo.cpp",
|
MAME_DIR .. "src/emu/divideo.cpp",
|
||||||
MAME_DIR .. "src/emu/divideo.h",
|
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.cpp",
|
||||||
MAME_DIR .. "src/emu/drawgfx.h",
|
MAME_DIR .. "src/emu/drawgfx.h",
|
||||||
MAME_DIR .. "src/emu/drawgfxm.h",
|
MAME_DIR .. "src/emu/drawgfxm.h",
|
||||||
|
@ -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)
|
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__)
|
: 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_program_config("program", ENDIANNESS_LITTLE, 32, 32, 0)
|
||||||
, m_io_config("io", ENDIANNESS_LITTLE, 32, 16, 0)
|
, m_io_config("io", ENDIANNESS_LITTLE, 32, 16, 0)
|
||||||
, m_smiact(*this)
|
, m_smiact(*this)
|
||||||
{
|
{
|
||||||
m_program_config.m_logaddr_width = 32;
|
m_program_config.m_logaddr_width = 32;
|
||||||
m_program_config.m_page_shift = 12;
|
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)
|
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)
|
: 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_program_config("program", ENDIANNESS_LITTLE, program_data_width, program_addr_width, 0)
|
||||||
, m_io_config("io", ENDIANNESS_LITTLE, io_data_width, 16, 0)
|
, m_io_config("io", ENDIANNESS_LITTLE, io_data_width, 16, 0)
|
||||||
, m_smiact(*this)
|
, m_smiact(*this)
|
||||||
{
|
{
|
||||||
m_program_config.m_logaddr_width = 32;
|
m_program_config.m_logaddr_width = 32;
|
||||||
m_program_config.m_page_shift = 12;
|
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)
|
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)
|
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__)
|
: 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)
|
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)
|
: 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)
|
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_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__)
|
: 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)
|
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__)
|
: 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)
|
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__)
|
: 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)
|
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__)
|
: 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)
|
m_cr[3] = READ32(tss+0x1c); // CR3 (PDBR)
|
||||||
if(oldcr3 != m_cr[3])
|
if(oldcr3 != m_cr[3])
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
vtlb_flush_dynamic();
|
||||||
|
|
||||||
/* Set the busy bit in the new task's descriptor */
|
/* Set the busy bit in the new task's descriptor */
|
||||||
if(selector & 0x0004)
|
if(selector & 0x0004)
|
||||||
@ -3178,7 +3198,7 @@ void i386_device::i386_postload()
|
|||||||
CHANGE_PC(m_eip);
|
CHANGE_PC(m_eip);
|
||||||
}
|
}
|
||||||
|
|
||||||
void i386_device::i386_common_init(int tlbsize)
|
void i386_device::i386_common_init()
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
static const int regs8[8] = {AL,CL,DL,BL,AH,CH,DH,BH};
|
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_program = &space(AS_PROGRAM);
|
||||||
m_direct = &m_program->direct();
|
m_direct = &m_program->direct();
|
||||||
m_io = &space(AS_IO);
|
m_io = &space(AS_IO);
|
||||||
m_vtlb = vtlb_alloc(this, AS_PROGRAM, 0, tlbsize);
|
|
||||||
m_smi = false;
|
m_smi = false;
|
||||||
m_debugger_temp = 0;
|
m_debugger_temp = 0;
|
||||||
m_lock = false;
|
m_lock = false;
|
||||||
@ -3294,7 +3313,7 @@ void i386_device::i386_common_init(int tlbsize)
|
|||||||
|
|
||||||
void i386_device::device_start()
|
void i386_device::device_start()
|
||||||
{
|
{
|
||||||
i386_common_init(32);
|
i386_common_init();
|
||||||
|
|
||||||
build_opcode_table(OP_I386);
|
build_opcode_table(OP_I386);
|
||||||
m_cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386].get();
|
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()
|
void i386_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -3890,7 +3908,7 @@ void i386_device::i386_set_a20_line(int state)
|
|||||||
m_a20_mask = ~(1 << 20);
|
m_a20_mask = ~(1 << 20);
|
||||||
}
|
}
|
||||||
// TODO: how does A20M and the tlb interact
|
// TODO: how does A20M and the tlb interact
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
vtlb_flush_dynamic();
|
||||||
}
|
}
|
||||||
|
|
||||||
void i386_device::execute_run()
|
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()
|
void i486_device::device_start()
|
||||||
{
|
{
|
||||||
i386_common_init(32);
|
i386_common_init();
|
||||||
|
|
||||||
build_opcode_table(OP_I386 | OP_FPU | OP_I486);
|
build_opcode_table(OP_I386 | OP_FPU | OP_I486);
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -3989,7 +4007,6 @@ void i486_device::device_start()
|
|||||||
void i486_device::device_reset()
|
void i486_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4033,8 +4050,7 @@ void i486_device::device_reset()
|
|||||||
|
|
||||||
void pentium_device::device_start()
|
void pentium_device::device_start()
|
||||||
{
|
{
|
||||||
// 64 dtlb small, 8 dtlb large, 32 itlb
|
i386_common_init();
|
||||||
i386_common_init(96);
|
|
||||||
register_state_i386_x87();
|
register_state_i386_x87();
|
||||||
|
|
||||||
build_opcode_table(OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM);
|
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()
|
void pentium_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4107,8 +4122,7 @@ void pentium_device::device_reset()
|
|||||||
|
|
||||||
void mediagx_device::device_start()
|
void mediagx_device::device_start()
|
||||||
{
|
{
|
||||||
// probably 32 unified
|
i386_common_init();
|
||||||
i386_common_init(32);
|
|
||||||
register_state_i386_x87();
|
register_state_i386_x87();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4120,7 +4134,6 @@ void mediagx_device::device_start()
|
|||||||
void mediagx_device::device_reset()
|
void mediagx_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4172,8 +4185,7 @@ void mediagx_device::device_reset()
|
|||||||
|
|
||||||
void pentium_pro_device::device_start()
|
void pentium_pro_device::device_start()
|
||||||
{
|
{
|
||||||
// 64 dtlb small, 32 itlb
|
i386_common_init();
|
||||||
i386_common_init(96);
|
|
||||||
register_state_i386_x87();
|
register_state_i386_x87();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4185,7 +4197,6 @@ void pentium_pro_device::device_start()
|
|||||||
void pentium_pro_device::device_reset()
|
void pentium_pro_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4247,8 +4258,7 @@ void pentium_pro_device::device_reset()
|
|||||||
|
|
||||||
void pentium_mmx_device::device_start()
|
void pentium_mmx_device::device_start()
|
||||||
{
|
{
|
||||||
// 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
|
i386_common_init();
|
||||||
i386_common_init(96);
|
|
||||||
register_state_i386_x87();
|
register_state_i386_x87();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4260,7 +4270,6 @@ void pentium_mmx_device::device_start()
|
|||||||
void pentium_mmx_device::device_reset()
|
void pentium_mmx_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4320,8 +4329,7 @@ void pentium_mmx_device::device_reset()
|
|||||||
|
|
||||||
void pentium2_device::device_start()
|
void pentium2_device::device_start()
|
||||||
{
|
{
|
||||||
// 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
|
i386_common_init();
|
||||||
i386_common_init(96);
|
|
||||||
register_state_i386_x87();
|
register_state_i386_x87();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4333,7 +4341,6 @@ void pentium2_device::device_start()
|
|||||||
void pentium2_device::device_reset()
|
void pentium2_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4387,8 +4394,7 @@ void pentium2_device::device_reset()
|
|||||||
|
|
||||||
void pentium3_device::device_start()
|
void pentium3_device::device_start()
|
||||||
{
|
{
|
||||||
// 64 dtlb small, 8 dtlb large, 32 itlb small, 2 itlb large
|
i386_common_init();
|
||||||
i386_common_init(96);
|
|
||||||
register_state_i386_x87_xmm();
|
register_state_i386_x87_xmm();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4400,7 +4406,6 @@ void pentium3_device::device_start()
|
|||||||
void pentium3_device::device_reset()
|
void pentium3_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
@ -4456,8 +4461,7 @@ void pentium3_device::device_reset()
|
|||||||
|
|
||||||
void pentium4_device::device_start()
|
void pentium4_device::device_start()
|
||||||
{
|
{
|
||||||
// 128 dtlb, 64 itlb
|
i386_common_init();
|
||||||
i386_common_init(196);
|
|
||||||
register_state_i386_x87_xmm();
|
register_state_i386_x87_xmm();
|
||||||
|
|
||||||
build_x87_opcode_table();
|
build_x87_opcode_table();
|
||||||
@ -4469,7 +4473,6 @@ void pentium4_device::device_start()
|
|||||||
void pentium4_device::device_reset()
|
void pentium4_device::device_reset()
|
||||||
{
|
{
|
||||||
zero_state();
|
zero_state();
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
|
|
||||||
m_sreg[CS].selector = 0xf000;
|
m_sreg[CS].selector = 0xf000;
|
||||||
m_sreg[CS].base = 0xffff0000;
|
m_sreg[CS].base = 0xffff0000;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
#include "softfloat/milieu.h"
|
#include "softfloat/milieu.h"
|
||||||
#include "softfloat/softfloat.h"
|
#include "softfloat/softfloat.h"
|
||||||
#include "debug/debugcpu.h"
|
#include "debug/debugcpu.h"
|
||||||
#include "cpu/vtlb.h"
|
#include "divtlb.h"
|
||||||
|
|
||||||
|
|
||||||
#define INPUT_LINE_A20 1
|
#define INPUT_LINE_A20 1
|
||||||
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#define X86_NUM_CPUS 4
|
#define X86_NUM_CPUS 4
|
||||||
|
|
||||||
class i386_device : public cpu_device
|
class i386_device : public cpu_device, public device_vtlb_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// construction/destruction
|
// construction/destruction
|
||||||
@ -270,8 +270,6 @@ struct I386_CALL_GATE
|
|||||||
UINT8 *m_cycle_table_pm;
|
UINT8 *m_cycle_table_pm;
|
||||||
UINT8 *m_cycle_table_rm;
|
UINT8 *m_cycle_table_rm;
|
||||||
|
|
||||||
vtlb_state *m_vtlb;
|
|
||||||
|
|
||||||
bool m_smm;
|
bool m_smm;
|
||||||
bool m_smi;
|
bool m_smi;
|
||||||
bool m_smi_latched;
|
bool m_smi_latched;
|
||||||
@ -1411,7 +1409,7 @@ struct I386_CALL_GATE
|
|||||||
void build_x87_opcode_table_df();
|
void build_x87_opcode_table_df();
|
||||||
void build_x87_opcode_table();
|
void build_x87_opcode_table();
|
||||||
void i386_postload();
|
void i386_postload();
|
||||||
void i386_common_init(int tlbsize);
|
void i386_common_init();
|
||||||
void build_opcode_table(UINT32 features);
|
void build_opcode_table(UINT32 features);
|
||||||
void pentium_smi();
|
void pentium_smi();
|
||||||
void zero_state();
|
void zero_state();
|
||||||
|
@ -701,7 +701,7 @@ void i386_device::i386_mov_cr_r32() // Opcode 0x0f 22
|
|||||||
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
|
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
|
||||||
case 3:
|
case 3:
|
||||||
CYCLES(CYCLES_MOV_REG_CR3);
|
CYCLES(CYCLES_MOV_REG_CR3);
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
vtlb_flush_dynamic();
|
||||||
break;
|
break;
|
||||||
case 4: CYCLES(1); break; // TODO
|
case 4: CYCLES(1); break; // TODO
|
||||||
default:
|
default:
|
||||||
|
@ -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
|
if(!(m_cr[0] & 0x80000000)) // Some (very few) old OS's won't work with this
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
const vtlb_entry *table = vtlb_table(m_vtlb);
|
const vtlb_entry *table = vtlb_table();
|
||||||
UINT32 index = *address >> 12;
|
UINT32 index = *address >> 12;
|
||||||
vtlb_entry entry = table[index];
|
vtlb_entry entry = table[index];
|
||||||
if(type == TRANSLATE_FETCH)
|
if(type == TRANSLATE_FETCH)
|
||||||
@ -506,7 +506,7 @@ int i386_device::translate_address(int pl, int type, UINT32 *address, UINT32 *er
|
|||||||
*error |= 1;
|
*error |= 1;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
vtlb_dynload(m_vtlb, index, *address, entry);
|
vtlb_dynload(index, *address, entry);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if(!(entry & (1 << type)))
|
if(!(entry & (1 << type)))
|
||||||
|
@ -312,7 +312,7 @@ void i386_device::i486_group0F01_16() // Opcode 0x0f 01
|
|||||||
}
|
}
|
||||||
ea = GetEA(modrm,-1);
|
ea = GetEA(modrm,-1);
|
||||||
CYCLES(25); // TODO: add to cycles.h
|
CYCLES(25); // TODO: add to cycles.h
|
||||||
vtlb_flush_address(m_vtlb, ea);
|
vtlb_flush_address(ea);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -430,7 +430,7 @@ void i386_device::i486_group0F01_32() // Opcode 0x0f 01
|
|||||||
}
|
}
|
||||||
ea = GetEA(modrm,-1);
|
ea = GetEA(modrm,-1);
|
||||||
CYCLES(25); // TODO: add to cycles.h
|
CYCLES(25); // TODO: add to cycles.h
|
||||||
vtlb_flush_address(m_vtlb, ea);
|
vtlb_flush_address(ea);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -500,12 +500,12 @@ void i386_device::i486_mov_cr_r32() // Opcode 0x0f 22
|
|||||||
case 0:
|
case 0:
|
||||||
CYCLES(CYCLES_MOV_REG_CR0);
|
CYCLES(CYCLES_MOV_REG_CR0);
|
||||||
if((oldcr ^ m_cr[cr]) & 0x80010000)
|
if((oldcr ^ m_cr[cr]) & 0x80010000)
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
vtlb_flush_dynamic();
|
||||||
break;
|
break;
|
||||||
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
|
case 2: CYCLES(CYCLES_MOV_REG_CR2); break;
|
||||||
case 3:
|
case 3:
|
||||||
CYCLES(CYCLES_MOV_REG_CR3);
|
CYCLES(CYCLES_MOV_REG_CR3);
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
vtlb_flush_dynamic();
|
||||||
break;
|
break;
|
||||||
case 4: CYCLES(1); break; // TODO
|
case 4: CYCLES(1); break; // TODO
|
||||||
default:
|
default:
|
||||||
|
@ -120,8 +120,10 @@ const device_type RM7000BE = &device_creator<rm7000be_device>;
|
|||||||
const device_type RM7000LE = &device_creator<rm7000le_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)
|
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__)
|
: 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_program_config("program", endianness, 32, 32, 0, 32, MIPS3_MIN_PAGE_SHIFT)
|
||||||
, m_flavor(flavor)
|
, m_flavor(flavor)
|
||||||
, m_core(nullptr)
|
, m_core(nullptr)
|
||||||
@ -134,7 +136,6 @@ mips3_device::mips3_device(const machine_config &mconfig, device_type type, cons
|
|||||||
, m_ll_value(0)
|
, m_ll_value(0)
|
||||||
, m_lld_value(0)
|
, m_lld_value(0)
|
||||||
, m_badcop_value(0)
|
, m_badcop_value(0)
|
||||||
, m_tlb_table(nullptr)
|
|
||||||
, m_lwl(endianness == ENDIANNESS_BIG ? &mips3_device::lwl_be : &mips3_device::lwl_le)
|
, 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_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)
|
, 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_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)
|
, m_sdr(endianness == ENDIANNESS_BIG ? &mips3_device::sdr_be : &mips3_device::sdr_le)
|
||||||
, c_system_clock(0)
|
, c_system_clock(0)
|
||||||
, m_pfnmask(0)
|
, m_pfnmask(flavor == MIPS3_TYPE_VR4300 ? 0x000fffff : 0x00ffffff)
|
||||||
, m_tlbentries(0)
|
, m_tlbentries(flavor == MIPS3_TYPE_VR4300 ? 32 : MIPS3_MAX_TLB_ENTRIES)
|
||||||
, m_bigendian(endianness == ENDIANNESS_BIG)
|
, m_bigendian(endianness == ENDIANNESS_BIG)
|
||||||
, m_byte_xor(m_bigendian ? BYTE4_XOR_BE(0) : BYTE4_XOR_LE(0))
|
, 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))
|
, m_word_xor(m_bigendian ? WORD_XOR_BE(0) : WORD_XOR_LE(0))
|
||||||
, c_icache_size(0)
|
, c_icache_size(0)
|
||||||
, c_dcache_size(0)
|
, c_dcache_size(0)
|
||||||
, m_vtlb(nullptr)
|
|
||||||
, m_fastram_select(0)
|
, m_fastram_select(0)
|
||||||
, m_debugger_temp(0)
|
, m_debugger_temp(0)
|
||||||
, m_cache(CACHE_SIZE + sizeof(internal_mips3_state))
|
, 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_fastram, 0, sizeof(m_fastram));
|
||||||
memset(m_hotspot, 0, sizeof(m_hotspot));
|
memset(m_hotspot, 0, sizeof(m_hotspot));
|
||||||
|
|
||||||
|
// configure the virtual TLB
|
||||||
|
set_vtlb_fixed_entries(2 * m_tlbentries + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void mips3_device::device_stop()
|
void mips3_device::device_stop()
|
||||||
{
|
{
|
||||||
if (m_vtlb != nullptr)
|
|
||||||
{
|
|
||||||
vtlb_free(m_vtlb);
|
|
||||||
m_vtlb = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_drcfe != nullptr)
|
if (m_drcfe != nullptr)
|
||||||
{
|
{
|
||||||
m_drcfe = nullptr;
|
m_drcfe = nullptr;
|
||||||
@ -331,28 +328,12 @@ void mips3_device::device_start()
|
|||||||
m_program = &space(AS_PROGRAM);
|
m_program = &space(AS_PROGRAM);
|
||||||
m_direct = &m_program->direct();
|
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 */
|
/* set up the endianness */
|
||||||
m_program->accessors(m_memory);
|
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 */
|
/* 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_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;
|
UINT32 flags = 0;
|
||||||
/* initialize the UML generator */
|
/* initialize the UML generator */
|
||||||
m_drcuml = std::make_unique<drcuml_state>(*this, m_cache, flags, 8, 32, 2);
|
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_hi = 0xffffffff;
|
||||||
entry->entry_lo[0] = 0xfffffff8;
|
entry->entry_lo[0] = 0xfffffff8;
|
||||||
entry->entry_lo[1] = 0xfffffff8;
|
entry->entry_lo[1] = 0xfffffff8;
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0);
|
vtlb_load(2 * tlbindex + 0, 0, 0, 0);
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
|
vtlb_load(2 * tlbindex + 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* load the fixed TLB range */
|
/* 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(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 + 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_core->mode = (MODE_KERNEL << 1) | 0;
|
||||||
m_cache_dirty = TRUE;
|
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 */
|
/* only applies to the program address space */
|
||||||
if (spacenum == AS_PROGRAM)
|
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];
|
vtlb_entry entry = table[address >> MIPS3_MIN_PAGE_SHIFT];
|
||||||
if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0)
|
if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0)
|
||||||
return false;
|
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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
*result = (*m_memory.read_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
|
*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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
*result = (*m_memory.read_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff));
|
*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)
|
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)
|
if (tlbval & VTLB_READ_ALLOWED)
|
||||||
{
|
{
|
||||||
*result = (*m_memory.read_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), mem_mask);
|
*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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
const UINT32 tlbaddress = (tlbval & ~0xfff) | (address & 0xfff);
|
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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
(*m_memory.write_dword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
|
(*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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
(*m_memory.write_qword)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data);
|
(*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)
|
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)
|
if (tlbval & VTLB_WRITE_ALLOWED)
|
||||||
{
|
{
|
||||||
(*m_memory.write_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
|
(*m_memory.write_qword_masked)(*m_program, (tlbval & ~0xfff) | (address & 0xfff), data, mem_mask);
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
#define __MIPS3_H__
|
#define __MIPS3_H__
|
||||||
|
|
||||||
|
|
||||||
#include "cpu/vtlb.h"
|
#include "divtlb.h"
|
||||||
#include "cpu/drcfe.h"
|
#include "cpu/drcfe.h"
|
||||||
#include "cpu/drcuml.h"
|
#include "cpu/drcuml.h"
|
||||||
#include "cpu/drcumlsh.h"
|
#include "cpu/drcumlsh.h"
|
||||||
@ -245,7 +245,7 @@ struct compiler_state
|
|||||||
|
|
||||||
class mips3_frontend;
|
class mips3_frontend;
|
||||||
|
|
||||||
class mips3_device : public cpu_device
|
class mips3_device : public cpu_device, public device_vtlb_interface
|
||||||
{
|
{
|
||||||
friend class mips3_frontend;
|
friend class mips3_frontend;
|
||||||
|
|
||||||
@ -355,7 +355,6 @@ private:
|
|||||||
UINT32 m_ll_value;
|
UINT32 m_ll_value;
|
||||||
UINT64 m_lld_value;
|
UINT64 m_lld_value;
|
||||||
UINT32 m_badcop_value;
|
UINT32 m_badcop_value;
|
||||||
const vtlb_entry *m_tlb_table;
|
|
||||||
|
|
||||||
/* endian-dependent load/store */
|
/* endian-dependent load/store */
|
||||||
typedef void (mips3_device::*loadstore_func)(UINT32 op);
|
typedef void (mips3_device::*loadstore_func)(UINT32 op);
|
||||||
@ -389,7 +388,6 @@ private:
|
|||||||
size_t c_dcache_size;
|
size_t c_dcache_size;
|
||||||
|
|
||||||
/* MMU */
|
/* MMU */
|
||||||
vtlb_state * m_vtlb;
|
|
||||||
mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES];
|
mips3_tlb_entry m_tlb[MIPS3_MAX_TLB_ENTRIES];
|
||||||
|
|
||||||
/* fast RAM */
|
/* fast RAM */
|
||||||
|
@ -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 */
|
/* 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))
|
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(2 * tlbindex + 0, 0, 0, 0);
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
|
vtlb_load(2 * tlbindex + 1, 0, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +334,8 @@ void mips3_device::tlb_map_entry(int tlbindex)
|
|||||||
vpn = ((entry->entry_hi >> 13) & 0x07ffffff) << 1;
|
vpn = ((entry->entry_hi >> 13) & 0x07ffffff) << 1;
|
||||||
if (vpn >= (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
|
if (vpn >= (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
|
||||||
{
|
{
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + 0, 0, 0, 0);
|
vtlb_load(2 * tlbindex + 0, 0, 0, 0);
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + 1, 0, 0, 0);
|
vtlb_load(2 * tlbindex + 1, 0, 0, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,9 +369,9 @@ void mips3_device::tlb_map_entry(int tlbindex)
|
|||||||
|
|
||||||
/* load the virtual TLB with the corresponding entries */
|
/* load the virtual TLB with the corresponding entries */
|
||||||
if ((effvpn + count) <= (0x80000000 >> MIPS3_MIN_PAGE_SHIFT) || effvpn >= (0xc0000000 >> MIPS3_MIN_PAGE_SHIFT))
|
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
|
else
|
||||||
vtlb_load(m_vtlb, 2 * tlbindex + which, 0, 0, 0);
|
vtlb_load(2 * tlbindex + which, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
#define __MIPS3COM_H__
|
#define __MIPS3COM_H__
|
||||||
|
|
||||||
#include "mips3.h"
|
#include "mips3.h"
|
||||||
#include "cpu/vtlb.h"
|
|
||||||
|
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -667,7 +667,7 @@ void mips3_device::static_generate_tlb_mismatch()
|
|||||||
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
||||||
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
|
UML_MOV(block, mem(&m_core->pc), I0); // mov <pc>,i0
|
||||||
UML_SHR(block, I1, I0, 12); // shr i1,i0,12
|
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)
|
if (PRINTF_MMU)
|
||||||
{
|
{
|
||||||
static const char text[] = "TLB mismatch @ %08X (ent=%08X)\n";
|
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 */
|
/* general case: assume paging and perform a translation */
|
||||||
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
|
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_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_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
|
||||||
UML_ROLINS(block, I0, I3, 0, 0xfffff000); // rolins i0,i3,0,0xfffff000
|
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 */
|
/* 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))
|
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 we currently have a valid TLB read entry, we just verify */
|
||||||
if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
|
if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
#ifndef __PPC_H__
|
#ifndef __PPC_H__
|
||||||
#define __PPC_H__
|
#define __PPC_H__
|
||||||
|
|
||||||
#include "cpu/vtlb.h"
|
#include "divtlb.h"
|
||||||
#include "cpu/drcfe.h"
|
#include "cpu/drcfe.h"
|
||||||
#include "cpu/drcuml.h"
|
#include "cpu/drcuml.h"
|
||||||
#include "cpu/drcumlsh.h"
|
#include "cpu/drcumlsh.h"
|
||||||
@ -171,7 +171,7 @@ enum
|
|||||||
class ppc_frontend;
|
class ppc_frontend;
|
||||||
|
|
||||||
|
|
||||||
class ppc_device : public cpu_device
|
class ppc_device : public cpu_device, public device_vtlb_interface
|
||||||
{
|
{
|
||||||
friend class ppc_frontend;
|
friend class ppc_frontend;
|
||||||
|
|
||||||
@ -462,9 +462,6 @@ protected:
|
|||||||
UINT32 m_sebr;
|
UINT32 m_sebr;
|
||||||
UINT32 m_ser;
|
UINT32 m_ser;
|
||||||
|
|
||||||
/* MMU */
|
|
||||||
vtlb_state *m_vtlb;
|
|
||||||
|
|
||||||
/* architectural distinctions */
|
/* architectural distinctions */
|
||||||
powerpc_flavor m_flavor;
|
powerpc_flavor m_flavor;
|
||||||
UINT32 m_cap;
|
UINT32 m_cap;
|
||||||
|
@ -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)
|
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__)
|
: 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)
|
, m_program_config("program", ENDIANNESS_BIG, data_bits, address_bits, 0, internal_map)
|
||||||
, c_bus_frequency(0)
|
, c_bus_frequency(0)
|
||||||
, m_core(nullptr)
|
, m_core(nullptr)
|
||||||
, m_bus_freq_multiplier(1)
|
, m_bus_freq_multiplier(1)
|
||||||
, m_vtlb(nullptr)
|
|
||||||
, m_flavor(flavor)
|
, m_flavor(flavor)
|
||||||
, m_cap(cap)
|
, m_cap(cap)
|
||||||
, m_tb_divisor(tb_divisor)
|
, 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_logaddr_width = 32;
|
||||||
m_program_config.m_page_shift = POWERPC_MIN_PAGE_SHIFT;
|
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)
|
//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)
|
if (!(m_cap & PPCCAP_4XX) && space_config()->m_endianness != ENDIANNESS_NATIVE)
|
||||||
m_codexor = 4;
|
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 */
|
/* allocate a timer for the compare interrupt */
|
||||||
if ((m_cap & PPCCAP_OEA) && (m_tb_divisor))
|
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));
|
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()
|
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;
|
m_core->irq_pending = 0;
|
||||||
|
|
||||||
/* flush the TLB */
|
/* flush the TLB */
|
||||||
vtlb_flush_dynamic(m_vtlb);
|
|
||||||
if (m_cap & PPCCAP_603_MMU)
|
if (m_cap & PPCCAP_603_MMU)
|
||||||
{
|
{
|
||||||
for (int tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++)
|
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 we're simulating the 603 MMU, fill in the data and stop here */
|
||||||
if (m_cap & PPCCAP_603_MMU)
|
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_cmp = 0x80000000 | ((segreg & 0xffffff) << 7) | (0 << 6) | ((address >> 22) & 0x3f);
|
||||||
m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask);
|
m_core->mmu603_hash[0] = hashbase | ((hash << 6) & hashmask);
|
||||||
m_core->mmu603_hash[1] = 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()
|
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()
|
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()
|
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()
|
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;
|
flags |= VTLB_FETCH_ALLOWED;
|
||||||
|
|
||||||
/* load the entry */
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -743,11 +743,11 @@ void ppc_device::static_generate_tlb_mismatch()
|
|||||||
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
|
UML_HANDLE(block, *m_tlb_mismatch); // handle tlb_mismatch
|
||||||
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
UML_RECOVER(block, I0, MAPVAR_PC); // recover i0,PC
|
||||||
UML_SHR(block, I1, I0, 12); // shr i1,i0,12
|
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->param0), I0); // mov [param0],i0
|
||||||
UML_MOV(block, mem(&m_core->param1), TRANSLATE_FETCH); // mov [param1],TRANSLATE_FETCH
|
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_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_TEST(block, I1, VTLB_FETCH_ALLOWED); // test i1,VTLB_FETCH_ALLOWED
|
||||||
UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z
|
UML_JMPc(block, COND_Z, isi = label++); // jmp isi,z
|
||||||
UML_CMP(block, I2, 0); // cmp i2,0
|
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)))
|
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_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_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type
|
||||||
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
|
UML_JMPc(block, COND_Z, tlbmiss = label++); // jmp tlbmiss,z
|
||||||
UML_LABEL(block, tlbreturn = label++); // tlbreturn:
|
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_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_CALLC(block, (c_function)cfunc_ppccom_tlb_fill, this); // callc tlbfill,ppc
|
||||||
UML_SHR(block, I3, I0, 12); // shr i3,i0,12
|
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_TEST(block, I3, (UINT64)1 << translate_type); // test i3,1 << translate_type
|
||||||
UML_JMPc(block, COND_NZ, tlbreturn); // jmp tlbreturn,nz
|
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 */
|
/* 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))
|
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 we currently have a valid TLB read entry, we just verify */
|
||||||
if (tlbtable[desc->pc >> 12] != 0)
|
if (tlbtable[desc->pc >> 12] != 0)
|
||||||
|
@ -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];
|
|
||||||
}
|
|
@ -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__ */
|
|
@ -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__ */
|
#endif /* __DIMEMORY_H__ */
|
||||||
|
341
src/emu/divtlb.cpp
Normal file
341
src/emu/divtlb.cpp
Normal 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
89
src/emu/divtlb.h
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user