mame/src/emu/cpu/vtlb.c
Aaron Giles e738b79785 Correct a long-standing design flaw: device configuration state
is now separate from runtime device state. I have larger plans
for devices, so there is some temporary scaffolding to hold
everything together, but this first step does separate things
out.

There is a new class 'running_device' which represents the
state of a live device. A list of these running_devices sits
in machine->devicelist and is created when a running_machine
is instantiated.

To access the configuration state, use device->baseconfig()
which returns a reference to the configuration.

The list of running_devices in machine->devicelist has a 1:1
correspondance with the list of device configurations in
machine->config->devicelist, and most navigation options work
equally on either (scanning by class, type, etc.)

For the most part, drivers will now deal with running_device
objects instead of const device_config objects. In fact, in
order to do this patch, I did the following global search &
replace:

  const device_config -> running_device
  device->static_config -> device->baseconfig().static_config
  device->inline_config -> device->baseconfig().inline_config

and then fixed up the compiler errors that fell out.

Some specifics:

  Removed device_get_info_* functions and replaced them with
  methods called get_config_*.
  
  Added methods for get_runtime_* to access runtime state from
  the running_device.
  
  DEVICE_GET_INFO callbacks are only passed a device_config *.
  This means they have no access to the token or runtime state
  at all. For most cases this is fine.
  
  Added new DEVICE_GET_RUNTIME_INFO callback that is passed
  the running_device for accessing data that is live at runtime.
  In the future this will go away to make room for a cleaner
  mechanism.
  
  Cleaned up the handoff of memory regions from the memory
  subsystem to the devices.
2010-01-18 09:34:43 +00:00

289 lines
8.7 KiB
C

/***************************************************************************
vtlb.c
Generic virtual TLB implementation.
Copyright Aaron Giles
Released for general non-commercial use under the MAME license
Visit http://mamedev.org for licensing and usage restrictions.
***************************************************************************/
#include "emu.h"
#include "vtlb.h"
/***************************************************************************
DEBUGGING
***************************************************************************/
#define PRINTF_TLB (0)
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
/* VTLB state */
struct _vtlb_state
{
running_device *device; /* CPU device */
int 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 */
offs_t * live; /* array of live entries by table index */
int * fixedpages; /* number of pages each fixed entry covers */
vtlb_entry * table; /* table of entries by address */
vtlb_entry * save; /* cache of live table entries for saving */
cpu_translate_func translate; /* translate function */
};
/***************************************************************************
INITIALIZATION/TEARDOWN
***************************************************************************/
/*-------------------------------------------------
vtlb_alloc - allocate a new VTLB for the
given CPU
-------------------------------------------------*/
vtlb_state *vtlb_alloc(running_device *cpu, int 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->device = cpu;
vtlb->space = space;
vtlb->dynamic = dynamic_entries;
vtlb->fixed = fixed_entries;
vtlb->pageshift = cpu_get_page_shift(cpu, space);
vtlb->addrwidth = cpu_get_logaddr_width(cpu, space);
vtlb->translate = (cpu_translate_func)cpu->get_config_fct(CPUINFO_FCT_TRANSLATE);
/* validate CPU information */
assert((1 << vtlb->pageshift) > VTLB_FLAGS_MASK);
assert(vtlb->translate != NULL);
assert(vtlb->addrwidth > vtlb->pageshift);
/* allocate the entry array */
vtlb->live = auto_alloc_array_clear(cpu->machine, offs_t, fixed_entries + dynamic_entries);
state_save_register_device_item_pointer(cpu, space, vtlb->live, fixed_entries + dynamic_entries);
/* allocate the lookup table */
vtlb->table = auto_alloc_array_clear(cpu->machine, vtlb_entry, (size_t) 1 << (vtlb->addrwidth - vtlb->pageshift));
state_save_register_device_item_pointer(cpu, space, vtlb->table, 1 << (vtlb->addrwidth - vtlb->pageshift));
/* allocate the fixed page count array */
if (fixed_entries > 0)
{
vtlb->fixedpages = auto_alloc_array_clear(cpu->machine, int, fixed_entries);
state_save_register_device_item_pointer(cpu, space, vtlb->fixedpages, fixed_entries);
}
return vtlb;
}
/*-------------------------------------------------
vtlb_free - free an allocated VTLB
-------------------------------------------------*/
void vtlb_free(vtlb_state *vtlb)
{
/* free the fixed pages if allocated */
if (vtlb->fixedpages != NULL)
auto_free(vtlb->device->machine, vtlb->fixedpages);
/* free the table and array if they exist */
if (vtlb->live != NULL)
auto_free(vtlb->device->machine, vtlb->live);
if (vtlb->table != NULL)
auto_free(vtlb->device->machine, vtlb->table);
/* and then the VTLB object itself */
auto_free(vtlb->device->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->translate)(vtlb->device, 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);
}
/***************************************************************************
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;
}