Revision 29e179bc
b/hw/sh7750.c | ||
---|---|---|
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 | 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 | 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)); |
b/target-sh4/cpu.h | ||
---|---|---|
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 |
|
b/target-sh4/helper.c | ||
---|---|---|
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 | 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 | 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 | 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 |
Also available in: Unified diff