sparc64 name mmu registers and general cleanup
- add names to mmu registers, this helps understanding the code which uses/modifies them. - fold i/d mmu tlb entries tag and tte arrays into arrays of tlb entries - extract demap_tlb routine (code duplication) - extract replace_tlb routine (code duplication) - flush qemu tlb translations when replacing sparc64 mmu tlb entries I have no test case which demands flushing qemu translations, and this patch should have no other visible changes to runtime. Signed-off-by: igor.v.kovalenko@gmail.com -- Kind regards, Igor V. Kovalenko
This commit is contained in:
parent
33b544ba5c
commit
6e8e7d4c09
@ -273,6 +273,11 @@ enum {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct SparcTLBEntry {
|
||||||
|
uint64_t tag;
|
||||||
|
uint64_t tte;
|
||||||
|
} SparcTLBEntry;
|
||||||
|
|
||||||
typedef struct CPUSPARCState {
|
typedef struct CPUSPARCState {
|
||||||
target_ulong gregs[8]; /* general registers */
|
target_ulong gregs[8]; /* general registers */
|
||||||
target_ulong *regwptr; /* pointer to current register window */
|
target_ulong *regwptr; /* pointer to current register window */
|
||||||
@ -319,12 +324,33 @@ typedef struct CPUSPARCState {
|
|||||||
uint64_t lsu;
|
uint64_t lsu;
|
||||||
#define DMMU_E 0x8
|
#define DMMU_E 0x8
|
||||||
#define IMMU_E 0x4
|
#define IMMU_E 0x4
|
||||||
uint64_t immuregs[16];
|
//typedef struct SparcMMU
|
||||||
uint64_t dmmuregs[16];
|
union {
|
||||||
uint64_t itlb_tag[64];
|
uint64_t immuregs[16];
|
||||||
uint64_t itlb_tte[64];
|
struct {
|
||||||
uint64_t dtlb_tag[64];
|
uint64_t tsb_tag_target;
|
||||||
uint64_t dtlb_tte[64];
|
uint64_t unused_mmu_primary_context; // use DMMU
|
||||||
|
uint64_t unused_mmu_secondary_context; // use DMMU
|
||||||
|
uint64_t sfsr;
|
||||||
|
uint64_t sfar;
|
||||||
|
uint64_t tsb;
|
||||||
|
uint64_t tag_access;
|
||||||
|
} immu;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
uint64_t dmmuregs[16];
|
||||||
|
struct {
|
||||||
|
uint64_t tsb_tag_target;
|
||||||
|
uint64_t mmu_primary_context;
|
||||||
|
uint64_t mmu_secondary_context;
|
||||||
|
uint64_t sfsr;
|
||||||
|
uint64_t sfar;
|
||||||
|
uint64_t tsb;
|
||||||
|
uint64_t tag_access;
|
||||||
|
} dmmu;
|
||||||
|
};
|
||||||
|
SparcTLBEntry itlb[64];
|
||||||
|
SparcTLBEntry dtlb[64];
|
||||||
uint32_t mmu_version;
|
uint32_t mmu_version;
|
||||||
#else
|
#else
|
||||||
uint32_t mmuregs[32];
|
uint32_t mmuregs[32];
|
||||||
|
@ -386,13 +386,13 @@ static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
|
|||||||
|
|
||||||
// Returns true if TTE tag is valid and matches virtual address value in context
|
// Returns true if TTE tag is valid and matches virtual address value in context
|
||||||
// requires virtual address mask value calculated from TTE entry size
|
// requires virtual address mask value calculated from TTE entry size
|
||||||
static inline int ultrasparc_tag_match(uint64_t tlb_tag, uint64_t tlb_tte,
|
static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
|
||||||
uint64_t address, uint64_t context,
|
uint64_t address, uint64_t context,
|
||||||
target_phys_addr_t *physical)
|
target_phys_addr_t *physical)
|
||||||
{
|
{
|
||||||
uint64_t mask;
|
uint64_t mask;
|
||||||
|
|
||||||
switch ((tlb_tte >> 61) & 3) {
|
switch ((tlb->tte >> 61) & 3) {
|
||||||
default:
|
default:
|
||||||
case 0x0: // 8k
|
case 0x0: // 8k
|
||||||
mask = 0xffffffffffffe000ULL;
|
mask = 0xffffffffffffe000ULL;
|
||||||
@ -409,12 +409,12 @@ static inline int ultrasparc_tag_match(uint64_t tlb_tag, uint64_t tlb_tte,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// valid, context match, virtual address match?
|
// valid, context match, virtual address match?
|
||||||
if ((tlb_tte & 0x8000000000000000ULL) &&
|
if ((tlb->tte & 0x8000000000000000ULL) &&
|
||||||
compare_masked(context, tlb_tag, 0x1fff) &&
|
compare_masked(context, tlb->tag, 0x1fff) &&
|
||||||
compare_masked(address, tlb_tag, mask))
|
compare_masked(address, tlb->tag, mask))
|
||||||
{
|
{
|
||||||
// decode physical address
|
// decode physical address
|
||||||
*physical = ((tlb_tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
|
*physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,21 +434,31 @@ static int get_physical_address_data(CPUState *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = env->dmmuregs[1] & 0x1fff;
|
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
// ctx match, vaddr match, valid?
|
// ctx match, vaddr match, valid?
|
||||||
if (ultrasparc_tag_match(env->dtlb_tag[i], env->dtlb_tte[i],
|
if (ultrasparc_tag_match(&env->dtlb[i],
|
||||||
address, context, physical)
|
address, context, physical)
|
||||||
) {
|
) {
|
||||||
// access ok?
|
// access ok?
|
||||||
if (((env->dtlb_tte[i] & 0x4) && is_user) ||
|
if (((env->dtlb[i].tte & 0x4) && is_user) ||
|
||||||
(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
|
(!(env->dtlb[i].tte & 0x2) && (rw == 1))) {
|
||||||
if (env->dmmuregs[3]) /* Fault status register */
|
uint8_t fault_type = 0;
|
||||||
env->dmmuregs[3] = 2; /* overflow (not read before
|
|
||||||
|
if ((env->dtlb[i].tte & 0x4) && is_user) {
|
||||||
|
fault_type |= 1; /* privilege violation */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->dmmu.sfsr & 1) /* Fault status register */
|
||||||
|
env->dmmu.sfsr = 2; /* overflow (not read before
|
||||||
another fault) */
|
another fault) */
|
||||||
env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
|
|
||||||
env->dmmuregs[4] = address; /* Fault address register */
|
env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
|
||||||
|
|
||||||
|
env->dmmu.sfsr |= (fault_type << 7);
|
||||||
|
|
||||||
|
env->dmmu.sfar = address; /* Fault address register */
|
||||||
env->exception_index = TT_DFAULT;
|
env->exception_index = TT_DFAULT;
|
||||||
#ifdef DEBUG_MMU
|
#ifdef DEBUG_MMU
|
||||||
printf("DFAULT at 0x%" PRIx64 "\n", address);
|
printf("DFAULT at 0x%" PRIx64 "\n", address);
|
||||||
@ -456,7 +466,7 @@ static int get_physical_address_data(CPUState *env,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
*prot = PAGE_READ;
|
*prot = PAGE_READ;
|
||||||
if (env->dtlb_tte[i] & 0x2)
|
if (env->dtlb[i].tte & 0x2)
|
||||||
*prot |= PAGE_WRITE;
|
*prot |= PAGE_WRITE;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -464,7 +474,7 @@ static int get_physical_address_data(CPUState *env,
|
|||||||
#ifdef DEBUG_MMU
|
#ifdef DEBUG_MMU
|
||||||
printf("DMISS at 0x%" PRIx64 "\n", address);
|
printf("DMISS at 0x%" PRIx64 "\n", address);
|
||||||
#endif
|
#endif
|
||||||
env->dmmuregs[6] = (address & ~0x1fffULL) | context;
|
env->dmmu.tag_access = (address & ~0x1fffULL) | context;
|
||||||
env->exception_index = TT_DMISS;
|
env->exception_index = TT_DMISS;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -483,19 +493,19 @@ static int get_physical_address_code(CPUState *env,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
context = env->dmmuregs[1] & 0x1fff;
|
context = env->dmmu.mmu_primary_context & 0x1fff;
|
||||||
|
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
// ctx match, vaddr match, valid?
|
// ctx match, vaddr match, valid?
|
||||||
if (ultrasparc_tag_match(env->itlb_tag[i], env->itlb_tte[i],
|
if (ultrasparc_tag_match(&env->itlb[i],
|
||||||
address, context, physical)
|
address, context, physical)
|
||||||
) {
|
) {
|
||||||
// access ok?
|
// access ok?
|
||||||
if ((env->itlb_tte[i] & 0x4) && is_user) {
|
if ((env->itlb[i].tte & 0x4) && is_user) {
|
||||||
if (env->immuregs[3]) /* Fault status register */
|
if (env->immu.sfsr) /* Fault status register */
|
||||||
env->immuregs[3] = 2; /* overflow (not read before
|
env->immu.sfsr = 2; /* overflow (not read before
|
||||||
another fault) */
|
another fault) */
|
||||||
env->immuregs[3] |= (is_user << 3) | 1;
|
env->immu.sfsr |= (is_user << 3) | 1;
|
||||||
env->exception_index = TT_TFAULT;
|
env->exception_index = TT_TFAULT;
|
||||||
#ifdef DEBUG_MMU
|
#ifdef DEBUG_MMU
|
||||||
printf("TFAULT at 0x%" PRIx64 "\n", address);
|
printf("TFAULT at 0x%" PRIx64 "\n", address);
|
||||||
@ -510,7 +520,7 @@ static int get_physical_address_code(CPUState *env,
|
|||||||
printf("TMISS at 0x%" PRIx64 "\n", address);
|
printf("TMISS at 0x%" PRIx64 "\n", address);
|
||||||
#endif
|
#endif
|
||||||
/* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
|
/* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
|
||||||
env->immuregs[6] = (address & ~0x1fffULL) | context;
|
env->immu.tag_access = (address & ~0x1fffULL) | context;
|
||||||
env->exception_index = TT_TMISS;
|
env->exception_index = TT_TMISS;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -561,7 +571,7 @@ void dump_mmu(CPUState *env)
|
|||||||
const char *mask;
|
const char *mask;
|
||||||
|
|
||||||
printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
|
printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
|
||||||
env->dmmuregs[1], env->dmmuregs[2]);
|
env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
|
||||||
if ((env->lsu & DMMU_E) == 0) {
|
if ((env->lsu & DMMU_E) == 0) {
|
||||||
printf("DMMU disabled\n");
|
printf("DMMU disabled\n");
|
||||||
} else {
|
} else {
|
||||||
@ -583,8 +593,9 @@ void dump_mmu(CPUState *env)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
||||||
printf("VA: %" PRIx64 ", PA: %" PRIx64
|
printf("[%02u] VA: " PRIx64 ", PA: " PRIx64
|
||||||
", %s, %s, %s, %s, ctx %" PRId64 "\n",
|
", %s, %s, %s, %s, ctx %" PRId64 "\n",
|
||||||
|
i,
|
||||||
env->dtlb_tag[i] & (uint64_t)~0x1fffULL,
|
env->dtlb_tag[i] & (uint64_t)~0x1fffULL,
|
||||||
env->dtlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
|
env->dtlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
|
||||||
mask,
|
mask,
|
||||||
@ -616,14 +627,15 @@ void dump_mmu(CPUState *env)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
|
||||||
printf("VA: %" PRIx64 ", PA: %" PRIx64
|
printf("[%02u] VA: " PRIx64 ", PA: " PRIx64
|
||||||
", %s, %s, %s, ctx %" PRId64 "\n",
|
", %s, %s, %s, ctx %" PRId64 "\n",
|
||||||
env->itlb_tag[i] & (uint64_t)~0x1fffULL,
|
i,
|
||||||
|
env->itlb[i].tag & (uint64_t)~0x1fffULL,
|
||||||
env->itlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
|
env->itlb_tte[i] & (uint64_t)0x1ffffffe000ULL,
|
||||||
mask,
|
mask,
|
||||||
env->itlb_tte[i] & 0x4? "priv": "user",
|
env->itlb_tte[i] & 0x4? "priv": "user",
|
||||||
env->itlb_tte[i] & 0x40? "locked": "unlocked",
|
env->itlb_tte[i] & 0x40? "locked": "unlocked",
|
||||||
env->itlb_tag[i] & (uint64_t)0x1fffULL);
|
env->itlb[i].tag & (uint64_t)0x1fffULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,10 @@ void cpu_save(QEMUFile *f, void *opaque)
|
|||||||
qemu_put_be64s(f, &env->dmmuregs[i]);
|
qemu_put_be64s(f, &env->dmmuregs[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
qemu_put_be64s(f, &env->itlb_tag[i]);
|
qemu_put_be64s(f, &env->itlb[i].tag);
|
||||||
qemu_put_be64s(f, &env->itlb_tte[i]);
|
qemu_put_be64s(f, &env->itlb[i].tte);
|
||||||
qemu_put_be64s(f, &env->dtlb_tag[i]);
|
qemu_put_be64s(f, &env->dtlb[i].tag);
|
||||||
qemu_put_be64s(f, &env->dtlb_tte[i]);
|
qemu_put_be64s(f, &env->dtlb[i].tte);
|
||||||
}
|
}
|
||||||
qemu_put_be32s(f, &env->mmu_version);
|
qemu_put_be32s(f, &env->mmu_version);
|
||||||
for (i = 0; i < MAXTL_MAX; i++) {
|
for (i = 0; i < MAXTL_MAX; i++) {
|
||||||
@ -148,10 +148,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
|
|||||||
qemu_get_be64s(f, &env->dmmuregs[i]);
|
qemu_get_be64s(f, &env->dmmuregs[i]);
|
||||||
}
|
}
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
qemu_get_be64s(f, &env->itlb_tag[i]);
|
qemu_get_be64s(f, &env->itlb[i].tag);
|
||||||
qemu_get_be64s(f, &env->itlb_tte[i]);
|
qemu_get_be64s(f, &env->itlb[i].tte);
|
||||||
qemu_get_be64s(f, &env->dtlb_tag[i]);
|
qemu_get_be64s(f, &env->dtlb[i].tag);
|
||||||
qemu_get_be64s(f, &env->dtlb_tte[i]);
|
qemu_get_be64s(f, &env->dtlb[i].tte);
|
||||||
}
|
}
|
||||||
qemu_get_be32s(f, &env->mmu_version);
|
qemu_get_be32s(f, &env->mmu_version);
|
||||||
for (i = 0; i < MAXTL_MAX; i++) {
|
for (i = 0; i < MAXTL_MAX; i++) {
|
||||||
|
@ -46,8 +46,8 @@ static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
|
|||||||
int page_size)
|
int page_size)
|
||||||
{
|
{
|
||||||
uint64_t tsb_base = tsb_register & ~0x1fffULL;
|
uint64_t tsb_base = tsb_register & ~0x1fffULL;
|
||||||
int tsb_split = (env->dmmuregs[5] & 0x1000ULL) ? 1 : 0;
|
int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
|
||||||
int tsb_size = env->dmmuregs[5] & 0xf;
|
int tsb_size = tsb_register & 0xf;
|
||||||
|
|
||||||
// discard lower 13 bits which hold tag access context
|
// discard lower 13 bits which hold tag access context
|
||||||
uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
|
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);
|
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
|
#endif
|
||||||
|
|
||||||
static inline void address_mask(CPUState *env1, target_ulong *addr)
|
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) {
|
if (reg == 0) {
|
||||||
// I-TSB Tag Target register
|
// I-TSB Tag Target register
|
||||||
ret = ultrasparc_tag_target(env->immuregs[6]);
|
ret = ultrasparc_tag_target(env->immu.tag_access);
|
||||||
} else {
|
} else {
|
||||||
ret = env->immuregs[reg];
|
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[5] holds I-MMU TSB register value
|
||||||
// env->immuregs[6] holds I-MMU Tag Access 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);
|
8*1024);
|
||||||
break;
|
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[5] holds I-MMU TSB register value
|
||||||
// env->immuregs[6] holds I-MMU Tag Access 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);
|
64*1024);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2170,14 +2219,14 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
|||||||
{
|
{
|
||||||
int reg = (addr >> 3) & 0x3f;
|
int reg = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
ret = env->itlb_tte[reg];
|
ret = env->itlb[reg].tte;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x56: // I-MMU tag read
|
case 0x56: // I-MMU tag read
|
||||||
{
|
{
|
||||||
int reg = (addr >> 3) & 0x3f;
|
int reg = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
ret = env->itlb_tag[reg];
|
ret = env->itlb[reg].tag;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x58: // D-MMU regs
|
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) {
|
if (reg == 0) {
|
||||||
// D-TSB Tag Target register
|
// D-TSB Tag Target register
|
||||||
ret = ultrasparc_tag_target(env->dmmuregs[6]);
|
ret = ultrasparc_tag_target(env->dmmu.tag_access);
|
||||||
} else {
|
} else {
|
||||||
ret = env->dmmuregs[reg];
|
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[5] holds D-MMU TSB register value
|
||||||
// env->dmmuregs[6] holds D-MMU Tag Access 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);
|
8*1024);
|
||||||
break;
|
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[5] holds D-MMU TSB register value
|
||||||
// env->dmmuregs[6] holds D-MMU Tag Access 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);
|
64*1024);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2212,14 +2261,14 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
|
|||||||
{
|
{
|
||||||
int reg = (addr >> 3) & 0x3f;
|
int reg = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
ret = env->dtlb_tte[reg];
|
ret = env->dtlb[reg].tte;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x5e: // D-MMU tag read
|
case 0x5e: // D-MMU tag read
|
||||||
{
|
{
|
||||||
int reg = (addr >> 3) & 0x3f;
|
int reg = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
ret = env->dtlb_tag[reg];
|
ret = env->dtlb[reg].tag;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x46: // D-cache data
|
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];
|
oldreg = env->immuregs[reg];
|
||||||
switch(reg) {
|
switch(reg) {
|
||||||
case 0: // RO
|
case 0: // RO
|
||||||
case 4:
|
|
||||||
return;
|
return;
|
||||||
case 1: // Not in I-MMU
|
case 1: // Not in I-MMU
|
||||||
case 2:
|
case 2:
|
||||||
case 7:
|
|
||||||
case 8:
|
|
||||||
return;
|
return;
|
||||||
case 3: // SFSR
|
case 3: // SFSR
|
||||||
if ((val & 1) == 0)
|
if ((val & 1) == 0)
|
||||||
val = 0; // Clear SFSR
|
val = 0; // Clear SFSR
|
||||||
|
env->immu.sfsr = val;
|
||||||
break;
|
break;
|
||||||
|
case 4: // RO
|
||||||
|
return;
|
||||||
case 5: // TSB access
|
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
|
case 6: // Tag access
|
||||||
|
env->immu.tag_access = val;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
case 8:
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
env->immuregs[reg] = val;
|
|
||||||
if (oldreg != env->immuregs[reg]) {
|
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]);
|
PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_MMU
|
#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
|
// Try finding an invalid entry
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
|
if ((env->itlb[i].tte & 0x8000000000000000ULL) == 0) {
|
||||||
env->itlb_tag[i] = env->immuregs[6];
|
replace_tlb_entry(&env->itlb[i], env,
|
||||||
env->itlb_tte[i] = val;
|
env->immu.tag_access, val);
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("immu data map replaced invalid entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try finding an unlocked entry
|
// Try finding an unlocked entry
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
if ((env->itlb_tte[i] & 0x40) == 0) {
|
if ((env->itlb[i].tte & 0x40) == 0) {
|
||||||
env->itlb_tag[i] = env->immuregs[6];
|
replace_tlb_entry(&env->itlb[i], env,
|
||||||
env->itlb_tte[i] = val;
|
env->immu.tag_access, val);
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("immu data map replaced unlocked entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("immu data map failed: no entries available\n");
|
||||||
|
#endif
|
||||||
// error state?
|
// error state?
|
||||||
return;
|
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;
|
unsigned int i = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
env->itlb_tag[i] = env->immuregs[6];
|
replace_tlb_entry(&env->itlb[i], env,
|
||||||
env->itlb_tte[i] = val;
|
env->immu.tag_access, val);
|
||||||
|
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("immu data access replaced entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 0x57: // I-MMU demap
|
case 0x57: // I-MMU demap
|
||||||
{
|
demap_tlb(env->itlb, val, env);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
case 0x58: // D-MMU regs
|
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
|
case 3: // SFSR
|
||||||
if ((val & 1) == 0) {
|
if ((val & 1) == 0) {
|
||||||
val = 0; // Clear SFSR, Fault address
|
val = 0; // Clear SFSR, Fault address
|
||||||
env->dmmuregs[4] = 0;
|
env->dmmu.sfar = 0;
|
||||||
}
|
}
|
||||||
env->dmmuregs[reg] = val;
|
env->dmmu.sfsr = val;
|
||||||
break;
|
break;
|
||||||
case 1: // Primary context
|
case 1: // Primary context
|
||||||
|
env->dmmu.mmu_primary_context = val;
|
||||||
|
break;
|
||||||
case 2: // Secondary context
|
case 2: // Secondary context
|
||||||
|
env->dmmu.mmu_secondary_context = val;
|
||||||
|
break;
|
||||||
case 5: // TSB access
|
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
|
case 6: // Tag access
|
||||||
|
env->dmmu.tag_access = val;
|
||||||
|
break;
|
||||||
case 7: // Virtual Watchpoint
|
case 7: // Virtual Watchpoint
|
||||||
case 8: // Physical Watchpoint
|
case 8: // Physical Watchpoint
|
||||||
default:
|
default:
|
||||||
|
env->dmmuregs[reg] = val;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
env->dmmuregs[reg] = val;
|
|
||||||
if (oldreg != env->dmmuregs[reg]) {
|
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]);
|
PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_MMU
|
#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
|
// Try finding an invalid entry
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
|
if ((env->dtlb[i].tte & 0x8000000000000000ULL) == 0) {
|
||||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
replace_tlb_entry(&env->dtlb[i], env,
|
||||||
env->dtlb_tte[i] = val;
|
env->dmmu.tag_access, val);
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("dmmu data map replaced invalid entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Try finding an unlocked entry
|
// Try finding an unlocked entry
|
||||||
for (i = 0; i < 64; i++) {
|
for (i = 0; i < 64; i++) {
|
||||||
if ((env->dtlb_tte[i] & 0x40) == 0) {
|
if ((env->dtlb[i].tte & 0x40) == 0) {
|
||||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
replace_tlb_entry(&env->dtlb[i], env,
|
||||||
env->dtlb_tte[i] = val;
|
env->dmmu.tag_access, val);
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("dmmu data map replaced unlocked entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("dmmu data map failed: no entries available\n");
|
||||||
|
#endif
|
||||||
// error state?
|
// error state?
|
||||||
return;
|
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;
|
unsigned int i = (addr >> 3) & 0x3f;
|
||||||
|
|
||||||
env->dtlb_tag[i] = env->dmmuregs[6];
|
replace_tlb_entry(&env->dtlb[i], env,
|
||||||
env->dtlb_tte[i] = val;
|
env->dmmu.tag_access, val);
|
||||||
|
#ifdef DEBUG_MMU
|
||||||
|
DPRINTF_MMU("dmmu data access replaced entry [%i]\n",
|
||||||
|
i);
|
||||||
|
dump_mmu(env);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case 0x5f: // D-MMU demap
|
case 0x5f: // D-MMU demap
|
||||||
{
|
demap_tlb(env->dtlb, val, env);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
case 0x49: // Interrupt data receive
|
case 0x49: // Interrupt data receive
|
||||||
// XXX
|
// XXX
|
||||||
|
Loading…
Reference in New Issue
Block a user