Commit ea2b542a4c8fbf50a00c7b431b9fd2c0b832991f
1 parent
939ef593
SH4 MMU improvements
(Shin-ichiro KAWASAKI) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4396 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
7 changed files
with
158 additions
and
6 deletions
hw/sh7750.c
| @@ -360,6 +360,9 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, | @@ -360,6 +360,9 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, | ||
| 360 | case SH7750_PTEL_A7: | 360 | case SH7750_PTEL_A7: |
| 361 | s->cpu->ptel = mem_value; | 361 | s->cpu->ptel = mem_value; |
| 362 | return; | 362 | return; |
| 363 | + case SH7750_PTEA_A7: | ||
| 364 | + s->cpu->ptea = mem_value & 0x0000000f; | ||
| 365 | + return; | ||
| 363 | case SH7750_TTB_A7: | 366 | case SH7750_TTB_A7: |
| 364 | s->cpu->ttb = mem_value; | 367 | s->cpu->ttb = mem_value; |
| 365 | return; | 368 | return; |
target-sh4/cpu.h
| @@ -163,5 +163,78 @@ enum { | @@ -163,5 +163,78 @@ enum { | ||
| 163 | #define MMUCR 0x1F000010 | 163 | #define MMUCR 0x1F000010 |
| 164 | #define MMUCR_AT (1<<0) | 164 | #define MMUCR_AT (1<<0) |
| 165 | #define MMUCR_SV (1<<8) | 165 | #define MMUCR_SV (1<<8) |
| 166 | +#define MMUCR_URC_BITS (6) | ||
| 167 | +#define MMUCR_URC_OFFSET (10) | ||
| 168 | +#define MMUCR_URC_SIZE (1 << MMUCR_URC_BITS) | ||
| 169 | +#define MMUCR_URC_MASK (((MMUCR_URC_SIZE) - 1) << MMUCR_URC_OFFSET) | ||
| 170 | +static inline int cpu_mmucr_urc (uint32_t mmucr) | ||
| 171 | +{ | ||
| 172 | + return ((mmucr & MMUCR_URC_MASK) >> MMUCR_URC_OFFSET); | ||
| 173 | +} | ||
| 174 | + | ||
| 175 | +/* PTEH : Page Translation Entry High register */ | ||
| 176 | +#define PTEH_ASID_BITS (8) | ||
| 177 | +#define PTEH_ASID_SIZE (1 << PTEH_ASID_BITS) | ||
| 178 | +#define PTEH_ASID_MASK (PTEH_ASID_SIZE - 1) | ||
| 179 | +#define cpu_pteh_asid(pteh) ((pteh) & PTEH_ASID_MASK) | ||
| 180 | +#define PTEH_VPN_BITS (22) | ||
| 181 | +#define PTEH_VPN_OFFSET (10) | ||
| 182 | +#define PTEH_VPN_SIZE (1 << PTEH_VPN_BITS) | ||
| 183 | +#define PTEH_VPN_MASK (((PTEH_VPN_SIZE) - 1) << PTEH_VPN_OFFSET) | ||
| 184 | +static inline int cpu_pteh_vpn (uint32_t pteh) | ||
| 185 | +{ | ||
| 186 | + return ((pteh & PTEH_VPN_MASK) >> PTEH_VPN_OFFSET); | ||
| 187 | +} | ||
| 188 | + | ||
| 189 | +/* PTEL : Page Translation Entry Low register */ | ||
| 190 | +#define PTEL_V (1 << 8) | ||
| 191 | +#define cpu_ptel_v(ptel) (((ptel) & PTEL_V) >> 8) | ||
| 192 | +#define PTEL_C (1 << 3) | ||
| 193 | +#define cpu_ptel_c(ptel) (((ptel) & PTEL_C) >> 3) | ||
| 194 | +#define PTEL_D (1 << 2) | ||
| 195 | +#define cpu_ptel_d(ptel) (((ptel) & PTEL_D) >> 2) | ||
| 196 | +#define PTEL_SH (1 << 1) | ||
| 197 | +#define cpu_ptel_sh(ptel)(((ptel) & PTEL_SH) >> 1) | ||
| 198 | +#define PTEL_WT (1 << 0) | ||
| 199 | +#define cpu_ptel_wt(ptel) ((ptel) & PTEL_WT) | ||
| 200 | + | ||
| 201 | +#define PTEL_SZ_HIGH_OFFSET (7) | ||
| 202 | +#define PTEL_SZ_HIGH (1 << PTEL_SZ_HIGH_OFFSET) | ||
| 203 | +#define PTEL_SZ_LOW_OFFSET (4) | ||
| 204 | +#define PTEL_SZ_LOW (1 << PTEL_SZ_LOW_OFFSET) | ||
| 205 | +static inline int cpu_ptel_sz (uint32_t ptel) | ||
| 206 | +{ | ||
| 207 | + int sz; | ||
| 208 | + sz = (ptel & PTEL_SZ_HIGH) >> PTEL_SZ_HIGH_OFFSET; | ||
| 209 | + sz <<= 1; | ||
| 210 | + sz |= (ptel & PTEL_SZ_LOW) >> PTEL_SZ_LOW_OFFSET; | ||
| 211 | + return sz; | ||
| 212 | +} | ||
| 213 | + | ||
| 214 | +#define PTEL_PPN_BITS (19) | ||
| 215 | +#define PTEL_PPN_OFFSET (10) | ||
| 216 | +#define PTEL_PPN_SIZE (1 << PTEL_PPN_BITS) | ||
| 217 | +#define PTEL_PPN_MASK (((PTEL_PPN_SIZE) - 1) << PTEL_PPN_OFFSET) | ||
| 218 | +static inline int cpu_ptel_ppn (uint32_t ptel) | ||
| 219 | +{ | ||
| 220 | + return ((ptel & PTEL_PPN_MASK) >> PTEL_PPN_OFFSET); | ||
| 221 | +} | ||
| 222 | + | ||
| 223 | +#define PTEL_PR_BITS (2) | ||
| 224 | +#define PTEL_PR_OFFSET (5) | ||
| 225 | +#define PTEL_PR_SIZE (1 << PTEL_PR_BITS) | ||
| 226 | +#define PTEL_PR_MASK (((PTEL_PR_SIZE) - 1) << PTEL_PR_OFFSET) | ||
| 227 | +static inline int cpu_ptel_pr (uint32_t ptel) | ||
| 228 | +{ | ||
| 229 | + return ((ptel & PTEL_PR_MASK) >> PTEL_PR_OFFSET); | ||
| 230 | +} | ||
| 231 | + | ||
| 232 | +/* PTEA : Page Translation Entry Assistance register */ | ||
| 233 | +#define PTEA_SA_BITS (3) | ||
| 234 | +#define PTEA_SA_SIZE (1 << PTEA_SA_BITS) | ||
| 235 | +#define PTEA_SA_MASK (PTEA_SA_SIZE - 1) | ||
| 236 | +#define cpu_ptea_sa(ptea) ((ptea) & PTEA_SA_MASK) | ||
| 237 | +#define PTEA_TC (1 << 3) | ||
| 238 | +#define cpu_ptea_tc(ptea) (((ptea) & PTEA_TC) >> 3) | ||
| 166 | 239 | ||
| 167 | #endif /* _CPU_SH4_H */ | 240 | #endif /* _CPU_SH4_H */ |
target-sh4/exec.h
| @@ -64,6 +64,7 @@ static inline void env_to_regs(void) | @@ -64,6 +64,7 @@ static inline void env_to_regs(void) | ||
| 64 | 64 | ||
| 65 | int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, | 65 | int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, |
| 66 | int mmu_idx, int is_softmmu); | 66 | int mmu_idx, int is_softmmu); |
| 67 | +void cpu_load_tlb(CPUState * env); | ||
| 67 | 68 | ||
| 68 | int find_itlb_entry(CPUState * env, target_ulong address, | 69 | int find_itlb_entry(CPUState * env, target_ulong address, |
| 69 | int use_asid, int update); | 70 | int use_asid, int update); |
| @@ -81,6 +82,7 @@ void helper_subc_T0_T1(void); | @@ -81,6 +82,7 @@ void helper_subc_T0_T1(void); | ||
| 81 | void helper_subv_T0_T1(void); | 82 | void helper_subv_T0_T1(void); |
| 82 | void helper_rotcl(uint32_t * addr); | 83 | void helper_rotcl(uint32_t * addr); |
| 83 | void helper_rotcr(uint32_t * addr); | 84 | void helper_rotcr(uint32_t * addr); |
| 85 | +void helper_ldtlb(void); | ||
| 84 | 86 | ||
| 85 | void do_interrupt(CPUState * env); | 87 | void do_interrupt(CPUState * env); |
| 86 | 88 |
target-sh4/helper.c
| @@ -193,7 +193,7 @@ static void update_itlb_use(CPUState * env, int itlbnb) | @@ -193,7 +193,7 @@ static void update_itlb_use(CPUState * env, int itlbnb) | ||
| 193 | 193 | ||
| 194 | switch (itlbnb) { | 194 | switch (itlbnb) { |
| 195 | case 0: | 195 | case 0: |
| 196 | - and_mask = 0x7f; | 196 | + and_mask = 0x1f; |
| 197 | break; | 197 | break; |
| 198 | case 1: | 198 | case 1: |
| 199 | and_mask = 0xe7; | 199 | and_mask = 0xe7; |
| @@ -208,7 +208,7 @@ static void update_itlb_use(CPUState * env, int itlbnb) | @@ -208,7 +208,7 @@ static void update_itlb_use(CPUState * env, int itlbnb) | ||
| 208 | break; | 208 | break; |
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | - env->mmucr &= (and_mask << 24); | 211 | + env->mmucr &= (and_mask << 24) | 0x00ffffff; |
| 212 | env->mmucr |= (or_mask << 24); | 212 | env->mmucr |= (or_mask << 24); |
| 213 | } | 213 | } |
| 214 | 214 | ||
| @@ -216,7 +216,7 @@ static int itlb_replacement(CPUState * env) | @@ -216,7 +216,7 @@ static int itlb_replacement(CPUState * env) | ||
| 216 | { | 216 | { |
| 217 | if ((env->mmucr & 0xe0000000) == 0xe0000000) | 217 | if ((env->mmucr & 0xe0000000) == 0xe0000000) |
| 218 | return 0; | 218 | return 0; |
| 219 | - if ((env->mmucr & 0x98000000) == 0x08000000) | 219 | + if ((env->mmucr & 0x98000000) == 0x18000000) |
| 220 | return 1; | 220 | return 1; |
| 221 | if ((env->mmucr & 0x54000000) == 0x04000000) | 221 | if ((env->mmucr & 0x54000000) == 0x04000000) |
| 222 | return 2; | 222 | return 2; |
| @@ -264,7 +264,7 @@ static int find_tlb_entry(CPUState * env, target_ulong address, | @@ -264,7 +264,7 @@ static int find_tlb_entry(CPUState * env, target_ulong address, | ||
| 264 | start = (entries[i].vpn << 10) & ~(entries[i].size - 1); | 264 | start = (entries[i].vpn << 10) & ~(entries[i].size - 1); |
| 265 | end = start + entries[i].size - 1; | 265 | end = start + entries[i].size - 1; |
| 266 | if (address >= start && address <= end) { /* Match */ | 266 | if (address >= start && address <= end) { /* Match */ |
| 267 | - if (match != -1) | 267 | + if (match != MMU_DTLB_MISS) |
| 268 | return MMU_DTLB_MULTIPLE; /* Multiple match */ | 268 | return MMU_DTLB_MULTIPLE; /* Multiple match */ |
| 269 | match = i; | 269 | match = i; |
| 270 | } | 270 | } |
| @@ -290,8 +290,10 @@ int find_itlb_entry(CPUState * env, target_ulong address, | @@ -290,8 +290,10 @@ int find_itlb_entry(CPUState * env, target_ulong address, | ||
| 290 | n = itlb_replacement(env); | 290 | n = itlb_replacement(env); |
| 291 | env->itlb[n] = env->utlb[e]; | 291 | env->itlb[n] = env->utlb[e]; |
| 292 | e = n; | 292 | e = n; |
| 293 | - } | ||
| 294 | - } | 293 | + } else if (e == MMU_DTLB_MISS) |
| 294 | + e = MMU_ITLB_MISS; | ||
| 295 | + } else if (e == MMU_DTLB_MISS) | ||
| 296 | + e = MMU_ITLB_MISS; | ||
| 295 | if (e >= 0) | 297 | if (e >= 0) |
| 296 | update_itlb_use(env, e); | 298 | update_itlb_use(env, e); |
| 297 | return e; | 299 | return e; |
| @@ -418,6 +420,21 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, | @@ -418,6 +420,21 @@ int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw, | ||
| 418 | target_ulong physical, page_offset, page_size; | 420 | target_ulong physical, page_offset, page_size; |
| 419 | int prot, ret, access_type; | 421 | int prot, ret, access_type; |
| 420 | 422 | ||
| 423 | + switch (rw) { | ||
| 424 | + case 0: | ||
| 425 | + rw = PAGE_READ; | ||
| 426 | + break; | ||
| 427 | + case 1: | ||
| 428 | + rw = PAGE_WRITE; | ||
| 429 | + break; | ||
| 430 | + case 2: /* READ_ACCESS_TYPE == 2 defined in softmmu_template.h */ | ||
| 431 | + rw = PAGE_READ; | ||
| 432 | + break; | ||
| 433 | + default: | ||
| 434 | + /* fatal error */ | ||
| 435 | + assert(0); | ||
| 436 | + } | ||
| 437 | + | ||
| 421 | /* XXXXX */ | 438 | /* XXXXX */ |
| 422 | #if 0 | 439 | #if 0 |
| 423 | fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n", | 440 | fprintf(stderr, "%s pc %08x ad %08x rw %d mmu_idx %d smmu %d\n", |
| @@ -479,4 +496,41 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) | @@ -479,4 +496,41 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) | ||
| 479 | return physical; | 496 | return physical; |
| 480 | } | 497 | } |
| 481 | 498 | ||
| 499 | +void cpu_load_tlb(CPUState * env) | ||
| 500 | +{ | ||
| 501 | + int n = cpu_mmucr_urc(env->mmucr); | ||
| 502 | + tlb_t * entry = &env->utlb[n]; | ||
| 503 | + | ||
| 504 | + /* Take values into cpu status from registers. */ | ||
| 505 | + entry->asid = (uint8_t)cpu_pteh_asid(env->pteh); | ||
| 506 | + entry->vpn = cpu_pteh_vpn(env->pteh); | ||
| 507 | + entry->v = (uint8_t)cpu_ptel_v(env->ptel); | ||
| 508 | + entry->ppn = cpu_ptel_ppn(env->ptel); | ||
| 509 | + entry->sz = (uint8_t)cpu_ptel_sz(env->ptel); | ||
| 510 | + switch (entry->sz) { | ||
| 511 | + case 0: /* 00 */ | ||
| 512 | + entry->size = 1024; /* 1K */ | ||
| 513 | + break; | ||
| 514 | + case 1: /* 01 */ | ||
| 515 | + entry->size = 1024 * 4; /* 4K */ | ||
| 516 | + break; | ||
| 517 | + case 2: /* 10 */ | ||
| 518 | + entry->size = 1024 * 64; /* 64K */ | ||
| 519 | + break; | ||
| 520 | + case 3: /* 11 */ | ||
| 521 | + entry->size = 1024 * 1024; /* 1M */ | ||
| 522 | + break; | ||
| 523 | + default: | ||
| 524 | + assert(0); | ||
| 525 | + break; | ||
| 526 | + } | ||
| 527 | + entry->sh = (uint8_t)cpu_ptel_sh(env->ptel); | ||
| 528 | + entry->c = (uint8_t)cpu_ptel_c(env->ptel); | ||
| 529 | + entry->pr = (uint8_t)cpu_ptel_pr(env->ptel); | ||
| 530 | + entry->d = (uint8_t)cpu_ptel_d(env->ptel); | ||
| 531 | + entry->wt = (uint8_t)cpu_ptel_wt(env->ptel); | ||
| 532 | + entry->sa = (uint8_t)cpu_ptea_sa(env->ptea); | ||
| 533 | + entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); | ||
| 534 | +} | ||
| 535 | + | ||
| 482 | #endif | 536 | #endif |
target-sh4/op.c
| @@ -185,6 +185,12 @@ void OPPROTO op_clrt(void) | @@ -185,6 +185,12 @@ void OPPROTO op_clrt(void) | ||
| 185 | RETURN(); | 185 | RETURN(); |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | +void OPPROTO op_ldtlb(void) | ||
| 189 | +{ | ||
| 190 | + helper_ldtlb(); | ||
| 191 | + RETURN(); | ||
| 192 | +} | ||
| 193 | + | ||
| 188 | void OPPROTO op_sets(void) | 194 | void OPPROTO op_sets(void) |
| 189 | { | 195 | { |
| 190 | env->sr |= SR_S; | 196 | env->sr |= SR_S; |
target-sh4/op_helper.c
| @@ -76,6 +76,16 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) | @@ -76,6 +76,16 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) | ||
| 76 | 76 | ||
| 77 | #endif | 77 | #endif |
| 78 | 78 | ||
| 79 | +void helper_ldtlb(void) | ||
| 80 | +{ | ||
| 81 | +#ifdef CONFIG_USER_ONLY | ||
| 82 | + /* XXXXX */ | ||
| 83 | + assert(0); | ||
| 84 | +#else | ||
| 85 | + cpu_load_tlb(env); | ||
| 86 | +#endif | ||
| 87 | +} | ||
| 88 | + | ||
| 79 | void helper_addc_T0_T1(void) | 89 | void helper_addc_T0_T1(void) |
| 80 | { | 90 | { |
| 81 | uint32_t tmp0, tmp1; | 91 | uint32_t tmp0, tmp1; |
target-sh4/translate.c
| @@ -256,7 +256,11 @@ void _decode_opc(DisasContext * ctx) | @@ -256,7 +256,11 @@ void _decode_opc(DisasContext * ctx) | ||
| 256 | gen_op_clrt(); | 256 | gen_op_clrt(); |
| 257 | return; | 257 | return; |
| 258 | case 0x0038: /* ldtlb */ | 258 | case 0x0038: /* ldtlb */ |
| 259 | +#if defined(CONFIG_USER_ONLY) | ||
| 259 | assert(0); /* XXXXX */ | 260 | assert(0); /* XXXXX */ |
| 261 | +#else | ||
| 262 | + gen_op_ldtlb(); | ||
| 263 | +#endif | ||
| 260 | return; | 264 | return; |
| 261 | case 0x002b: /* rte */ | 265 | case 0x002b: /* rte */ |
| 262 | CHECK_NOT_DELAY_SLOT gen_op_rte(); | 266 | CHECK_NOT_DELAY_SLOT gen_op_rte(); |