diff options
Diffstat (limited to 'src/emu/divtlb.cpp')
-rw-r--r-- | src/emu/divtlb.cpp | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/src/emu/divtlb.cpp b/src/emu/divtlb.cpp new file mode 100644 index 00000000000..01be30919cb --- /dev/null +++ b/src/emu/divtlb.cpp @@ -0,0 +1,341 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + divtlb.c + + Device generic virtual TLB interface. + +***************************************************************************/ + +#include "emu.h" +#include "divtlb.h" +#include "validity.h" + + + +//************************************************************************** +// DEBUGGING +//************************************************************************** + +#define PRINTF_TLB (0) + + + +//************************************************************************** +// DEVICE VTLB INTERFACE +//************************************************************************** + +//------------------------------------------------- +// device_vtlb_interface - constructor +//------------------------------------------------- + +device_vtlb_interface::device_vtlb_interface(const machine_config &mconfig, device_t &device, address_spacenum space) + : device_interface(device, "vtlb"), + m_space(space), + m_dynamic(0), + m_fixed(0), + m_dynindex(0), + m_pageshift(0), + m_addrwidth(0) +{ +} + + +//------------------------------------------------- +// device_vtlb_interface - destructor +//------------------------------------------------- + +device_vtlb_interface::~device_vtlb_interface() +{ +} + + +//------------------------------------------------- +// interface_validity_check - validation for a +// device after the configuration has been +// constructed +//------------------------------------------------- + +void device_vtlb_interface::interface_validity_check(validity_checker &valid) const +{ + const device_memory_interface *intf; + if (!device().interface(intf)) + osd_printf_error("Device does not have memory interface\n"); + else + { + // validate CPU information + const address_space_config *spaceconfig = intf->space_config(m_space); + if (spaceconfig == nullptr) + osd_printf_error("No memory address space configuration found for space %d\n", m_space); + else if ((1 << spaceconfig->m_page_shift) <= VTLB_FLAGS_MASK || spaceconfig->m_logaddr_width <= spaceconfig->m_page_shift) + osd_printf_error("Invalid page shift %d for VTLB\n", spaceconfig->m_page_shift); + } +} + + +//------------------------------------------------- +// interface_pre_start - work to be done prior to +// actually starting a device +//------------------------------------------------- + +void device_vtlb_interface::interface_pre_start() +{ + // fill in CPU information + const address_space_config *spaceconfig = device().memory().space_config(m_space); + m_pageshift = spaceconfig->m_page_shift; + m_addrwidth = spaceconfig->m_logaddr_width; + + // allocate the entry array + m_live.resize(m_fixed + m_dynamic); + memset(&m_live[0], 0, m_live.size()*sizeof(m_live[0])); + + // allocate the lookup table + m_table.resize((size_t) 1 << (m_addrwidth - m_pageshift)); + memset(&m_table[0], 0, m_table.size()*sizeof(m_table[0])); + + // allocate the fixed page count array + if (m_fixed > 0) + { + m_fixedpages.resize(m_fixed); + memset(&m_fixedpages[0], 0, m_fixed*sizeof(m_fixedpages[0])); + } +} + + +//------------------------------------------------- +// interface_post_start - work to be done after +// actually starting a device +//------------------------------------------------- + +void device_vtlb_interface::interface_post_start() +{ + device().save_item(NAME(m_live)); + device().save_item(NAME(m_table)); + if (m_fixed > 0) + device().save_item(NAME(m_fixedpages)); +} + + +//------------------------------------------------- +// interface_pre_reset - work to be done prior to +// actually resetting a device +//------------------------------------------------- + +void device_vtlb_interface::interface_pre_reset() +{ + vtlb_flush_dynamic(); +} + + +//************************************************************************** +// FILLING +//************************************************************************** + +//------------------------------------------------- +// vtlb_fill - called by the CPU core in +// response to an unmapped access +//------------------------------------------------- + +int device_vtlb_interface::vtlb_fill(offs_t address, int intention) +{ + offs_t tableindex = address >> m_pageshift; + vtlb_entry entry = m_table[tableindex]; + offs_t taddress; + +#if PRINTF_TLB + osd_printf_debug("vtlb_fill: %08X(%X) ... ", address, intention); +#endif + + // should not be called here if the entry is in the table already +// assert((entry & (1 << intention)) == 0); + + // if we have no dynamic entries, we always fail + if (m_dynamic == 0) + { +#if PRINTF_TLB + osd_printf_debug("failed: no dynamic entries\n"); +#endif + return FALSE; + } + + // ask the CPU core to translate for us + taddress = address; + if (!device().memory().translate(m_space, intention, taddress)) + { +#if PRINTF_TLB + osd_printf_debug("failed: no translation\n"); +#endif + return FALSE; + } + + // if this is the first successful translation for this address, allocate a new entry + if ((entry & VTLB_FLAGS_MASK) == 0) + { + int liveindex = m_dynindex++ % m_dynamic; + + // if an entry already exists at this index, free it + if (m_live[liveindex] != 0) + m_table[m_live[liveindex] - 1] = 0; + + // claim this new entry + m_live[liveindex] = tableindex + 1; + + // form a new blank entry + entry = (taddress >> m_pageshift) << m_pageshift; + entry |= VTLB_FLAG_VALID; + +#if PRINTF_TLB + osd_printf_debug("success (%08X), new entry\n", taddress); +#endif + } + + // otherwise, ensure that different intentions do not produce different addresses + else + { + assert((entry >> m_pageshift) == (taddress >> m_pageshift)); + assert(entry & VTLB_FLAG_VALID); + +#if PRINTF_TLB + osd_printf_debug("success (%08X), existing entry\n", taddress); +#endif + } + + // add the intention to the list of valid intentions and store + entry |= 1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)); + m_table[tableindex] = entry; + return TRUE; +} + + +//------------------------------------------------- +// vtlb_load - load a fixed VTLB entry +//------------------------------------------------- + +void device_vtlb_interface::vtlb_load(int entrynum, int numpages, offs_t address, vtlb_entry value) +{ + offs_t tableindex = address >> m_pageshift; + int liveindex = m_dynamic + entrynum; + int pagenum; + + // must be in range + assert(entrynum >= 0 && entrynum < m_fixed); + +#if PRINTF_TLB + osd_printf_debug("vtlb_load %d for %d pages at %08X == %08X\n", entrynum, numpages, address, value); +#endif + + // if an entry already exists at this index, free it + if (m_live[liveindex] != 0) + { + int pagecount = m_fixedpages[entrynum]; + int oldtableindex = m_live[liveindex] - 1; + for (pagenum = 0; pagenum < pagecount; pagenum++) + m_table[oldtableindex + pagenum] = 0; + } + + // claim this new entry + m_live[liveindex] = tableindex + 1; + + // store the raw value, making sure the "fixed" flag is set + value |= VTLB_FLAG_FIXED; + m_fixedpages[entrynum] = numpages; + for (pagenum = 0; pagenum < numpages; pagenum++) + m_table[tableindex + pagenum] = value + (pagenum << m_pageshift); +} + +//------------------------------------------------- +// vtlb_dynload - load a dynamic VTLB entry +//------------------------------------------------- + +void device_vtlb_interface::vtlb_dynload(UINT32 index, offs_t address, vtlb_entry value) +{ + vtlb_entry entry = m_table[index]; + + if (m_dynamic == 0) + { +#if PRINTF_TLB + osd_printf_debug("failed: no dynamic entries\n"); +#endif + return; + } + + int liveindex = m_dynindex++ % m_dynamic; + // is entry already live? + if (!(entry & VTLB_FLAG_VALID)) + { + // if an entry already exists at this index, free it + if (m_live[liveindex] != 0) + m_table[m_live[liveindex] - 1] = 0; + + // claim this new entry + m_live[liveindex] = index + 1; + } + // form a new blank entry + entry = (address >> m_pageshift) << m_pageshift; + entry |= VTLB_FLAG_VALID | value; + +#if PRINTF_TLB + osd_printf_debug("success (%08X), new entry\n", address); +#endif + m_table[index] = entry; +} + +//************************************************************************** +// FLUSHING +//************************************************************************** + +//------------------------------------------------- +// vtlb_flush_dynamic - flush all knowledge +// from the dynamic part of the VTLB +//------------------------------------------------- + +void device_vtlb_interface::vtlb_flush_dynamic() +{ +#if PRINTF_TLB + osd_printf_debug("vtlb_flush_dynamic\n"); +#endif + + // loop over live entries and release them from the table + for (int liveindex = 0; liveindex < m_dynamic; liveindex++) + if (m_live[liveindex] != 0) + { + offs_t tableindex = m_live[liveindex] - 1; + m_table[tableindex] = 0; + m_live[liveindex] = 0; + } +} + + +//------------------------------------------------- +// vtlb_flush_address - flush knowledge of a +// particular address from the VTLB +//------------------------------------------------- + +void device_vtlb_interface::vtlb_flush_address(offs_t address) +{ + offs_t tableindex = address >> m_pageshift; + +#if PRINTF_TLB + osd_printf_debug("vtlb_flush_address %08X\n", address); +#endif + + // free the entry in the table; for speed, we leave the entry in the live array + m_table[tableindex] = 0; +} + + + +//************************************************************************** +// ACCESSORS +//************************************************************************** + +//------------------------------------------------- +// vtlb_table - return a pointer to the base of +// the linear VTLB lookup table +//------------------------------------------------- + +const vtlb_entry *device_vtlb_interface::vtlb_table() const +{ + return &m_table[0]; +} |