diff options
Diffstat (limited to 'src/emu/divtlb.cpp')
-rw-r--r-- | src/emu/divtlb.cpp | 403 |
1 files changed, 217 insertions, 186 deletions
diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp index 4c9a9a2f311..01be30919cb 100644 --- a/src/emu/divtlb.cpp +++ b/src/emu/divtlb.cpp @@ -2,309 +2,340 @@ // copyright-holders:Aaron Giles /*************************************************************************** - vtlb.c + divtlb.c - Generic virtual TLB implementation. + Device generic virtual TLB interface. ***************************************************************************/ #include "emu.h" -#include "vtlb.h" +#include "divtlb.h" +#include "validity.h" -/*************************************************************************** - DEBUGGING -***************************************************************************/ +//************************************************************************** +// DEBUGGING +//************************************************************************** #define PRINTF_TLB (0) -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// DEVICE VTLB INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vtlb_interface - constructor +//------------------------------------------------- -/* VTLB state */ -struct vtlb_state +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) { - 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 */ -}; +} +//------------------------------------------------- +// 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); + } +} -/*************************************************************************** - INITIALIZATION/TEARDOWN -***************************************************************************/ -/*------------------------------------------------- - vtlb_alloc - allocate a new VTLB for the - given CPU --------------------------------------------------*/ +//------------------------------------------------- +// interface_pre_start - work to be done prior to +// actually starting a device +//------------------------------------------------- -vtlb_state *vtlb_alloc(device_t *cpu, address_spacenum space, int fixed_entries, int dynamic_entries) +void device_vtlb_interface::interface_pre_start() { - 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) + // 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) { - vtlb->fixedpages.resize(fixed_entries); - memset(&vtlb->fixedpages[0], 0, fixed_entries*sizeof(vtlb->fixedpages[0])); - cpu->save_item(NAME(vtlb->fixedpages)); + m_fixedpages.resize(m_fixed); + memset(&m_fixedpages[0], 0, m_fixed*sizeof(m_fixedpages[0])); } - return vtlb; } -/*------------------------------------------------- - vtlb_free - free an allocated VTLB --------------------------------------------------*/ +//------------------------------------------------- +// interface_post_start - work to be done after +// actually starting a device +//------------------------------------------------- -void vtlb_free(vtlb_state *vtlb) +void device_vtlb_interface::interface_post_start() { - auto_free(vtlb->cpudevice->machine(), vtlb); + 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 +//------------------------------------------------- -/*************************************************************************** - FILLING -***************************************************************************/ +void device_vtlb_interface::interface_pre_reset() +{ + vtlb_flush_dynamic(); +} -/*------------------------------------------------- - vtlb_fill - rcalled by the CPU core in - response to an unmapped access --------------------------------------------------*/ -int vtlb_fill(vtlb_state *vtlb, offs_t address, int intention) +//************************************************************************** +// 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 >> vtlb->pageshift; - vtlb_entry entry = vtlb->table[tableindex]; + offs_t tableindex = address >> m_pageshift; + vtlb_entry entry = m_table[tableindex]; offs_t taddress; - if (PRINTF_TLB) - printf("vtlb_fill: %08X(%X) ... ", address, intention); +#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 */ + // 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 we have no dynamic entries, we always fail + if (m_dynamic == 0) { - if (PRINTF_TLB) - printf("failed: no dynamic entries\n"); +#if PRINTF_TLB + osd_printf_debug("failed: no dynamic entries\n"); +#endif return FALSE; } - /* ask the CPU core to translate for us */ + // ask the CPU core to translate for us taddress = address; - if (!vtlb->cpudevice->translate(vtlb->space, intention, taddress)) + if (!device().memory().translate(m_space, intention, taddress)) { - if (PRINTF_TLB) - printf("failed: no translation\n"); +#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 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; + int liveindex = m_dynindex++ % m_dynamic; - /* if an entry already exists at this index, free it */ - if (vtlb->live[liveindex] != 0) - vtlb->table[vtlb->live[liveindex] - 1] = 0; + // 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 */ - vtlb->live[liveindex] = tableindex + 1; + // claim this new entry + m_live[liveindex] = tableindex + 1; - /* form a new blank entry */ - entry = (taddress >> vtlb->pageshift) << vtlb->pageshift; + // form a new blank entry + entry = (taddress >> m_pageshift) << m_pageshift; entry |= VTLB_FLAG_VALID; - if (PRINTF_TLB) - printf("success (%08X), new entry\n", taddress); +#if PRINTF_TLB + osd_printf_debug("success (%08X), new entry\n", taddress); +#endif } - /* otherwise, ensure that different intentions do not produce different addresses */ + // otherwise, ensure that different intentions do not produce different addresses else { - assert((entry >> vtlb->pageshift) == (taddress >> vtlb->pageshift)); + assert((entry >> m_pageshift) == (taddress >> m_pageshift)); assert(entry & VTLB_FLAG_VALID); - if (PRINTF_TLB) - printf("success (%08X), existing entry\n", taddress); +#if PRINTF_TLB + osd_printf_debug("success (%08X), existing entry\n", taddress); +#endif } - /* add the intention to the list of valid intentions and store */ + // add the intention to the list of valid intentions and store entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)); - vtlb->table[tableindex] = entry; + m_table[tableindex] = entry; return TRUE; } -/*------------------------------------------------- - vtlb_load - load a fixed VTLB entry --------------------------------------------------*/ +//------------------------------------------------- +// vtlb_load - load a fixed VTLB entry +//------------------------------------------------- -void vtlb_load(vtlb_state *vtlb, int entrynum, int numpages, offs_t address, vtlb_entry value) +void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value) { - offs_t tableindex = address >> vtlb->pageshift; - int liveindex = vtlb->dynamic + entrynum; + offs_t tableindex = address >> m_pageshift; + int liveindex = m_dynamic + entrynum; int pagenum; - /* must be in range */ - assert(entrynum >= 0 && entrynum < vtlb->fixed); + // must be in range + assert(entrynum >= 0 && entrynum < m_fixed); - if (PRINTF_TLB) - printf("vtlb_load %d for %d pages at %08X == %08X\n", entrynum, numpages, address, value); +#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 (vtlb->live[liveindex] != 0) + // if an entry already exists at this index, free it + if (m_live[liveindex] != 0) { - int pagecount = vtlb->fixedpages[entrynum]; - int oldtableindex = vtlb->live[liveindex] - 1; + int pagecount = m_fixedpages[entrynum]; + int oldtableindex = m_live[liveindex] - 1; for (pagenum = 0; pagenum < pagecount; pagenum++) - vtlb->table[oldtableindex + pagenum] = 0; + m_table[oldtableindex + pagenum] = 0; } - /* claim this new entry */ - vtlb->live[liveindex] = tableindex + 1; + // claim this new entry + m_live[liveindex] = tableindex + 1; - /* store the raw value, making sure the "fixed" flag is set */ + // store the raw value, making sure the "fixed" flag is set value |= VTLB_FLAG_FIXED; - vtlb->fixedpages[entrynum] = numpages; + m_fixedpages[entrynum] = numpages; for (pagenum = 0; pagenum < numpages; pagenum++) - vtlb->table[tableindex + pagenum] = value + (pagenum << vtlb->pageshift); + m_table[tableindex + pagenum] = value + (pagenum << m_pageshift); } -/*------------------------------------------------- - vtlb_dynload - load a dynamic VTLB entry --------------------------------------------------*/ +//------------------------------------------------- +// vtlb_dynload - load a dynamic VTLB entry +//------------------------------------------------- -void vtlb_dynload(vtlb_state *vtlb, UINT32 index, offs_t address, vtlb_entry value) +void device_vtlb_interface::vtlb_dynload(UINT32 index, offs_t address, vtlb_entry value) { - vtlb_entry entry = vtlb->table[index]; + vtlb_entry entry = m_table[index]; - if (vtlb->dynamic == 0) + if (m_dynamic == 0) { - if (PRINTF_TLB) - printf("failed: no dynamic entries\n"); +#if PRINTF_TLB + osd_printf_debug("failed: no dynamic entries\n"); +#endif return; } - int liveindex = vtlb->dynindex++ % vtlb->dynamic; - /* is entry already live? */ + 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 (vtlb->live[liveindex] != 0) - vtlb->table[vtlb->live[liveindex] - 1] = 0; + // 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 */ - vtlb->live[liveindex] = index + 1; + // claim this new entry + m_live[liveindex] = index + 1; } - /* form a new blank entry */ - entry = (address >> vtlb->pageshift) << vtlb->pageshift; + // form a new blank entry + entry = (address >> m_pageshift) << m_pageshift; entry |= VTLB_FLAG_VALID | value; - if (PRINTF_TLB) - printf("success (%08X), new entry\n", address); - - vtlb->table[index] = entry; +#if PRINTF_TLB + osd_printf_debug("success (%08X), new entry\n", address); +#endif + m_table[index] = entry; } -/*************************************************************************** - FLUSHING -***************************************************************************/ +//************************************************************************** +// FLUSHING +//************************************************************************** -/*------------------------------------------------- - vtlb_flush_dynamic - flush all knowledge - from the dynamic part of the VTLB --------------------------------------------------*/ +//------------------------------------------------- +// vtlb_flush_dynamic - flush all knowledge +// from the dynamic part of the VTLB +//------------------------------------------------- -void vtlb_flush_dynamic(vtlb_state *vtlb) +void device_vtlb_interface::vtlb_flush_dynamic() { - int liveindex; - - if (PRINTF_TLB) - printf("vtlb_flush_dynamic\n"); +#if PRINTF_TLB + osd_printf_debug("vtlb_flush_dynamic\n"); +#endif - /* loop over live entries and release them from the table */ - for (liveindex = 0; liveindex < vtlb->dynamic; liveindex++) - if (vtlb->live[liveindex] != 0) + // 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 = vtlb->live[liveindex] - 1; - vtlb->table[tableindex] = 0; - vtlb->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 --------------------------------------------------*/ +//------------------------------------------------- +// vtlb_flush_address - flush knowledge of a +// particular address from the VTLB +//------------------------------------------------- -void vtlb_flush_address(vtlb_state *vtlb, offs_t address) +void device_vtlb_interface::vtlb_flush_address(offs_t address) { - offs_t tableindex = address >> vtlb->pageshift; + offs_t tableindex = address >> m_pageshift; - if (PRINTF_TLB) - printf("vtlb_flush_address %08X\n", address); +#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 */ - vtlb->table[tableindex] = 0; + // free the entry in the table; for speed, we leave the entry in the live array + m_table[tableindex] = 0; } -/*************************************************************************** - ACCESSORS -***************************************************************************/ +//************************************************************************** +// ACCESSORS +//************************************************************************** -/*------------------------------------------------- - vtlb_table - return a pointer to the base of - the linear VTLB lookup table --------------------------------------------------*/ +//------------------------------------------------- +// vtlb_table - return a pointer to the base of +// the linear VTLB lookup table +//------------------------------------------------- -const vtlb_entry *vtlb_table(vtlb_state *vtlb) +const vtlb_entry *device_vtlb_interface::vtlb_table() const { - return &vtlb->table[0]; + return &m_table[0]; } |