summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2008-06-16 03:12:49 +0000
committer Aaron Giles <aaron@aarongiles.com>2008-06-16 03:12:49 +0000
commit5deab27d6d41791498aac45246d3b7cc5ea6281f (patch)
tree56c1910008a5e3df2cc6ea0034b409044765d041 /src
parentcd0703d80ab10309a691929f66efd792b5fff6ca (diff)
Created common virtual TLB managment module.
Updated MIPS and PowerPC code to make use of it.
Diffstat (limited to 'src')
-rw-r--r--src/emu/cpu/cpu.mak9
-rw-r--r--src/emu/cpu/mips/mips3.c3
-rw-r--r--src/emu/cpu/mips/mips3com.c333
-rw-r--r--src/emu/cpu/mips/mips3com.h11
-rw-r--r--src/emu/cpu/mips/mips3drc.c46
-rw-r--r--src/emu/cpu/powerpc/ppccom.c188
-rw-r--r--src/emu/cpu/powerpc/ppccom.h14
-rw-r--r--src/emu/cpu/powerpc/ppcdrc.c217
-rw-r--r--src/emu/cpu/vtlb.c284
-rw-r--r--src/emu/cpu/vtlb.h89
10 files changed, 755 insertions, 439 deletions
diff --git a/src/emu/cpu/cpu.mak b/src/emu/cpu/cpu.mak
index 8a0cb72fc38..6dce0300f22 100644
--- a/src/emu/cpu/cpu.mak
+++ b/src/emu/cpu/cpu.mak
@@ -15,6 +15,15 @@ CPUOBJ = $(EMUOBJ)/cpu
#-------------------------------------------------
+# Shared code
+#-------------------------------------------------
+
+OBJDIRS += $(CPUOBJ)
+CPUOBJS += $(CPUOBJ)/vtlb.o
+
+
+
+#-------------------------------------------------
# Dynamic recompiler objects
#-------------------------------------------------
diff --git a/src/emu/cpu/mips/mips3.c b/src/emu/cpu/mips/mips3.c
index 78d7a097813..ed12d7f8d7a 100644
--- a/src/emu/cpu/mips/mips3.c
+++ b/src/emu/cpu/mips/mips3.c
@@ -556,8 +556,7 @@ INLINE void set_cop0_reg(int idx, UINT64 val)
if ((mips3.core.cpr[0][idx] ^ val) & 0xff)
{
mips3.core.cpr[0][idx] = val;
- mips3com_unmap_tlb_entries(&mips3.core);
- mips3com_map_tlb_entries(&mips3.core);
+ mips3com_asid_changed(&mips3.core);
}
mips3.core.cpr[0][idx] = val;
break;
diff --git a/src/emu/cpu/mips/mips3com.c b/src/emu/cpu/mips/mips3com.c
index cdf8e69bf67..74d1a8f8bac 100644
--- a/src/emu/cpu/mips/mips3com.c
+++ b/src/emu/cpu/mips/mips3com.c
@@ -13,7 +13,7 @@
DEBUGGING
***************************************************************************/
-#define PRINTF_TLB (1)
+#define PRINTF_TLB (0)
@@ -26,8 +26,36 @@ static TIMER_CALLBACK( compare_int_callback );
static UINT32 compute_config_register(const mips3_state *mips);
static UINT32 compute_prid_register(const mips3_state *mips);
-static void tlb_write_common(mips3_state *mips, int index);
-static void tlb_entry_log_half(mips3_tlb_entry *tlbent, int index, int which);
+static void tlb_map_entry(mips3_state *mips, int tlbindex);
+static void tlb_write_common(mips3_state *mips, int tlbindex);
+static void tlb_entry_log_half(mips3_tlb_entry *entry, int tlbindex, int which);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ tlb_entry_matches_asid - TRUE if the given
+ TLB entry matches the provided ASID
+-------------------------------------------------*/
+
+INLINE int tlb_entry_matches_asid(const mips3_tlb_entry *entry, UINT8 asid)
+{
+ return (entry->entry_hi & 0xff) == asid;
+}
+
+
+/*-------------------------------------------------
+ tlb_entry_is_global - TRUE if the given
+ TLB entry is global
+-------------------------------------------------*/
+
+INLINE int tlb_entry_is_global(const mips3_tlb_entry *entry)
+{
+ return (entry->entry_lo[0] & entry->entry_lo[1] & TLB_GLOBAL);
+}
@@ -40,14 +68,8 @@ static void tlb_entry_log_half(mips3_tlb_entry *tlbent, int index, int which);
structure based on the configured type
-------------------------------------------------*/
-size_t mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const mips3_config *config, int (*irqcallback)(int), void *memory)
+void mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const mips3_config *config, int (*irqcallback)(int))
{
- int tlbindex;
-
- /* if no memory, return the amount needed */
- if (memory == NULL)
- return sizeof(mips->tlb_table[0]) * (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT));
-
/* initialize based on the config */
memset(mips, 0, sizeof(*mips));
mips->flavor = flavor;
@@ -61,25 +83,25 @@ size_t mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int
/* set up the endianness */
mips->memory = *memory_get_accessors(ADDRESS_SPACE_PROGRAM, 32, mips->bigendian ? CPU_IS_BE : CPU_IS_LE);
- /* allocate memory */
- mips->tlb_table = memory;
-
- /* initialize the TLB state */
- for (tlbindex = 0; tlbindex < ARRAY_LENGTH(mips->tlb); tlbindex++)
- {
- mips3_tlb_entry *tlbent = &mips->tlb[tlbindex];
- tlbent->page_mask = 0;
- tlbent->entry_hi = 0xffffffff;
- tlbent->entry_lo[0] = 0xfffffff8;
- tlbent->entry_lo[1] = 0xfffffff8;
- }
+ /* allocate the virtual TLB */
+ mips->vtlb = vtlb_alloc(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, 2 * MIPS3_TLB_ENTRIES + 2, 0);
/* allocate a timer for the compare interrupt */
mips->compare_int_timer = timer_alloc(compare_int_callback, NULL);
/* reset the state */
mips3com_reset(mips);
- return 0;
+}
+
+
+/*-------------------------------------------------
+ mips3com_exit - common cleanup/exit
+-------------------------------------------------*/
+
+void mips3com_exit(mips3_state *mips)
+{
+ if (mips->vtlb != NULL)
+ vtlb_free(mips->vtlb);
}
@@ -90,6 +112,8 @@ size_t mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int
void mips3com_reset(mips3_state *mips)
{
+ int tlbindex;
+
/* initialize the state */
mips->pc = 0xbfc00000;
mips->cpr[0][COP0_Status] = SR_BEV | SR_ERL;
@@ -100,8 +124,21 @@ void mips3com_reset(mips3_state *mips)
mips->cpr[0][COP0_PRId] = compute_prid_register(mips);
mips->count_zero_time = activecpu_gettotalcycles();
- /* recompute the TLB table */
- mips3com_recompute_tlb_table(mips);
+ /* initialize the TLB state */
+ for (tlbindex = 0; tlbindex < ARRAY_LENGTH(mips->tlb); tlbindex++)
+ {
+ mips3_tlb_entry *entry = &mips->tlb[tlbindex];
+ entry->page_mask = 0;
+ entry->entry_hi = 0xffffffff;
+ entry->entry_lo[0] = 0xfffffff8;
+ entry->entry_lo[1] = 0xfffffff8;
+ vtlb_load(mips->vtlb, 2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(mips->vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ }
+
+ /* load the fixed TLB range */
+ vtlb_load(mips->vtlb, 2 * MIPS3_TLB_ENTRIES + 0, (0xa0000000 - 0x80000000) >> MIPS3_MIN_PAGE_SHIFT, 0x80000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
+ vtlb_load(mips->vtlb, 2 * MIPS3_TLB_ENTRIES + 1, (0xc0000000 - 0xa0000000) >> MIPS3_MIN_PAGE_SHIFT, 0xa0000000, 0x00000000 | VTLB_READ_ALLOWED | VTLB_WRITE_ALLOWED | VTLB_FETCH_ALLOWED | VTLB_FLAG_VALID);
}
@@ -154,99 +191,18 @@ void mips3com_update_cycle_counting(mips3_state *mips)
***************************************************************************/
/*-------------------------------------------------
- mips3com_map_tlb_entries - map entries from the
- TLB into the tlb_table
--------------------------------------------------*/
-
-void mips3com_map_tlb_entries(mips3_state *mips)
-{
- int valid_asid = mips->cpr[0][COP0_EntryHi] & 0xff;
- int index;
-
- /* iterate over all TLB entries */
- for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
- {
- mips3_tlb_entry *tlbent = &mips->tlb[index];
-
- /* only process if the ASID matches or if global */
- if (valid_asid == (tlbent->entry_hi & 0xff) || ((tlbent->entry_lo[0] & tlbent->entry_lo[1]) & TLB_GLOBAL))
- {
- UINT32 count = (tlbent->page_mask >> 13) & 0x00fff;
- UINT32 vpn = ((tlbent->entry_hi >> 13) & 0x07ffffff) << 1;
- int which, i;
-
- /* ignore if the virtual address is beyond 32 bits */
- if (vpn < (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
-
- /* loop over both the even and odd pages */
- for (which = 0; which < 2; which++)
- {
- UINT64 lo = tlbent->entry_lo[which];
- UINT32 pfn = (lo >> 6) & 0x00ffffff;
- UINT32 wp = (lo & 7) | TLB_PRESENT;
-
- /* ensure that if the valid bit is clear, the dirty bit is as well */
- /* this way we can always test dirty for writes, and valid for reads */
- if (!(wp & TLB_VALID))
- wp &= ~TLB_DIRTY;
-
- for (i = 0; i <= count; i++, vpn++, pfn++)
- if (vpn < 0x80000 || vpn >= 0xc0000)
- mips->tlb_table[vpn] = (pfn << MIPS3_MIN_PAGE_SHIFT) | wp;
- }
- }
- }
-}
-
-
-/*-------------------------------------------------
- mips3com_unmap_tlb_entries - unmap entries from
- the TLB into the tlb_table
+ mips3com_asid_changed - remap all non-global
+ TLB entries
-------------------------------------------------*/
-void mips3com_unmap_tlb_entries(mips3_state *mips)
+void mips3com_asid_changed(mips3_state *mips)
{
- int index;
-
- /* iterate over all TLB entries */
- for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
- {
- mips3_tlb_entry *tlbent = &mips->tlb[index];
- UINT32 count = (tlbent->page_mask >> 13) & 0x00fff;
- UINT32 vpn = ((tlbent->entry_hi >> 13) & 0x07ffffff) << 1;
- int which, i;
-
- /* ignore if the virtual address is beyond 32 bits */
- if (vpn < (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
-
- /* loop over both the even and odd pages */
- for (which = 0; which < 2; which++)
- for (i = 0; i <= count; i++, vpn++)
- if (vpn < 0x80000 || vpn >= 0xc0000)
- mips->tlb_table[vpn] = 0;
- }
-}
-
-
-/*-------------------------------------------------
- mips3com_recompute_tlb_table - recompute the TLB
- table from scratch
--------------------------------------------------*/
-
-void mips3com_recompute_tlb_table(mips3_state *mips)
-{
- UINT32 addr;
-
- /* map in the hard-coded spaces */
- for (addr = 0x80000000; addr < 0xc0000000; addr += MIPS3_MIN_PAGE_SIZE)
- mips->tlb_table[addr >> MIPS3_MIN_PAGE_SHIFT] = (addr & 0x1ffff000) | TLB_PRESENT | TLB_DIRTY | TLB_VALID | TLB_GLOBAL;
-
- /* reset everything else to unmapped */
- memset(&mips->tlb_table[0x00000000 >> MIPS3_MIN_PAGE_SHIFT], 0, sizeof(mips->tlb_table[0]) * (0x80000000 >> MIPS3_MIN_PAGE_SHIFT));
- memset(&mips->tlb_table[0xc0000000 >> MIPS3_MIN_PAGE_SHIFT], 0, sizeof(mips->tlb_table[0]) * (0x40000000 >> MIPS3_MIN_PAGE_SHIFT));
+ int tlbindex;
- /* remap all the entries in the TLB */
- mips3com_map_tlb_entries(mips);
+ /* iterate over all non-global TLB entries and remap them */
+ for (tlbindex = 0; tlbindex < ARRAY_LENGTH(mips->tlb); tlbindex++)
+ if (!tlb_entry_is_global(&mips->tlb[tlbindex]))
+ tlb_map_entry(mips, tlbindex);
}
@@ -260,10 +216,11 @@ int mips3com_translate_address(mips3_state *mips, int space, int intention, offs
/* only applies to the program address space */
if (space == ADDRESS_SPACE_PROGRAM)
{
- UINT32 result = mips->tlb_table[*address >> MIPS3_MIN_PAGE_SHIFT];
- if (!(result & TLB_PRESENT) || !(result & TLB_VALID))
+ const vtlb_entry *table = vtlb_table(mips->vtlb);
+ vtlb_entry entry = table[*address >> MIPS3_MIN_PAGE_SHIFT];
+ if ((entry & (1 << (intention & (TRANSLATE_TYPE_MASK | TRANSLATE_USER_MASK)))) == 0)
return FALSE;
- *address = (result & ~MIPS3_MIN_PAGE_MASK) | (*address & MIPS3_MIN_PAGE_MASK);
+ *address = (entry & ~MIPS3_MIN_PAGE_MASK) | (*address & MIPS3_MIN_PAGE_MASK);
}
return TRUE;
}
@@ -275,18 +232,18 @@ int mips3com_translate_address(mips3_state *mips, int space, int intention, offs
void mips3com_tlbr(mips3_state *mips)
{
- UINT32 index = mips->cpr[0][COP0_Index] & 0x3f;
+ UINT32 tlbindex = mips->cpr[0][COP0_Index] & 0x3f;
/* only handle entries within the TLB */
- if (index < ARRAY_LENGTH(mips->tlb))
+ if (tlbindex < ARRAY_LENGTH(mips->tlb))
{
- mips3_tlb_entry *tlbent = &mips->tlb[index];
+ mips3_tlb_entry *entry = &mips->tlb[tlbindex];
/* copy data from the TLB entry into the COP0 registers */
- mips->cpr[0][COP0_PageMask] = tlbent->page_mask;
- mips->cpr[0][COP0_EntryHi] = tlbent->entry_hi;
- mips->cpr[0][COP0_EntryLo0] = tlbent->entry_lo[0];
- mips->cpr[0][COP0_EntryLo1] = tlbent->entry_lo[1];
+ mips->cpr[0][COP0_PageMask] = entry->page_mask;
+ mips->cpr[0][COP0_EntryHi] = entry->entry_hi;
+ mips->cpr[0][COP0_EntryLo0] = entry->entry_lo[0];
+ mips->cpr[0][COP0_EntryLo1] = entry->entry_lo[1];
}
}
@@ -310,14 +267,14 @@ void mips3com_tlbwr(mips3_state *mips)
{
UINT32 wired = mips->cpr[0][COP0_Wired] & 0x3f;
UINT32 unwired = ARRAY_LENGTH(mips->tlb) - wired;
- UINT32 index = ARRAY_LENGTH(mips->tlb) - 1;
+ UINT32 tlbindex = ARRAY_LENGTH(mips->tlb) - 1;
/* "random" is based off of the current cycle counting through the non-wired pages */
if (unwired > 0)
- index = ((activecpu_gettotalcycles() - mips->count_zero_time) % unwired + wired) & 0x3f;
+ tlbindex = ((activecpu_gettotalcycles() - mips->count_zero_time) % unwired + wired) & 0x3f;
- /* use the common handler to write to this index */
- tlb_write_common(mips, index);
+ /* use the common handler to write to this tlbindex */
+ tlb_write_common(mips, tlbindex);
}
@@ -327,35 +284,29 @@ void mips3com_tlbwr(mips3_state *mips)
void mips3com_tlbp(mips3_state *mips)
{
- UINT32 index;
+ UINT32 tlbindex;
UINT64 vpn;
/* iterate over TLB entries */
- for (index = 0; index < ARRAY_LENGTH(mips->tlb); index++)
+ for (tlbindex = 0; tlbindex < ARRAY_LENGTH(mips->tlb); tlbindex++)
{
- mips3_tlb_entry *tlbent = &mips->tlb[index];
- UINT64 mask = ~((tlbent->page_mask >> 13) & 0xfff) << 13;
+ mips3_tlb_entry *entry = &mips->tlb[tlbindex];
+ UINT64 mask = ~((entry->page_mask >> 13) & 0xfff) << 13;
/* if the relevant bits of EntryHi match the relevant bits of the TLB */
- if ((tlbent->entry_hi & mask) == (mips->cpr[0][COP0_EntryHi] & mask))
+ if ((entry->entry_hi & mask) == (mips->cpr[0][COP0_EntryHi] & mask))
/* and if we are either global or matching the current ASID, then stop */
- if ((tlbent->entry_hi & 0xff) == (mips->cpr[0][COP0_EntryHi] & 0xff) || ((tlbent->entry_lo[0] & tlbent->entry_lo[1]) & TLB_GLOBAL))
+ if ((entry->entry_hi & 0xff) == (mips->cpr[0][COP0_EntryHi] & 0xff) || ((entry->entry_lo[0] & entry->entry_lo[1]) & TLB_GLOBAL))
break;
}
/* validate that our tlb_table was in sync */
vpn = ((mips->cpr[0][COP0_EntryHi] >> 13) & 0x07ffffff) << 1;
- if (index != ARRAY_LENGTH(mips->tlb))
- {
- assert(mips->tlb_table[vpn & 0xfffff] & TLB_PRESENT);
- mips->cpr[0][COP0_Index] = index;
- }
+ if (tlbindex != ARRAY_LENGTH(mips->tlb))
+ mips->cpr[0][COP0_Index] = tlbindex;
else
- {
- assert(!(mips->tlb_table[vpn & 0xfffff] & TLB_PRESENT));
mips->cpr[0][COP0_Index] = 0x80000000;
- }
}
@@ -828,32 +779,90 @@ static UINT32 compute_prid_register(const mips3_state *mips)
/*-------------------------------------------------
+ tlb_map_entry - map a single TLB
+ entry
+-------------------------------------------------*/
+
+static void tlb_map_entry(mips3_state *mips, int tlbindex)
+{
+ int current_asid = mips->cpr[0][COP0_EntryHi] & 0xff;
+ mips3_tlb_entry *entry = &mips->tlb[tlbindex];
+ UINT32 count, vpn;
+ int which;
+
+ /* the ASID doesn't match the current ASID, and if the page isn't global, unmap it from the TLB */
+ if (!tlb_entry_matches_asid(entry, current_asid) && !tlb_entry_is_global(entry))
+ {
+ vtlb_load(mips->vtlb, 2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(mips->vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ return;
+ }
+
+ /* extract the VPN index; ignore if the virtual address is beyond 32 bits */
+ vpn = ((entry->entry_hi >> 13) & 0x07ffffff) << 1;
+ if (vpn >= (1 << (MIPS3_MAX_PADDR_SHIFT - MIPS3_MIN_PAGE_SHIFT)))
+ {
+ vtlb_load(mips->vtlb, 2 * tlbindex + 0, 0, 0, 0);
+ vtlb_load(mips->vtlb, 2 * tlbindex + 1, 0, 0, 0);
+ return;
+ }
+
+ /* get the number of pages from the page mask */
+ count = ((entry->page_mask >> 13) & 0x00fff) + 1;
+
+ /* loop over both the even and odd pages */
+ for (which = 0; which < 2; which++)
+ {
+ UINT32 effvpn = vpn + count * which;
+ UINT64 lo = entry->entry_lo[which];
+ UINT32 pfn = (lo >> 6) & 0x00ffffff;
+ UINT32 flags = 0;
+
+ /* valid? */
+ if ((lo & 2) != 0)
+ {
+ flags |= VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED;
+
+ /* writable? */
+ if ((lo & 4) != 0)
+ flags |= VTLB_WRITE_ALLOWED;
+
+ /* mirror the flags for user mode if the VPN is in user space */
+ if (effvpn < (0x80000000 >> MIPS3_MIN_PAGE_SHIFT))
+ flags |= (flags << 4) & (VTLB_USER_READ_ALLOWED | VTLB_USER_WRITE_ALLOWED | VTLB_USER_FETCH_ALLOWED);
+ }
+
+ /* load the virtual TLB with the corresponding entries */
+ if ((effvpn + count) <= (0x80000000 >> MIPS3_MIN_PAGE_SHIFT) || effvpn >= (0xc0000000 >> MIPS3_MIN_PAGE_SHIFT))
+ vtlb_load(mips->vtlb, 2 * tlbindex + which, count, effvpn << MIPS3_MIN_PAGE_SHIFT, (pfn << MIPS3_MIN_PAGE_SHIFT) | flags);
+ }
+}
+
+
+/*-------------------------------------------------
tlb_write_common - common routine for writing
a TLB entry
-------------------------------------------------*/
-static void tlb_write_common(mips3_state *mips, int index)
+static void tlb_write_common(mips3_state *mips, int tlbindex)
{
/* only handle entries within the TLB */
- if (index < ARRAY_LENGTH(mips->tlb))
+ if (tlbindex < ARRAY_LENGTH(mips->tlb))
{
- mips3_tlb_entry *tlbent = &mips->tlb[index];
-
- /* unmap what we have */
- mips3com_unmap_tlb_entries(mips);
+ mips3_tlb_entry *entry = &mips->tlb[tlbindex];
/* fill in the new TLB entry from the COP0 registers */
- tlbent->page_mask = mips->cpr[0][COP0_PageMask];
- tlbent->entry_hi = mips->cpr[0][COP0_EntryHi] & ~(tlbent->page_mask & U64(0x0000000001ffe000));
- tlbent->entry_lo[0] = mips->cpr[0][COP0_EntryLo0];
- tlbent->entry_lo[1] = mips->cpr[0][COP0_EntryLo1];
+ entry->page_mask = mips->cpr[0][COP0_PageMask];
+ entry->entry_hi = mips->cpr[0][COP0_EntryHi] & ~(entry->page_mask & U64(0x0000000001ffe000));
+ entry->entry_lo[0] = mips->cpr[0][COP0_EntryLo0];
+ entry->entry_lo[1] = mips->cpr[0][COP0_EntryLo1];
- /* remap the TLB */
- mips3com_map_tlb_entries(mips);
+ /* remap this TLB entry */
+ tlb_map_entry(mips, tlbindex);
/* log the two halves once they are in */
- tlb_entry_log_half(tlbent, index, 0);
- tlb_entry_log_half(tlbent, index, 1);
+ tlb_entry_log_half(entry, tlbindex, 0);
+ tlb_entry_log_half(entry, tlbindex, 1);
}
}
@@ -863,24 +872,24 @@ static void tlb_write_common(mips3_state *mips, int index)
entry
-------------------------------------------------*/
-static void tlb_entry_log_half(mips3_tlb_entry *tlbent, int index, int which)
+static void tlb_entry_log_half(mips3_tlb_entry *entry, int tlbindex, int which)
{
#if PRINTF_TLB
- UINT64 hi = tlbent->entry_hi;
- UINT64 lo = tlbent->entry_lo[which];
+ UINT64 hi = entry->entry_hi;
+ UINT64 lo = entry->entry_lo[which];
UINT32 vpn = (((hi >> 13) & 0x07ffffff) << 1);
UINT32 asid = hi & 0xff;
UINT32 r = (hi >> 62) & 3;
UINT32 pfn = (lo >> 6) & 0x00ffffff;
UINT32 c = (lo >> 3) & 7;
- UINT32 pagesize = (((tlbent->page_mask >> 13) & 0xfff) + 1) << MIPS3_MIN_PAGE_SHIFT;
+ UINT32 pagesize = (((entry->page_mask >> 13) & 0xfff) + 1) << MIPS3_MIN_PAGE_SHIFT;
UINT64 vaddr = (UINT64)vpn * MIPS3_MIN_PAGE_SIZE;
UINT64 paddr = (UINT64)pfn * MIPS3_MIN_PAGE_SIZE;
vaddr += pagesize * which;
- mame_printf_debug("index=%08X pagesize=%08X vaddr=%08X%08X paddr=%08X%08X asid=%02X r=%X c=%X dvg=%c%c%c\n",
- index, pagesize, (UINT32)(vaddr >> 32), (UINT32)vaddr, (UINT32)(paddr >> 32), (UINT32)paddr,
+ printf("index=%08X pagesize=%08X vaddr=%08X%08X paddr=%08X%08X asid=%02X r=%X c=%X dvg=%c%c%c\n",
+ tlbindex, pagesize, (UINT32)(vaddr >> 32), (UINT32)vaddr, (UINT32)(paddr >> 32), (UINT32)paddr,
asid, r, c, (lo & 4) ? 'd' : '.', (lo & 2) ? 'v' : '.', (lo & 1) ? 'g' : '.');
#endif
}
diff --git a/src/emu/cpu/mips/mips3com.h b/src/emu/cpu/mips/mips3com.h
index b970b659b48..67de9a615d9 100644
--- a/src/emu/cpu/mips/mips3com.h
+++ b/src/emu/cpu/mips/mips3com.h
@@ -11,6 +11,7 @@
#include "cpuintrf.h"
#include "mips3.h"
+#include "cpu/vtlb.h"
/***************************************************************************
@@ -205,8 +206,8 @@ struct _mips3_state
size_t dcache_size;
/* MMU */
+ vtlb_state * vtlb;
mips3_tlb_entry tlb[MIPS3_TLB_ENTRIES];
- UINT32 * tlb_table;
/* for use by specific implementations */
mips3imp_state *impstate;
@@ -218,16 +219,18 @@ struct _mips3_state
FUNCTION PROTOTYPES
***************************************************************************/
-size_t mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const mips3_config *config, int (*irqcallback)(int), void *memory);
+void mips3com_init(mips3_state *mips, mips3_flavor flavor, int bigendian, int index, int clock, const mips3_config *config, int (*irqcallback)(int));
+void mips3com_exit(mips3_state *mips);
+
void mips3com_reset(mips3_state *mips);
#ifdef ENABLE_DEBUGGER
offs_t mips3com_dasm(mips3_state *mips, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
#endif
void mips3com_update_cycle_counting(mips3_state *mips);
+void mips3com_map_tlb_entry(mips3_state *mips, int tlbindex);
void mips3com_map_tlb_entries(mips3_state *mips);
-void mips3com_unmap_tlb_entries(mips3_state *mips);
-void mips3com_recompute_tlb_table(mips3_state *mips);
+void mips3com_asid_changed(mips3_state *mips);
int mips3com_translate_address(mips3_state *mips, int space, int intention, offs_t *address);
void mips3com_tlbr(mips3_state *mips);
void mips3com_tlbwi(mips3_state *mips);
diff --git a/src/emu/cpu/mips/mips3drc.c b/src/emu/cpu/mips/mips3drc.c
index 8f8dbccb403..225f58dfe19 100644
--- a/src/emu/cpu/mips/mips3drc.c
+++ b/src/emu/cpu/mips/mips3drc.c
@@ -353,26 +353,19 @@ static void mips3_init(mips3_flavor flavor, int bigendian, int index, int clock,
drccache *cache;
drcbe_info beinfo;
UINT32 flags = 0;
- size_t extrasize;
- void *extramem;
int regnum;
- /* determine how much memory beyond the core size we need */
- extrasize = mips3com_init(NULL, flavor, bigendian, index, clock, config, irqcallback, NULL);
-
/* allocate enough space for the cache and the core */
- cache = drccache_alloc(CACHE_SIZE + sizeof(*mips3) + extrasize);
+ cache = drccache_alloc(CACHE_SIZE + sizeof(*mips3));
if (cache == NULL)
- fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*mips3) + extrasize));
+ fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*mips3)));
- /* allocate the core and the extra memory */
+ /* allocate the core memory */
mips3 = drccache_memory_alloc_near(cache, sizeof(*mips3));
memset(mips3, 0, sizeof(*mips3));
- extramem = drccache_memory_alloc(cache, extrasize);
- memset(extramem, 0, extrasize);
/* initialize the core */
- mips3com_init(mips3, flavor, bigendian, index, clock, config, irqcallback, extramem);
+ mips3com_init(mips3, flavor, bigendian, index, clock, config, irqcallback);
/* allocate the implementation-specific state from the full cache */
mips3->impstate = drccache_memory_alloc_near(cache, sizeof(*mips3->impstate));
@@ -532,6 +525,8 @@ static int mips3_execute(int cycles)
static void mips3_exit(void)
{
+ mips3com_exit(mips3);
+
/* clean up the DRC */
drcfe_exit(mips3->impstate->drcfe);
drcuml_free(mips3->impstate->drcuml);
@@ -1063,17 +1058,17 @@ static void static_generate_tlb_mismatch(drcuml_state *drcuml)
UML_RECOVER(block, IREG(0), MAPVAR_PC); // recover i0,PC
UML_MOV(block, MEM(&mips3->pc), IREG(0)); // mov <pc>,i0
UML_SHR(block, IREG(1), IREG(0), IMM(12)); // shr i1,i0,12
- UML_LOAD(block, IREG(1), mips3->tlb_table, IREG(1), DWORD); // load i1,[tlb_table],i1,dword
+ UML_LOAD(block, IREG(1), (void *)vtlb_table(mips3->vtlb), IREG(1), DWORD); // load i1,[vtlb_table],i1,dword
if (PRINTF_MMU)
{
UML_MOV(block, MEM(&mips3->impstate->arg0), IREG(0)); // mov [arg0],i0
UML_MOV(block, MEM(&mips3->impstate->arg1), IREG(1)); // mov [arg1],i1
UML_CALLC(block, cfunc_printf_debug, "TLB mismatch @ %08X (ent=%08X)\n"); // callc printf_debug
}
- UML_TEST(block, IREG(1), IMM(TLB_VALID)); // test i1,TLB_VALID
+ UML_TEST(block, IREG(1), IMM(VTLB_FETCH_ALLOWED)); // test i1,VTLB_FETCH_ALLOWED
UML_JMPc(block, IF_NZ, 1); // jmp 1,nz
- UML_TEST(block, IREG(1), IMM(TLB_PRESENT)); // test i1,TLB_PRESENT
- UML_EXHc(block, IF_NZ, mips3->impstate->exception[EXCEPTION_TLBLOAD], IREG(0)); // exh exception[TLBLOAD],i0,nz
+ UML_TEST(block, IREG(1), IMM(VTLB_FLAG_VALID)); // test i1,VTLB_FLAG_VALID
+ UML_EXHc(block, IF_Z, mips3->impstate->exception[EXCEPTION_TLBLOAD], IREG(0)); // exh exception[TLBLOAD],i0,z
UML_EXH(block, mips3->impstate->exception[EXCEPTION_TLBLOAD_FILL], IREG(0)); // exh exception[TLBLOAD_FILL],i0
UML_LABEL(block, 1); // 1:
save_fast_iregs(block);
@@ -1229,8 +1224,8 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int
/* general case: assume paging and perform a translation */
UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12
- UML_LOAD(block, IREG(3), mips3->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword
- UML_TEST(block, IREG(3), IMM(iswrite ? TLB_DIRTY : TLB_VALID)); // test i3,iswrite ? TLB_DIRTY : TLB_VALID
+ UML_LOAD(block, IREG(3), (void *)vtlb_table(mips3->vtlb), IREG(3), DWORD); // load i3,[vtlb_table],i3,dword
+ UML_TEST(block, IREG(3), IMM(iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED));// test i3,iswrite ? VTLB_WRITE_ALLOWED : VTLB_READ_ALLOWED
UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000
@@ -1385,12 +1380,12 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int
UML_LABEL(block, tlbmiss); // tlbmiss:
if (iswrite)
{
- UML_TEST(block, IREG(3), IMM(TLB_VALID)); // test i3,TLB_VALID
+ UML_TEST(block, IREG(3), IMM(VTLB_READ_ALLOWED)); // test i3,VTLB_READ_ALLOWED
UML_EXHc(block, IF_NZ, mips3->impstate->exception[EXCEPTION_TLBMOD], IREG(0));
// exh tlbmod,i0,nz
}
- UML_TEST(block, IREG(3), IMM(TLB_PRESENT)); // test i3,TLB_PRESENT
- UML_EXHc(block, IF_NZ, exception_tlb, IREG(0)); // exh tlb,i0,nz
+ UML_TEST(block, IREG(3), IMM(VTLB_FLAG_VALID)); // test i3,VTLB_FLAG_VALID
+ UML_EXHc(block, IF_Z, exception_tlb, IREG(0)); // exh tlb,i0,z
UML_EXH(block, exception_tlbfill, IREG(0)); // exh tlbfill,i0
}
@@ -1590,16 +1585,18 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c
/* validate our TLB entry at this PC; if we fail, we need to handle it */
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (desc->pc < 0x80000000 || desc->pc >= 0xc0000000))
{
+ const vtlb_entry *tlbtable = vtlb_table(mips3->vtlb);
+
/* if we currently have a valid TLB read entry, we just verify */
- if (mips3->tlb_table[desc->pc >> 12] & TLB_VALID)
+ if (tlbtable[desc->pc >> 12] & VTLB_FETCH_ALLOWED)
{
if (PRINTF_MMU)
{
UML_MOV(block, MEM(&mips3->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc
UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug
}
- UML_LOAD(block, IREG(0), &mips3->tlb_table[desc->pc >> 12], IMM(0), DWORD);// load i0,tlb_table[desc->pc >> 12],0,dword
- UML_CMP(block, IREG(0), IMM(mips3->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry
+ UML_LOAD(block, IREG(0), &tlbtable[desc->pc >> 12], IMM(0), DWORD); // load i0,tlbtable[desc->pc >> 12],0,dword
+ UML_CMP(block, IREG(0), IMM(tlbtable[desc->pc >> 12])); // cmp i0,*tlbentry
UML_EXHc(block, IF_NE, mips3->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE
}
@@ -2781,8 +2778,7 @@ static int generate_set_cop0_reg(drcuml_block *block, compiler_state *compiler,
UML_MOV(block, CPR032(reg), IREG(0)); // mov cpr0[reg],i0
UML_TEST(block, IREG(1), IMM(0xff)); // test i1,0xff
UML_JMPc(block, IF_Z, link = compiler->labelnum++); // jmp link,z
- UML_CALLC(block, mips3com_unmap_tlb_entries, mips3); // callc mips3com_unmap_tlb_entries
- UML_CALLC(block, mips3com_map_tlb_entries, mips3); // callc mips3com_map_tlb_entries
+ UML_CALLC(block, mips3com_asid_changed, mips3); // callc mips3com_asid_changed
UML_LABEL(block, link); // link:
return TRUE;
diff --git a/src/emu/cpu/powerpc/ppccom.c b/src/emu/cpu/powerpc/ppccom.c
index 6994c73c52a..6a56669d009 100644
--- a/src/emu/cpu/powerpc/ppccom.c
+++ b/src/emu/cpu/powerpc/ppccom.c
@@ -14,7 +14,6 @@
DEBUGGING
***************************************************************************/
-#define PRINTF_TLB_FILL (1)
#define PRINTF_SPU (0)
#define PRINTF_DECREMENTER (0)
@@ -61,51 +60,6 @@ INLINE int page_access_allowed(int transtype, UINT8 key, UINT8 protbits)
/*-------------------------------------------------
- tlb_entry_free - free an entry from the TLB,
- by index
--------------------------------------------------*/
-
-INLINE void tlb_entry_free(powerpc_state *ppc, int entrynum)
-{
- int oldentry = ppc->tlb_entries[entrynum];
-
- /* if we're mapped to something, free the entry in the table */
- if (oldentry != 0)
- {
- ppc->tlb_table[oldentry - 1] = 0;
- ppc->tlb_entries[entrynum] = 0;
- }
-}
-
-
-/*-------------------------------------------------
- tlb_entry_allocate - allocate a TLB entry
- for the given address, if needed, and set its
- new value
--------------------------------------------------*/
-
-INLINE int tlb_entry_allocate(powerpc_state *ppc, int entrynum, offs_t address, UINT32 value)
-{
- UINT32 *entry = &ppc->tlb_table[address >> 12];
- int allocated = FALSE;
-
- /* only need to allocate if we are empty */
- if (*entry == 0)
- {
- /* if there's already a TLB entry at the current index, zap it */
- tlb_entry_free(ppc, entrynum);
-
- /* allocate a new entry and advance to the next one */
- ppc->tlb_entries[entrynum] = (address >> 12) + 1;
- allocated = TRUE;
- }
- *entry = value;
-
- return allocated;
-}
-
-
-/*-------------------------------------------------
get_cr - return the current CR value
-------------------------------------------------*/
@@ -229,12 +183,8 @@ INLINE void set_decrementer(powerpc_state *ppc, UINT32 newdec)
structure based on the configured type
-------------------------------------------------*/
-size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int), void *memory)
+void ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int))
{
- /* if no memory, return the amount needed */
- if (memory == NULL)
- return sizeof(ppc->tlb_table[0]) * (POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES + (1 << (32 - POWERPC_MIN_PAGE_SHIFT)));
-
/* initialize based on the config */
memset(ppc, 0, sizeof(*ppc));
ppc->cpunum = cpu_getactivecpu();
@@ -247,9 +197,8 @@ size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_
ppc->system_clock = (config != NULL) ? config->bus_frequency : clock;
ppc->tb_divisor = (ppc->tb_divisor * clock + ppc->system_clock / 2 - 1) / ppc->system_clock;
- /* initialize the TLB state */
- ppc->tlb_entries = memory;
- ppc->tlb_table = ppc->tlb_entries + POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES;
+ /* allocate the virtual TLB */
+ ppc->vtlb = vtlb_alloc(cpu_getactivecpu(), ADDRESS_SPACE_PROGRAM, (cap & PPCCAP_603_MMU) ? PPC603_FIXED_TLB_ENTRIES : 0, POWERPC_TLB_ENTRIES);
/* allocate a timer for the compare interrupt */
if (cap & PPCCAP_OEA)
@@ -265,7 +214,17 @@ size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_
/* reset the state */
ppccom_reset(ppc);
- return 0;
+}
+
+
+/*-------------------------------------------------
+ ppccom_exit - common cleanup/exit
+-------------------------------------------------*/
+
+void ppccom_exit(powerpc_state *ppc)
+{
+ if (ppc->vtlb != NULL)
+ vtlb_free(ppc->vtlb);
}
@@ -276,6 +235,8 @@ size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_
void ppccom_reset(powerpc_state *ppc)
{
+ int tlbindex;
+
/* initialize the OEA state */
if (ppc->cap & PPCCAP_OEA)
{
@@ -307,9 +268,10 @@ void ppccom_reset(powerpc_state *ppc)
ppc->irq_pending = 0;
/* flush the TLB */
- ppc->tlb_index = 0;
- memset(ppc->tlb_entries, 0, sizeof(ppc->tlb_entries[0]) * (POWERPC_TLB_ENTRIES + PPC603_FIXED_TLB_ENTRIES));
- memset(ppc->tlb_table, 0, sizeof(ppc->tlb_table[0]) * (1 << (32 - POWERPC_MIN_PAGE_SHIFT)));
+ vtlb_flush_dynamic(ppc->vtlb);
+ if (ppc->cap & PPCCAP_603_MMU)
+ for (tlbindex = 0; tlbindex < PPC603_FIXED_TLB_ENTRIES; tlbindex++)
+ vtlb_load(ppc->vtlb, tlbindex, 0, 0, 0);
}
@@ -349,6 +311,28 @@ static UINT32 ppccom_translate_address_internal(powerpc_state *ppc, int intentio
int batbase, batnum, hashnum;
UINT32 segreg;
+ /* 4xx case: "TLB" really just caches writes and checks compare registers */
+ if (ppc->cap & PPCCAP_4XX)
+ {
+ /* we don't support the MMU of the 403GCX */
+ if (ppc->flavor == PPC_MODEL_403GCX && (ppc->msr & MSROEA_DR))
+ fatalerror("MMU enabled but not supported!");
+
+ /* only check if PE is enabled */
+ if (transtype == TRANSLATE_WRITE && (ppc->msr & MSR4XX_PE))
+ {
+ /* are we within one of the protection ranges? */
+ int inrange1 = ((*address >> 12) >= (ppc->spr[SPR4XX_PBL1] >> 12) && (*address >> 12) < (ppc->spr[SPR4XX_PBU1] >> 12));
+ int inrange2 = ((*address >> 12) >= (ppc->spr[SPR4XX_PBL2] >> 12) && (*address >> 12) < (ppc->spr[SPR4XX_PBU2] >> 12));
+
+ /* if PX == 1, writes are only allowed OUTSIDE of the bounds */
+ if (((ppc->msr & MSR4XX_PX) && (inrange1 || inrange2)) || (!(ppc->msr & MSR4XX_PX) && (!inrange1 && !inrange2)))
+ return 0x002;
+ }
+ *address &= 0x7fffffff;
+ return 0x001;
+ }
+
/* only applies if we support the OEA */
if (!(ppc->cap & PPCCAP_OEA))
return 0x001;
@@ -471,56 +455,7 @@ int ppccom_translate_address(powerpc_state *ppc, int space, int intention, offs_
void ppccom_tlb_fill(powerpc_state *ppc)
{
- int transuser = (ppc->msr & MSR_PR) ? TRANSLATE_USER_MASK : 0;
- offs_t address = ppc->param0;
- int transtype = ppc->param1;
- offs_t transaddr = address;
- UINT32 entryval;
-
- /* 4xx case: "TLB" really just caches writes and checks compare registers */
- if (ppc->cap & PPCCAP_4XX)
- {
- /* assume success and direct translation */
- ppc->param0 = 1;
- transaddr = address & 0x7fffffff;
-
- /* we don't support the MMU of the 403GCX */
- if (ppc->flavor == PPC_MODEL_403GCX && (ppc->msr & MSROEA_DR))
- fatalerror("MMU enabled but not supported!");
-
- /* only check if PE is enabled */
- if (transtype == TRANSLATE_WRITE && (ppc->msr & MSR4XX_PE))
- {
- /* are we within one of the protection ranges? */
- int inrange1 = ((address >> 12) >= (ppc->spr[SPR4XX_PBL1] >> 12) && (address >> 12) < (ppc->spr[SPR4XX_PBU1] >> 12));
- int inrange2 = ((address >> 12) >= (ppc->spr[SPR4XX_PBL2] >> 12) && (address >> 12) < (ppc->spr[SPR4XX_PBU2] >> 12));
-
- /* if PX == 1, writes are only allowed OUTSIDE of the bounds */
- if (((ppc->msr & MSR4XX_PX) && (inrange1 || inrange2)) || (!(ppc->msr & MSR4XX_PX) && (!inrange1 && !inrange2)))
- ppc->param0 = 2;
- }
- }
-
- /* OEA case: perform an address translation */
- else
- ppc->param0 = ppccom_translate_address_internal(ppc, transtype | transuser, &transaddr);
-
- /* log information and return upon failure */
- if (PRINTF_TLB_FILL)
- printf("tlb_fill: %08X (%s%s) -> ", address, (transtype == TRANSLATE_READ) ? "R" : (transtype == TRANSLATE_WRITE) ? "W" : "F", transuser ? "U" : "S");
- if (ppc->param0 > 1)
- {
- if (PRINTF_TLB_FILL)
- printf("failed(%08X)\n", ppc->param0);
- return;
- }
-
- /* if we did translate the address, get a pointer to our entry in the TLB table and fill it in */
- if (PRINTF_TLB_FILL)
- printf("succeeded(%d) -> %08X\n", ppc->param0, transaddr);
- entryval = (transaddr & 0xfffff000) | TLB_READ | ((ppc->param0 & 1) ? TLB_WRITE : 0);
- if (tlb_entry_allocate(ppc, ppc->tlb_index, address, entryval))
- ppc->tlb_index = (ppc->tlb_index + 1) % POWERPC_TLB_ENTRIES;
+ vtlb_fill(ppc->vtlb, ppc->param0, ppc->param1);
}
@@ -531,11 +466,7 @@ void ppccom_tlb_fill(powerpc_state *ppc)
void ppccom_tlb_flush(powerpc_state *ppc)
{
- int entnum;
-
- /* iterate over entries and invalidate them */
- for (entnum = 0; entnum < POWERPC_TLB_ENTRIES; entnum++)
- tlb_entry_free(ppc, entnum);
+ vtlb_flush_dynamic(ppc->vtlb);
}
@@ -551,10 +482,7 @@ void ppccom_tlb_flush(powerpc_state *ppc)
void ppccom_execute_tlbie(powerpc_state *ppc)
{
- offs_t address = ppc->param0;
-
- /* just nuke it in the table; we may have spare entries referencing it, but no harm */
- ppc->tlb_table[address >> 12] = 0;
+ vtlb_flush_address(ppc->vtlb, ppc->param0);
}
@@ -565,7 +493,7 @@ void ppccom_execute_tlbie(powerpc_state *ppc)
void ppccom_execute_tlbia(powerpc_state *ppc)
{
- ppccom_tlb_flush(ppc);
+ vtlb_flush_dynamic(ppc->vtlb);
}
@@ -578,19 +506,21 @@ void ppccom_execute_tlbl(powerpc_state *ppc)
{
UINT32 address = ppc->param0;
int isitlb = ppc->param1;
- UINT32 entrynum, entryval;
-
+ vtlb_entry flags = 0;
+ int entrynum;
+
/* determine entry number; we use rand() for associativity */
entrynum = ((address >> 12) & 0x1f) | (mame_rand(Machine) & 0x20) | (isitlb ? 0x40 : 0);
- /* invalidate any existing TLB entry here */
- ppc->tlb_table[address >> 12] = 0;
+ /* determine the flags */
+ flags = VTLB_FLAG_VALID | VTLB_READ_ALLOWED | VTLB_FETCH_ALLOWED;
+ if (ppc->spr[SPR603_RPA] & 0x80)
+ flags |= VTLB_WRITE_ALLOWED;
+ if (isitlb)
+ flags |= VTLB_FETCH_ALLOWED;
- /* allocate this entry */
- entryval = (ppc->spr[SPR603_RPA] & 0xfffff000) | TLB_READ | ((ppc->spr[SPR603_RPA] & 0x80) ? TLB_WRITE : 0);
- tlb_entry_allocate(ppc, POWERPC_TLB_ENTRIES + entrynum, address, entryval);
- if (PRINTF_TLB_FILL)
- printf("tlb_load: %08X (%sS) -> %08X\n", address, isitlb ? "F" : "R", ppc->spr[SPR603_RPA] & 0xfffff000);
+ /* load the entry */
+ vtlb_load(ppc->vtlb, entrynum, 1, address, (ppc->spr[SPR603_RPA] & 0xfffff000) | flags);
}
@@ -1897,8 +1827,8 @@ void ppc4xx_get_info(powerpc_state *ppc, UINT32 state, cpuinfo *info)
case CPUINFO_INT_DATABUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
case CPUINFO_INT_ADDRBUS_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 31; break;
- case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
- case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = 0; break;
+ case CPUINFO_INT_LOGADDR_WIDTH + ADDRESS_SPACE_PROGRAM: info->i = 32; break;
+ case CPUINFO_INT_PAGE_SHIFT + ADDRESS_SPACE_PROGRAM: info->i = POWERPC_MIN_PAGE_SHIFT;break;
/* --- the following bits of info are returned as pointers to data or functions --- */
case CPUINFO_PTR_INIT: /* provided per-CPU */ break;
diff --git a/src/emu/cpu/powerpc/ppccom.h b/src/emu/cpu/powerpc/ppccom.h
index ff61e82c8e1..e825728a93c 100644
--- a/src/emu/cpu/powerpc/ppccom.h
+++ b/src/emu/cpu/powerpc/ppccom.h
@@ -11,6 +11,7 @@
#include "cpuintrf.h"
#include "ppc.h"
+#include "cpu/vtlb.h"
/***************************************************************************
@@ -39,11 +40,6 @@
#define PPCCAP_603_MMU 0x20 /* TRUE if we have 603-class MMU features */
-/* bits in our internal TLB */
-#define TLB_READ 0x01 /* reads are allowed */
-#define TLB_WRITE 0x02 /* writes are allowed */
-
-
/* PowerPC flavors */
enum _powerpc_flavor
{
@@ -531,9 +527,7 @@ struct _powerpc_state
UINT32 param1;
/* MMU */
- UINT32 * tlb_table;
- UINT32 * tlb_entries;
- UINT32 tlb_index;
+ vtlb_state * vtlb;
/* architectural distinctions */
powerpc_flavor flavor;
@@ -574,7 +568,9 @@ struct _powerpc_state
FUNCTION PROTOTYPES
***************************************************************************/
-size_t ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int), void *memory);
+void ppccom_init(powerpc_state *ppc, powerpc_flavor flavor, UINT8 cap, int tb_divisor, int clock, const powerpc_config *config, int (*irqcallback)(int));
+void ppccom_exit(powerpc_state *ppc);
+
void ppccom_reset(powerpc_state *ppc);
#ifdef ENABLE_DEBUGGER
offs_t ppccom_dasm(powerpc_state *ppc, char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram);
diff --git a/src/emu/cpu/powerpc/ppcdrc.c b/src/emu/cpu/powerpc/ppcdrc.c
index 51597e8e100..6ec4a47680c 100644
--- a/src/emu/cpu/powerpc/ppcdrc.c
+++ b/src/emu/cpu/powerpc/ppcdrc.c
@@ -199,24 +199,24 @@ struct _ppcimp_state
drcuml_codehandle * out_of_cycles; /* out of cycles exception handler */
drcuml_codehandle * tlb_mismatch; /* tlb mismatch handler */
drcuml_codehandle * swap_tgpr; /* swap TGPR handler */
- drcuml_codehandle * lsw[4][32]; /* lsw entries */
- drcuml_codehandle * stsw[4][32]; /* stsw entries */
- drcuml_codehandle * read8[4]; /* read byte */
- drcuml_codehandle * write8[4]; /* write byte */
- drcuml_codehandle * read16[4]; /* read half */
- drcuml_codehandle * read16mask[4]; /* read half */
- drcuml_codehandle * write16[4]; /* write half */
- drcuml_codehandle * write16mask[4]; /* write half */
- drcuml_codehandle * read32[4]; /* read word */
- drcuml_codehandle * read32align[4]; /* read word aligned */
- drcuml_codehandle * read32mask[4]; /* read word */
- drcuml_codehandle * write32[4]; /* write word */
- drcuml_codehandle * write32align[4]; /* write word aligned */
- drcuml_codehandle * write32mask[4]; /* write word */
- drcuml_codehandle * read64[4]; /* read double */
- drcuml_codehandle * read64mask[4]; /* read double */
- drcuml_codehandle * write64[4]; /* write double */
- drcuml_codehandle * write64mask[4]; /* write double */
+ drcuml_codehandle * lsw[8][32]; /* lsw entries */
+ drcuml_codehandle * stsw[8][32]; /* stsw entries */
+ drcuml_codehandle * read8[8]; /* read byte */
+ drcuml_codehandle * write8[8]; /* write byte */
+ drcuml_codehandle * read16[8]; /* read half */
+ drcuml_codehandle * read16mask[8]; /* read half */
+ drcuml_codehandle * write16[8]; /* write half */
+ drcuml_codehandle * write16mask[8]; /* write half */
+ drcuml_codehandle * read32[8]; /* read word */
+ drcuml_codehandle * read32align[8]; /* read word aligned */
+ drcuml_codehandle * read32mask[8]; /* read word */
+ drcuml_codehandle * write32[8]; /* write word */
+ drcuml_codehandle * write32align[8]; /* write word aligned */
+ drcuml_codehandle * write32mask[8]; /* write word */
+ drcuml_codehandle * read64[8]; /* read double */
+ drcuml_codehandle * read64mask[8]; /* read double */
+ drcuml_codehandle * write64[8]; /* write double */
+ drcuml_codehandle * write64mask[8]; /* write double */
drcuml_codehandle * exception[EXCEPTION_COUNT]; /* array of exception handlers */
drcuml_codehandle * exception_norecover[EXCEPTION_COUNT]; /* array of exception handlers */
@@ -545,27 +545,20 @@ static void ppcdrc_init(powerpc_flavor flavor, UINT8 cap, int tb_divisor, int cl
};
drcbe_info beinfo;
UINT32 flags = 0;
- size_t extrasize;
drccache *cache;
- void *extramem;
int regnum;
- /* determine how much memory beyond the core size we need */
- extrasize = ppccom_init(NULL, flavor, cap, tb_divisor, clock, config, irqcallback, NULL);
-
/* allocate enough space for the cache and the core */
- cache = drccache_alloc(CACHE_SIZE + sizeof(*ppc) + extrasize);
+ cache = drccache_alloc(CACHE_SIZE + sizeof(*ppc));
if (cache == NULL)
- fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*ppc) + extrasize));
+ fatalerror("Unable to allocate cache of size %d", (UINT32)(CACHE_SIZE + sizeof(*ppc)));
- /* allocate the core from the near cache, and the extra memory from the full cache */
+ /* allocate the core from the near cache */
ppc = drccache_memory_alloc_near(cache, sizeof(*ppc));
memset(ppc, 0, sizeof(*ppc));
- extramem = drccache_memory_alloc(cache, extrasize);
- memset(extramem, 0, extrasize);
/* initialize the core */
- ppccom_init(ppc, flavor, cap, tb_divisor, clock, config, irqcallback, extramem);
+ ppccom_init(ppc, flavor, cap, tb_divisor, clock, config, irqcallback);
/* allocate the implementation-specific state from the full cache */
ppc->impstate = drccache_memory_alloc_near(cache, sizeof(*ppc->impstate));
@@ -729,6 +722,8 @@ static int ppcdrc_execute(int cycles)
static void ppcdrc_exit(void)
{
+ ppccom_exit(ppc);
+
/* clean up the DRC */
drcfe_exit(ppc->impstate->drcfe);
drcuml_free(ppc->impstate->drcuml);
@@ -897,7 +892,7 @@ static void code_flush_cache(drcuml_state *drcuml)
}
/* add subroutines for memory accesses */
- for (mode = 0; mode < 4; mode++)
+ for (mode = 0; mode < 8; mode++)
{
static_generate_memory_accessor(drcuml, mode, 1, FALSE, FALSE, "read8", &ppc->impstate->read8[mode], NULL);
static_generate_memory_accessor(drcuml, mode, 1, TRUE, FALSE, "write8", &ppc->impstate->write8[mode], NULL);
@@ -1232,8 +1227,10 @@ static void static_generate_tlb_mismatch(drcuml_state *drcuml)
UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0
UML_MOV(block, MEM(&ppc->param1), IMM(TRANSLATE_FETCH)); // mov [param1],TRANSLATE_FETCH
UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc
- UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1
- UML_JMPc(block, IF_A, isi = label++); // jmp isi,A
+ UML_SHR(block, IREG(1), IREG(0), IMM(12)); // shr i1,i0,11
+ UML_LOAD(block, IREG(1), (void *)vtlb_table(ppc->vtlb), IREG(1), DWORD); // load i1,[vtlb],i1,dword
+ UML_TEST(block, IREG(1), IMM(VTLB_FETCH_ALLOWED)); // test i1,VTLB_FETCH_ALLOWED
+ UML_JMPc(block, IF_Z, isi = label++); // jmp isi,z
UML_MOV(block, MEM(&ppc->pc), IREG(0)); // mov <pc>,i0
save_fast_iregs(block); // <save fastregs>
UML_EXIT(block, IMM(EXECUTE_MISSING_CODE)); // exit EXECUTE_MISSING_CODE
@@ -1447,12 +1444,18 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int
int fastxor = BYTE8_XOR_BE(0) >> (activecpu_databus_width(ADDRESS_SPACE_PROGRAM) < 64);
drcuml_block *block;
jmp_buf errorbuf;
+ int translate_type;
int tlbreturn = 0;
int unaligned = 0;
int alignex = 0;
int tlbmiss = 0;
int label = 1;
int ramnum;
+
+ if (mode & MODE_USER)
+ translate_type = iswrite ? TRANSLATE_WRITE_USER : TRANSLATE_READ_USER;
+ else
+ translate_type = iswrite ? TRANSLATE_WRITE : TRANSLATE_READ;
/* if we get an error back, we're screwed */
if (setjmp(errorbuf) != 0)
@@ -1498,8 +1501,8 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int
if (((ppc->cap & PPCCAP_OEA) && (mode & MODE_DATA_TRANSLATION)) || (iswrite && (ppc->cap & PPCCAP_4XX) && (mode & MODE_PROTECTION)))
{
UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12
- UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword
- UML_TEST(block, IREG(3), IMM(iswrite ? TLB_WRITE : TLB_READ)); // test i3,iswrite ? TLB_WRITE : TLB_READ
+ UML_LOAD(block, IREG(3), (void *)vtlb_table(ppc->vtlb), IREG(3), DWORD); // load i3,[vtlb],i3,dword
+ UML_TEST(block, IREG(3), IMM((UINT64)1 << translate_type)); // test i3,1 << translate_type
UML_JMPc(block, IF_Z, tlbmiss = label++); // jmp tlbmiss,z
UML_LABEL(block, tlbreturn = label++); // tlbreturn:
UML_ROLINS(block, IREG(0), IREG(3), IMM(0), IMM(0xfffff000)); // rolins i0,i3,0,0xfffff000
@@ -1786,18 +1789,14 @@ static void static_generate_memory_accessor(drcuml_state *drcuml, int mode, int
/* handle a TLB miss */
if (tlbmiss != 0)
{
- int dsi;
-
UML_LABEL(block, tlbmiss); // tlbmiss:
UML_MOV(block, MEM(&ppc->param0), IREG(0)); // mov [param0],i0
- UML_MOV(block, MEM(&ppc->param1), IMM(iswrite ? TRANSLATE_WRITE : TRANSLATE_READ)); // mov [param1],TRANSLATE_READ/WRITE
+ UML_MOV(block, MEM(&ppc->param1), IMM(translate_type)); // mov [param1],translate_type
UML_CALLC(block, ppccom_tlb_fill, ppc); // callc tlbfill,ppc
- UML_CMP(block, MEM(&ppc->param0), IMM(1)); // cmp [param0],1
- UML_JMPc(block, IF_A, dsi = label++); // jmp dsi,A
UML_SHR(block, IREG(3), IREG(0), IMM(12)); // shr i3,i0,12
- UML_LOAD(block, IREG(3), ppc->tlb_table, IREG(3), DWORD); // load i3,[tlb_table],i3,dword
- UML_JMP(block, tlbreturn); // jmp tlbreturn
- UML_LABEL(block, dsi); // dsi:
+ UML_LOAD(block, IREG(3), (void *)vtlb_table(ppc->vtlb), IREG(3), DWORD); // load i3,[vtlb],i3,dword
+ UML_TEST(block, IREG(3), IMM((UINT64)1 << translate_type)); // test i3,1 << translate_type
+ UML_JMPc(block, IF_NZ, tlbreturn); // jmp tlbreturn,nz
/* 4XX case: protection exception */
if (ppc->cap & PPCCAP_4XX)
@@ -2166,16 +2165,18 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c
/* validate our TLB entry at this PC; if we fail, we need to handle it */
if ((desc->flags & OPFLAG_VALIDATE_TLB) && (ppc->impstate->mode & MODE_DATA_TRANSLATION))
{
+ const vtlb_entry *tlbtable = vtlb_table(ppc->vtlb);
+
/* if we currently have a valid TLB read entry, we just verify */
- if (ppc->tlb_table[desc->pc >> 12] != 0)
+ if (tlbtable[desc->pc >> 12] != 0)
{
if (PRINTF_MMU)
{
UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc
UML_CALLC(block, cfunc_printf_debug, "Checking TLB at @ %08X\n"); // callc printf_debug
}
- UML_LOAD(block, IREG(0), &ppc->tlb_table[desc->pc >> 12], IMM(0), DWORD); // load i0,tlb_table[desc->pc >> 12],dword
- UML_CMP(block, IREG(0), IMM(ppc->tlb_table[desc->pc >> 12])); // cmp i0,*tlbentry
+ UML_LOAD(block, IREG(0), &tlbtable[desc->pc >> 12], IMM(0), DWORD); // load i0,tlbtable[desc->pc >> 12],dword
+ UML_CMP(block, IREG(0), IMM(tlbtable[desc->pc >> 12])); // cmp i0,*tlbentry
UML_EXHc(block, IF_NE, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0,NE
}
@@ -2184,20 +2185,20 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c
{
if (PRINTF_MMU)
{
- UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc
+ UML_MOV(block, MEM(&ppc->impstate->arg0), IMM(desc->pc)); // mov [arg0],desc->pc
UML_CALLC(block, cfunc_printf_debug, "No valid TLB @ %08X\n"); // callc printf_debug
}
- UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0
+ UML_EXH(block, ppc->impstate->tlb_mismatch, IMM(0)); // exh tlb_mismatch,0
}
}
/* if this is an invalid opcode, generate the exception now */
if (desc->flags & OPFLAG_INVALID_OPCODE)
- UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x80000)); // exh exception_program,0x80000
+ UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x80000)); // exh exception_program,0x80000
/* if this is a privileged opcode in user mode, generate the exception */
else if ((desc->flags & OPFLAG_PRIVILEGED) && (ppc->impstate->mode & MODE_USER))
- UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x40000)); // exh exception_program,0x40000
+ UML_EXH(block, ppc->impstate->exception[EXCEPTION_PROGRAM], IMM(0x40000)); // exh exception_program,0x40000
/* otherwise, unless this is a virtual no-op, it's a regular instruction */
else if (!(desc->flags & OPFLAG_VIRTUAL_NOOP))
@@ -2205,7 +2206,7 @@ static void generate_sequence_instruction(drcuml_block *block, compiler_state *c
/* compile the instruction */
if (!generate_opcode(block, compiler, desc))
{
- UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc
+ UML_MOV(block, MEM(&ppc->pc), IMM(desc->pc)); // mov [pc],desc->pc
UML_CALLC(block, cfunc_unimplemented, (void *)(FPTR)*desc->opptr.l); // callc cfunc_unimplemented
}
}
@@ -2493,7 +2494,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x22: /* LBZ */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8
+ UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode]); // callh read8
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2501,7 +2502,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x28: /* LHZ */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2509,7 +2510,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x2a: /* LHA */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2517,7 +2518,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x20: /* LWZ */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2526,7 +2527,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8
+ UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode]); // callh read8
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2536,7 +2537,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2546,7 +2547,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2556,7 +2557,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2566,7 +2567,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8
+ UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode]); // callh write8
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2574,7 +2575,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16
+ UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode]); // callh write16
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2582,7 +2583,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2591,7 +2592,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8
+ UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode]); // callh write8
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2601,7 +2602,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16
+ UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode]); // callh write16
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2611,7 +2612,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2623,7 +2624,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
{
UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RD(op))));
// add i0,[tempaddr],simm + 4*(regnum-rd)
- UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align
+ UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align
UML_MOV(block, R32(regnum), IREG(0)); // mov regnum,i0
}
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2637,7 +2638,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM((INT16)G_SIMM(op) + 4 * (regnum - G_RS(op))));
// add i0,[tempaddr],simm + 4*(regnum-rs)
UML_MOV(block, IREG(1), R32(regnum)); // mov i1,regnum
- UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align
+ UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode]); // callh write32align
}
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2645,7 +2646,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x30: /* LFS */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, MEM(&ppc->impstate->tempdata.w.l), IREG(0)); // mov [tempdata],i0
UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.w.l), DWORD); // fdfrflt fd,[tempdata],dword
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2654,7 +2655,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
case 0x32: /* LFD */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64
+ UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode]); // callh read64
UML_DMOV(block, MEM(&ppc->impstate->tempdata.d), IREG(0)); // dmov [tempdata],i0
UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -2664,7 +2665,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, MEM(&ppc->impstate->tempdata.w.l), IREG(0)); // mov [tempdata],i0
UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.w.l), DWORD); // fdfrflt fd,[tempdata],dword
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
@@ -2675,7 +2676,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_ADD(block, IREG(0), R32(G_RA(op)), IMM((INT16)G_SIMM(op))); // add i0,ra,simm
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64
+ UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode]); // callh read64
UML_DMOV(block, MEM(&ppc->impstate->tempdata.d), IREG(0)); // dmov [tempdata],i0
UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata]
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
@@ -2687,7 +2688,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword
UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata]
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2696,7 +2697,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_FDMOV(block, MEM(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs
UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata]
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMM(op)); // mapvar dsisr,DSISR_IMM(op)
- UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64
+ UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode]); // callh write64
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2706,7 +2707,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata]
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -2717,7 +2718,7 @@ static int generate_opcode(drcuml_block *block, compiler_state *compiler, const
UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata]
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IMMU(op)); // mapvar dsisr,DSISR_IMMU(op)
- UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64
+ UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode]); // callh write64
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3169,7 +3170,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x057: /* LBZX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8
+ UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode]); // callh read8
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3177,7 +3178,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x117: /* LHZX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3185,7 +3186,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x157: /* LHAX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3193,7 +3194,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x017: /* LWZX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3201,7 +3202,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x217: /* LFSX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, MEM(&ppc->impstate->tempdata.w.l), IREG(0)); // mov [tempdata],i0
UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.w.l), DWORD); // fdfrflt fd,[tempdata],dword
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3210,7 +3211,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x257: /* LFDX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64
+ UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode]); // callh read64
UML_DMOV(block, MEM(&ppc->impstate->tempdata.d), IREG(0)); // dmov [tempdata],i0
UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3219,7 +3220,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x316: /* LHBRX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_BSWAP(block, IREG(0), IREG(0)); // bswap i0,i0
UML_SHR(block, R32(G_RD(op)), IREG(0), IMM(16)); // shr rd,i0,16
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3228,7 +3229,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x216: /* LWBRX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align
+ UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align
UML_BSWAP(block, R32(G_RD(op)), IREG(0)); // bswap rd,i0
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3237,7 +3238,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op)
- UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode & 3]); // callh read8
+ UML_CALLH(block, ppc->impstate->read8[ppc->impstate->mode]); // callh read8
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xff)); // and rd,i0,0xff
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3247,7 +3248,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_AND(block, R32(G_RD(op)), IREG(0), IMM(0xffff)); // and rd,i0,0xffff
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3257,7 +3258,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op)
- UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode & 3]); // callh read16
+ UML_CALLH(block, ppc->impstate->read16[ppc->impstate->mode]); // callh read16
UML_SEXT(block, R32(G_RD(op)), IREG(0), WORD); // sext rd,i0,word
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3267,7 +3268,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
@@ -3277,7 +3278,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode & 3]); // callh read32
+ UML_CALLH(block, ppc->impstate->read32[ppc->impstate->mode]); // callh read32
UML_MOV(block, MEM(&ppc->impstate->tempdata.w.l), IREG(0)); // mov [tempdata],i0
UML_FDFRFLT(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.w.l), DWORD); // fdfrflt fd,[tempdata],dword
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
@@ -3288,7 +3289,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode & 3]); // callh read64
+ UML_CALLH(block, ppc->impstate->read64[ppc->impstate->mode]); // callh read64
UML_DMOV(block, MEM(&ppc->impstate->tempdata.d), IREG(0)); // dmov [tempdata],i0
UML_FDMOV(block, F64(G_RD(op)), MEM(&ppc->impstate->tempdata.d)); // fdmov fd,[tempdata]
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
@@ -3298,7 +3299,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x014: /* LWARX */
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode & 3]); // callh read32align
+ UML_CALLH(block, ppc->impstate->read32align[ppc->impstate->mode]); // callh read32align
UML_MOV(block, R32(G_RD(op)), IREG(0)); // mov rd,i0
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3306,7 +3307,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x255: /* LSWI */
UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra
UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],G_NB
- UML_CALLH(block, ppc->impstate->lsw[ppc->impstate->mode & 3][G_RD(op)]); // call lsw[rd]
+ UML_CALLH(block, ppc->impstate->lsw[ppc->impstate->mode][G_RD(op)]); // call lsw[rd]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3314,7 +3315,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb
UML_AND(block, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f)); // and [swcount],[xer],0x7f
UML_SUB(block, MEM(&ppc->icount), MEM(&ppc->icount), MEM(&ppc->impstate->swcount));// sub icount,icount,[swcount]
- UML_CALLHc(block, IF_NZ, ppc->impstate->lsw[ppc->impstate->mode & 3][G_RD(op)]);// call lsw[rd],nz
+ UML_CALLHc(block, IF_NZ, ppc->impstate->lsw[ppc->impstate->mode][G_RD(op)]);// call lsw[rd],nz
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3326,7 +3327,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8
+ UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode]); // callh write8
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3334,7 +3335,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16
+ UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode]); // callh write16
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3342,7 +3343,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3351,7 +3352,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_FSFRFLT(block, MEM(&ppc->impstate->tempdata.w.l), F64(G_RS(op)), QWORD); // fsfrflt [tempdata],rs,qword
UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata]
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3360,7 +3361,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_FDMOV(block, MEM(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs
UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata.lo]
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3369,7 +3370,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_FDMOV(block, MEM(&ppc->impstate->tempdata.d), F64(G_RS(op))); // fdmov [tempdata],rs
UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata]
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64
+ UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode]); // callh write64
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3378,7 +3379,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs
UML_SHR(block, IREG(1), IREG(1), IMM(16)); // shr i1,i1,16
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16
+ UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode]); // callh write16
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3386,7 +3387,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_BSWAP(block, IREG(1), R32(G_RS(op))); // bswap i1,rs
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3395,7 +3396,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xff)); // and i1,rs,0xff
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode & 3]); // callh write8
+ UML_CALLH(block, ppc->impstate->write8[ppc->impstate->mode]); // callh write8
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3405,7 +3406,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_AND(block, IREG(1), R32(G_RS(op)), IMM(0xffff)); // and i1,rs,0xffff
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode & 3]); // callh write16
+ UML_CALLH(block, ppc->impstate->write16[ppc->impstate->mode]); // callh write16
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3415,7 +3416,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDXU(op)); // mapvar dsisr,DSISR_IDXU(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3426,7 +3427,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_MOV(block, IREG(1), MEM(&ppc->impstate->tempdata.w.l)); // mov i1,[tempdata]
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode & 3]); // callh write32
+ UML_CALLH(block, ppc->impstate->write32[ppc->impstate->mode]); // callh write32
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3437,7 +3438,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_DMOV(block, IREG(1), MEM(&ppc->impstate->tempdata.d)); // dmov i1,[tempdata]
UML_MOV(block, MEM(&ppc->impstate->updateaddr), IREG(0)); // mov [updateaddr],i0
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64
+ UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode]); // callh write64
UML_MOV(block, R32(G_RA(op)), MEM(&ppc->impstate->updateaddr)); // mov ra,[updateaddr]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3446,7 +3447,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, IREG(0), R32Z(G_RA(op)), R32(G_RB(op))); // add i0,ra,rb
UML_MOV(block, IREG(1), R32(G_RS(op))); // mov i1,rs
UML_MAPVAR(block, MAPVAR_DSISR, DSISR_IDX(op)); // mapvar dsisr,DSISR_IDX(op)
- UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode & 3]); // callh write32align
+ UML_CALLH(block, ppc->impstate->write32align[ppc->impstate->mode]); // callh write32align
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
UML_CMP(block, IREG(0), IREG(0)); // cmp i0,i0
generate_compute_flags(block, desc, TRUE, 0, FALSE); // <update flags>
@@ -3455,7 +3456,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
case 0x2d5: /* STSWI */
UML_MOV(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op))); // mov [updateaddr],ra
UML_MOV(block, MEM(&ppc->impstate->swcount), IMM(((G_NB(op) - 1) & 0x1f) + 1)); // mov [swcount],G_NB
- UML_CALLH(block, ppc->impstate->stsw[ppc->impstate->mode & 3][G_RD(op)]); // call stsw[rd]
+ UML_CALLH(block, ppc->impstate->stsw[ppc->impstate->mode][G_RD(op)]); // call stsw[rd]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3463,7 +3464,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
UML_ADD(block, MEM(&ppc->impstate->updateaddr), R32Z(G_RA(op)), R32(G_RB(op))); // add [updateaddr],ra,rb
UML_AND(block, MEM(&ppc->impstate->swcount), SPR32(SPR_XER), IMM(0x7f)); // and [swcount],[xer],0x7f
UML_SUB(block, MEM(&ppc->icount), MEM(&ppc->icount), MEM(&ppc->impstate->swcount));// sub icount,icount,[swcount]
- UML_CALLHc(block, IF_NZ, ppc->impstate->stsw[ppc->impstate->mode & 3][G_RD(op)]);// call stsw[rd]
+ UML_CALLHc(block, IF_NZ, ppc->impstate->stsw[ppc->impstate->mode][G_RD(op)]);// call stsw[rd]
generate_update_cycles(block, compiler, IMM(desc->pc + 4), TRUE); // <update cycles>
return TRUE;
@@ -3491,7 +3492,7 @@ static int generate_instruction_1f(drcuml_block *block, compiler_state *compiler
{
UML_ADD(block, IREG(0), MEM(&ppc->impstate->tempaddr), IMM(8 * item)); // add i0,[tempaddr],8*item
UML_DMOV(block, IREG(1), IMM(0)); // dmov i1,0
- UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode & 3]); // callh write64
+ UML_CALLH(block, ppc->impstate->write64[ppc->impstate->mode]); // callh write64
}
return TRUE;
diff --git a/src/emu/cpu/vtlb.c b/src/emu/cpu/vtlb.c
new file mode 100644
index 00000000000..932b3b4c5a5
--- /dev/null
+++ b/src/emu/cpu/vtlb.c
@@ -0,0 +1,284 @@
+/***************************************************************************
+
+ 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 "vtlb.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define PRINTF_TLB (0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* VTLB state */
+struct _vtlb_state
+{
+ 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 */
+ cpu_translate_func translate; /* translate function */
+};
+
+
+
+/***************************************************************************
+ INITIALIZATION/TEARDOWN
+***************************************************************************/
+
+/*-------------------------------------------------
+ vtlb_alloc - allocate a new VTLB for the
+ given CPU
+-------------------------------------------------*/
+
+vtlb_state *vtlb_alloc(int cpunum, int space, int fixed_entries, int dynamic_entries)
+{
+ vtlb_state *vtlb;
+
+ /* allocate memory for the core structure */
+ vtlb = malloc_or_die(sizeof(*vtlb));
+ memset(vtlb, 0, sizeof(*vtlb));
+
+ /* fill in CPU information */
+ vtlb->space = space;
+ vtlb->dynamic = dynamic_entries;
+ vtlb->fixed = fixed_entries;
+ vtlb->pageshift = cpunum_page_shift(cpunum, space);
+ vtlb->addrwidth = cpunum_logaddr_width(cpunum, space);
+ vtlb->translate = (cpu_translate_func)cpunum_get_info_fct(cpunum, CPUINFO_PTR_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 = malloc_or_die(sizeof(vtlb->live[0]) * (fixed_entries + dynamic_entries));
+ memset(vtlb->live, 0, sizeof(vtlb->live[0]) * (fixed_entries + dynamic_entries));
+
+ /* allocate the lookup table */
+ vtlb->table = malloc_or_die(sizeof(vtlb->table[0]) << (vtlb->addrwidth - vtlb->pageshift));
+ memset(vtlb->table, 0, sizeof(vtlb->table[0]) << (vtlb->addrwidth - vtlb->pageshift));
+
+ /* allocate the fixed page count array */
+ if (fixed_entries > 0)
+ {
+ vtlb->fixedpages = malloc_or_die(sizeof(vtlb->fixedpages[0]) * fixed_entries);
+ memset(vtlb->fixedpages, 0, sizeof(vtlb->fixedpages[0]) * 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)
+ free(vtlb->fixedpages);
+
+ /* free the table and array if they exist */
+ if (vtlb->live != NULL)
+ free(vtlb->live);
+ if (vtlb->table != NULL)
+ free(vtlb->table);
+
+ /* and then the VTLB object itself */
+ free(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->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];
+ for (pagenum = 0; pagenum < pagecount; pagenum++)
+ vtlb->table[vtlb->live[liveindex] - 1 + 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;
+ 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;
+}
diff --git a/src/emu/cpu/vtlb.h b/src/emu/cpu/vtlb.h
new file mode 100644
index 00000000000..c6b2045e7cd
--- /dev/null
+++ b/src/emu/cpu/vtlb.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ vtlb.h
+
+ 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.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __VTLB_H__
+#define __VTLB_H__
+
+#include "cpuintrf.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 */
+typedef struct _vtlb_state vtlb_state;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- initialization/teardown ----- */
+
+/* allocate a new VTLB for the given CPU */
+vtlb_state *vtlb_alloc(int cpunum, int 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);
+
+
+/* ----- 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