Commit 29e179bc3f5e804ab58b975e65c91cb9cd287846

Authored by aurel32
1 parent 274a9e70

[sh4] memory mapped TLB entries

SH4 MMU's memory mapped TLB feature is implemented.
SH-Linux seems to write to memory mapped TLB to invalidate a TLB entry,
but does not to read it. So only memory write feature is implemented.
Work on memory read feature is left.

(Shin-ichiro KAWASAKI)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5067 c046a42c-6fe2-441c-8c8c-71466251a162
hw/sh7750.c
... ... @@ -30,6 +30,7 @@
30 30 #include "sh7750_regs.h"
31 31 #include "sh7750_regnames.h"
32 32 #include "sh_intc.h"
  33 +#include "cpu.h"
33 34  
34 35 #define NB_DEVICES 4
35 36  
... ... @@ -532,10 +533,113 @@ static struct intc_group groups_pci[] = {
532 533 #define SH_CPU_SH7750_ALL (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7750R)
533 534 #define SH_CPU_SH7751_ALL (SH_CPU_SH7751 | SH_CPU_SH7751R)
534 535  
  536 +/**********************************************************************
  537 + Memory mapped cache and TLB
  538 +**********************************************************************/
  539 +
  540 +#define MM_REGION_MASK 0x07000000
  541 +#define MM_ICACHE_ADDR (0)
  542 +#define MM_ICACHE_DATA (1)
  543 +#define MM_ITLB_ADDR (2)
  544 +#define MM_ITLB_DATA (3)
  545 +#define MM_OCACHE_ADDR (4)
  546 +#define MM_OCACHE_DATA (5)
  547 +#define MM_UTLB_ADDR (6)
  548 +#define MM_UTLB_DATA (7)
  549 +#define MM_REGION_TYPE(addr) ((addr & MM_REGION_MASK) >> 24)
  550 +
  551 +static uint32_t invalid_read(void *opaque, target_phys_addr_t addr)
  552 +{
  553 + assert(0);
  554 +
  555 + return 0;
  556 +}
  557 +
  558 +static uint32_t sh7750_mmct_readl(void *opaque, target_phys_addr_t addr)
  559 +{
  560 + uint32_t ret = 0;
  561 +
  562 + switch (MM_REGION_TYPE(addr)) {
  563 + case MM_ICACHE_ADDR:
  564 + case MM_ICACHE_DATA:
  565 + /* do nothing */
  566 + break;
  567 + case MM_ITLB_ADDR:
  568 + case MM_ITLB_DATA:
  569 + /* XXXXX */
  570 + assert(0);
  571 + break;
  572 + case MM_OCACHE_ADDR:
  573 + case MM_OCACHE_DATA:
  574 + /* do nothing */
  575 + break;
  576 + case MM_UTLB_ADDR:
  577 + case MM_UTLB_DATA:
  578 + /* XXXXX */
  579 + assert(0);
  580 + break;
  581 + default:
  582 + assert(0);
  583 + }
  584 +
  585 + return ret;
  586 +}
  587 +
  588 +static void invalid_write(void *opaque, target_phys_addr_t addr,
  589 + uint32_t mem_value)
  590 +{
  591 + assert(0);
  592 +}
  593 +
  594 +static void sh7750_mmct_writel(void *opaque, target_phys_addr_t addr,
  595 + uint32_t mem_value)
  596 +{
  597 + SH7750State *s = opaque;
  598 +
  599 + switch (MM_REGION_TYPE(addr)) {
  600 + case MM_ICACHE_ADDR:
  601 + case MM_ICACHE_DATA:
  602 + /* do nothing */
  603 + break;
  604 + case MM_ITLB_ADDR:
  605 + case MM_ITLB_DATA:
  606 + /* XXXXX */
  607 + assert(0);
  608 + break;
  609 + case MM_OCACHE_ADDR:
  610 + case MM_OCACHE_DATA:
  611 + /* do nothing */
  612 + break;
  613 + case MM_UTLB_ADDR:
  614 + cpu_sh4_write_mmaped_utlb_addr(s->cpu, addr, mem_value);
  615 + break;
  616 + case MM_UTLB_DATA:
  617 + /* XXXXX */
  618 + assert(0);
  619 + break;
  620 + default:
  621 + assert(0);
  622 + break;
  623 + }
  624 +}
  625 +
  626 +static CPUReadMemoryFunc *sh7750_mmct_read[] = {
  627 + invalid_read,
  628 + invalid_read,
  629 + sh7750_mmct_readl
  630 +};
  631 +
  632 +static CPUWriteMemoryFunc *sh7750_mmct_write[] = {
  633 + invalid_write,
  634 + invalid_write,
  635 + sh7750_mmct_writel
  636 +};
  637 +
535 638 SH7750State *sh7750_init(CPUSH4State * cpu)
536 639 {
537 640 SH7750State *s;
538 641 int sh7750_io_memory;
  642 + int sh7750_mm_cache_and_tlb; /* memory mapped cache and tlb */
539 643 int cpu_model = SH_CPU_SH7751R; /* for now */
540 644  
541 645 s = qemu_mallocz(sizeof(SH7750State));
... ... @@ -546,6 +650,12 @@ SH7750State *sh7750_init(CPUSH4State * cpu)
546 650 sh7750_mem_write, s);
547 651 cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
548 652  
  653 + sh7750_mm_cache_and_tlb = cpu_register_io_memory(0,
  654 + sh7750_mmct_read,
  655 + sh7750_mmct_write, s);
  656 + cpu_register_physical_memory(0xf0000000, 0x08000000,
  657 + sh7750_mm_cache_and_tlb);
  658 +
549 659 sh_intc_init(&s->intc, NR_SOURCES,
550 660 _INTC_ARRAY(mask_registers),
551 661 _INTC_ARRAY(prio_registers));
... ...
target-sh4/cpu.h
... ... @@ -124,6 +124,8 @@ CPUSH4State *cpu_sh4_init(const char *cpu_model);
124 124 int cpu_sh4_exec(CPUSH4State * s);
125 125 int cpu_sh4_signal_handler(int host_signum, void *pinfo,
126 126 void *puc);
  127 +void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
  128 + uint32_t mem_value);
127 129  
128 130 #include "softfloat.h"
129 131  
... ...
target-sh4/helper.c
... ... @@ -282,6 +282,29 @@ static int find_tlb_entry(CPUState * env, target_ulong address,
282 282 return match;
283 283 }
284 284  
  285 +static int same_tlb_entry_exists(const tlb_t * haystack, uint8_t nbtlb,
  286 + const tlb_t * needle)
  287 +{
  288 + int i;
  289 + for (i = 0; i < nbtlb; i++)
  290 + if (!memcmp(&haystack[i], needle, sizeof(tlb_t)))
  291 + return 1;
  292 + return 0;
  293 +}
  294 +
  295 +static void increment_urc(CPUState * env)
  296 +{
  297 + uint8_t urb, urc;
  298 +
  299 + /* Increment URC */
  300 + urb = ((env->mmucr) >> 18) & 0x3f;
  301 + urc = ((env->mmucr) >> 10) & 0x3f;
  302 + urc++;
  303 + if (urc == urb || urc == UTLB_SIZE - 1)
  304 + urc = 0;
  305 + env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
  306 +}
  307 +
285 308 /* Find itlb entry - update itlb from utlb if necessary and asked for
286 309 Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
287 310 Update the itlb from utlb if update is not 0
... ... @@ -313,15 +336,8 @@ int find_itlb_entry(CPUState * env, target_ulong address,
313 336 Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
314 337 int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
315 338 {
316   - uint8_t urb, urc;
317   -
318   - /* Increment URC */
319   - urb = ((env->mmucr) >> 18) & 0x3f;
320   - urc = ((env->mmucr) >> 10) & 0x3f;
321   - urc++;
322   - if (urc == urb || urc == UTLB_SIZE - 1)
323   - urc = 0;
324   - env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
  339 + /* per utlb access */
  340 + increment_urc(env);
325 341  
326 342 /* Return entry */
327 343 return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
... ... @@ -407,8 +423,21 @@ int get_physical_address(CPUState * env, target_ulong * physical,
407 423 return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
408 424 MMU_DTLB_MISS_READ;
409 425 }
410   - /* Mask upper 3 bits */
411   - *physical = address & 0x1FFFFFFF;
  426 + if (address >= 0x80000000 && address < 0xc0000000) {
  427 + /* Mask upper 3 bits for P1 and P2 areas */
  428 + *physical = address & 0x1fffffff;
  429 + } else if (address >= 0xfc000000) {
  430 + /*
  431 + * Mask upper 3 bits for control registers in P4 area,
  432 + * to unify access to control registers via P0-P3 area.
  433 + * The addresses for cache store queue, TLB address array
  434 + * are not masked.
  435 + */
  436 + *physical = address & 0x1fffffff;
  437 + } else {
  438 + /* access to cache store queue, or TLB address array. */
  439 + *physical = address;
  440 + }
412 441 *prot = PAGE_READ | PAGE_WRITE;
413 442 return MMU_OK;
414 443 }
... ... @@ -543,4 +572,75 @@ void cpu_load_tlb(CPUState * env)
543 572 entry->tc = (uint8_t)cpu_ptea_tc(env->ptea);
544 573 }
545 574  
  575 +void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr,
  576 + uint32_t mem_value)
  577 +{
  578 + int associate = addr & 0x0000080;
  579 + uint32_t vpn = (mem_value & 0xfffffc00) >> 10;
  580 + uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9);
  581 + uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8);
  582 + uint8_t asid = (uint8_t)(mem_value & 0x000000ff);
  583 +
  584 + if (associate) {
  585 + int i;
  586 + tlb_t * utlb_match_entry = NULL;
  587 + int needs_tlb_flush = 0;
  588 +
  589 + /* search UTLB */
  590 + for (i = 0; i < UTLB_SIZE; i++) {
  591 + tlb_t * entry = &s->utlb[i];
  592 + if (!entry->v)
  593 + continue;
  594 +
  595 + if (entry->vpn == vpn && entry->asid == asid) {
  596 + if (utlb_match_entry) {
  597 + /* Multiple TLB Exception */
  598 + s->exception_index = 0x140;
  599 + s->tea = addr;
  600 + break;
  601 + }
  602 + if (entry->v && !v)
  603 + needs_tlb_flush = 1;
  604 + entry->v = v;
  605 + entry->d = d;
  606 + utlb_match_entry = entry;
  607 + }
  608 + increment_urc(s); /* per utlb access */
  609 + }
  610 +
  611 + /* search ITLB */
  612 + for (i = 0; i < ITLB_SIZE; i++) {
  613 + tlb_t * entry = &s->itlb[i];
  614 + if (entry->vpn == vpn && entry->asid == asid) {
  615 + if (entry->v && !v)
  616 + needs_tlb_flush = 1;
  617 + if (utlb_match_entry)
  618 + *entry = *utlb_match_entry;
  619 + else
  620 + entry->v = v;
  621 + break;
  622 + }
  623 + }
  624 +
  625 + if (needs_tlb_flush)
  626 + tlb_flush_page(s, vpn << 10);
  627 +
  628 + } else {
  629 + int index = (addr & 0x00003f00) >> 8;
  630 + tlb_t * entry = &s->utlb[index];
  631 + if (entry->v) {
  632 + /* Overwriting valid entry in utlb. */
  633 + target_ulong address = entry->vpn << 10;
  634 + if (!same_tlb_entry_exists(s->itlb, ITLB_SIZE, entry)) {
  635 + tlb_flush_page(s, address);
  636 + }
  637 + }
  638 + entry->asid = asid;
  639 + entry->vpn = vpn;
  640 + entry->d = d;
  641 + entry->v = v;
  642 + increment_urc(s);
  643 + }
  644 +}
  645 +
546 646 #endif
... ...