aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r--target-sparc/op_helper.c214
1 files changed, 145 insertions, 69 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 739ed9abd2..5acaa0d268 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -46,8 +46,8 @@ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
int page_size)
{
uint64_t tsb_base = tsb_register & ~0x1fffULL;
- int tsb_split = (env->dmmuregs[5] & 0x1000ULL) ? 1 : 0;
- int tsb_size = env->dmmuregs[5] & 0xf;
+ int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
+ int tsb_size = tsb_register & 0xf;
// discard lower 13 bits which hold tag access context
uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
@@ -87,6 +87,55 @@ static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
}
+static void replace_tlb_entry(SparcTLBEntry *tlb, CPUState *env1,
+ uint64_t tlb_tag, uint64_t tlb_tte)
+{
+ target_ulong mask, size, va, offset;
+
+ // flush page range if translation is valid
+ if (tlb->tte & 0x8000000000000000ULL) {
+
+ mask = 0xffffffffffffe000ULL;
+ mask <<= 3 * ((tlb->tte >> 61) & 3);
+ size = ~mask + 1;
+
+ va = tlb->tag & mask;
+
+ for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
+ tlb_flush_page(env1, va + offset);
+ }
+ }
+
+ tlb->tag = tlb_tag;
+ tlb->tte = tlb_tte;
+}
+
+static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
+ CPUState *env1)
+{
+ unsigned int i;
+ target_ulong mask;
+
+ for (i = 0; i < 64; i++) {
+ if (tlb[i].tte & 0x8000000000000000ULL) {
+
+ mask = 0xffffffffffffe000ULL;
+ mask <<= 3 * ((tlb[i].tte >> 61) & 3);
+
+ if ((demap_addr & mask) == (tlb[i].tag & mask)) {
+ replace_tlb_entry(&tlb[i], env1, 0, 0);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("mmu demap invalidated entry [%02u]\n",
+ i);
+ dump_mmu(env);
+#endif
+ }
+ //return;
+ }
+ }
+
+}
+
#endif
static inline void address_mask(CPUState *env1, target_ulong *addr)
@@ -2143,7 +2192,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
if (reg == 0) {
// I-TSB Tag Target register
- ret = ultrasparc_tag_target(env->immuregs[6]);
+ ret = ultrasparc_tag_target(env->immu.tag_access);
} else {
ret = env->immuregs[reg];
}
@@ -2154,7 +2203,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
// env->immuregs[5] holds I-MMU TSB register value
// env->immuregs[6] holds I-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6],
+ ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
8*1024);
break;
}
@@ -2162,7 +2211,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
// env->immuregs[5] holds I-MMU TSB register value
// env->immuregs[6] holds I-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->immuregs[5], env->immuregs[6],
+ ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
64*1024);
break;
}
@@ -2170,14 +2219,14 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
int reg = (addr >> 3) & 0x3f;
- ret = env->itlb_tte[reg];
+ ret = env->itlb[reg].tte;
break;
}
case 0x56: // I-MMU tag read
{
int reg = (addr >> 3) & 0x3f;
- ret = env->itlb_tag[reg];
+ ret = env->itlb[reg].tag;
break;
}
case 0x58: // D-MMU regs
@@ -2186,7 +2235,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
if (reg == 0) {
// D-TSB Tag Target register
- ret = ultrasparc_tag_target(env->dmmuregs[6]);
+ ret = ultrasparc_tag_target(env->dmmu.tag_access);
} else {
ret = env->dmmuregs[reg];
}
@@ -2196,7 +2245,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
// env->dmmuregs[5] holds D-MMU TSB register value
// env->dmmuregs[6] holds D-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6],
+ ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
8*1024);
break;
}
@@ -2204,7 +2253,7 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
// env->dmmuregs[5] holds D-MMU TSB register value
// env->dmmuregs[6] holds D-MMU Tag Access register value
- ret = ultrasparc_tsb_pointer(env->dmmuregs[5], env->dmmuregs[6],
+ ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
64*1024);
break;
}
@@ -2212,14 +2261,14 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
{
int reg = (addr >> 3) & 0x3f;
- ret = env->dtlb_tte[reg];
+ ret = env->dtlb[reg].tte;
break;
}
case 0x5e: // D-MMU tag read
{
int reg = (addr >> 3) & 0x3f;
- ret = env->dtlb_tag[reg];
+ ret = env->dtlb[reg].tag;
break;
}
case 0x46: // D-cache data
@@ -2462,25 +2511,34 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
oldreg = env->immuregs[reg];
switch(reg) {
case 0: // RO
- case 4:
return;
case 1: // Not in I-MMU
case 2:
- case 7:
- case 8:
return;
case 3: // SFSR
if ((val & 1) == 0)
val = 0; // Clear SFSR
+ env->immu.sfsr = val;
break;
+ case 4: // RO
+ return;
case 5: // TSB access
+ DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", env->immu.tsb, val);
+ env->immu.tsb = val;
+ break;
case 6: // Tag access
+ env->immu.tag_access = val;
+ break;
+ case 7:
+ case 8:
+ return;
default:
break;
}
- env->immuregs[reg] = val;
+
if (oldreg != env->immuregs[reg]) {
- DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08"
+ DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
}
#ifdef DEBUG_MMU
@@ -2494,20 +2552,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
// Try finding an invalid entry
for (i = 0; i < 64; i++) {
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = val;
+ if ((env->itlb[i].tte & 0x8000000000000000ULL) == 0) {
+ replace_tlb_entry(&env->itlb[i], env,
+ env->immu.tag_access, val);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("immu data map replaced invalid entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
}
// Try finding an unlocked entry
for (i = 0; i < 64; i++) {
- if ((env->itlb_tte[i] & 0x40) == 0) {
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = val;
+ if ((env->itlb[i].tte & 0x40) == 0) {
+ replace_tlb_entry(&env->itlb[i], env,
+ env->immu.tag_access, val);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("immu data map replaced unlocked entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
}
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("immu data map failed: no entries available\n");
+#endif
// error state?
return;
}
@@ -2517,27 +2588,18 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
unsigned int i = (addr >> 3) & 0x3f;
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = val;
+ replace_tlb_entry(&env->itlb[i], env,
+ env->immu.tag_access, val);
+
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("immu data access replaced entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
case 0x57: // I-MMU demap
- {
- unsigned int i;
-
- for (i = 0; i < 64; i++) {
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
- target_ulong mask = 0xffffffffffffe000ULL;
-
- mask <<= 3 * ((env->itlb_tte[i] >> 61) & 3);
- if ((val & mask) == (env->itlb_tag[i] & mask)) {
- env->itlb_tag[i] = 0;
- env->itlb_tte[i] = 0;
- }
- return;
- }
- }
- }
+ demap_tlb(env->itlb, val, env);
return;
case 0x58: // D-MMU regs
{
@@ -2552,22 +2614,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
case 3: // SFSR
if ((val & 1) == 0) {
val = 0; // Clear SFSR, Fault address
- env->dmmuregs[4] = 0;
+ env->dmmu.sfar = 0;
}
- env->dmmuregs[reg] = val;
+ env->dmmu.sfsr = val;
break;
case 1: // Primary context
+ env->dmmu.mmu_primary_context = val;
+ break;
case 2: // Secondary context
+ env->dmmu.mmu_secondary_context = val;
+ break;
case 5: // TSB access
+ DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
+ PRIx64 "\n", env->dmmu.tsb, val);
+ env->dmmu.tsb = val;
+ break;
case 6: // Tag access
+ env->dmmu.tag_access = val;
+ break;
case 7: // Virtual Watchpoint
case 8: // Physical Watchpoint
default:
+ env->dmmuregs[reg] = val;
break;
}
- env->dmmuregs[reg] = val;
+
if (oldreg != env->dmmuregs[reg]) {
- DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08"
+ DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
}
#ifdef DEBUG_MMU
@@ -2581,20 +2654,33 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
// Try finding an invalid entry
for (i = 0; i < 64; i++) {
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = val;
+ if ((env->dtlb[i].tte & 0x8000000000000000ULL) == 0) {
+ replace_tlb_entry(&env->dtlb[i], env,
+ env->dmmu.tag_access, val);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("dmmu data map replaced invalid entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
}
// Try finding an unlocked entry
for (i = 0; i < 64; i++) {
- if ((env->dtlb_tte[i] & 0x40) == 0) {
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = val;
+ if ((env->dtlb[i].tte & 0x40) == 0) {
+ replace_tlb_entry(&env->dtlb[i], env,
+ env->dmmu.tag_access, val);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("dmmu data map replaced unlocked entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
}
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("dmmu data map failed: no entries available\n");
+#endif
// error state?
return;
}
@@ -2602,27 +2688,17 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
{
unsigned int i = (addr >> 3) & 0x3f;
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = val;
+ replace_tlb_entry(&env->dtlb[i], env,
+ env->dmmu.tag_access, val);
+#ifdef DEBUG_MMU
+ DPRINTF_MMU("dmmu data access replaced entry [%i]\n",
+ i);
+ dump_mmu(env);
+#endif
return;
}
case 0x5f: // D-MMU demap
- {
- unsigned int i;
-
- for (i = 0; i < 64; i++) {
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
- target_ulong mask = 0xffffffffffffe000ULL;
-
- mask <<= 3 * ((env->dtlb_tte[i] >> 61) & 3);
- if ((val & mask) == (env->dtlb_tag[i] & mask)) {
- env->dtlb_tag[i] = 0;
- env->dtlb_tte[i] = 0;
- }
- return;
- }
- }
- }
+ demap_tlb(env->dtlb, val, env);
return;
case 0x49: // Interrupt data receive
// XXX