25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips_coproc.c,v 1.23 2005/06/26 11:36:27 debug Exp $ |
* $Id: cpu_mips_coproc.c,v 1.27 2005/08/14 15:47:36 debug Exp $ |
29 |
* |
* |
30 |
* Emulation of MIPS coprocessors. |
* Emulation of MIPS coprocessors. |
31 |
*/ |
*/ |
88 |
#else |
#else |
89 |
const int m16 = 0; |
const int m16 = 0; |
90 |
#endif |
#endif |
91 |
int cpu_type, IB, DB, SB, IC, DC, SC; |
int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA; |
92 |
|
|
93 |
/* Default values: */ |
/* Default values: */ |
94 |
c->reg[COP0_CONFIG] = |
c->reg[COP0_CONFIG] = |
319 |
| ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */ |
| ( 1 << 7) /* MMU type: 1=TLB, 3=FMT */ |
320 |
| ( 2 << 0) /* kseg0 cache coherency algorithm */ |
| ( 2 << 0) /* kseg0 cache coherency algorithm */ |
321 |
; |
; |
322 |
/* Config select 1: caches etc. TODO: Associativity? */ |
/* Config select 1: caches etc. TODO: Don't use |
323 |
|
cpu->machine for this stuff! */ |
324 |
IB = cpu->machine->cache_picache_linesize - 1; |
IB = cpu->machine->cache_picache_linesize - 1; |
325 |
IB = IB < 0? 0 : (IB > 7? 7 : IB); |
IB = IB < 0? 0 : (IB > 7? 7 : IB); |
326 |
DB = cpu->machine->cache_pdcache_linesize - 1; |
DB = cpu->machine->cache_pdcache_linesize - 1; |
329 |
cpu->machine->cache_picache_linesize - 7; |
cpu->machine->cache_picache_linesize - 7; |
330 |
DC = cpu->machine->cache_pdcache - |
DC = cpu->machine->cache_pdcache - |
331 |
cpu->machine->cache_pdcache_linesize - 7; |
cpu->machine->cache_pdcache_linesize - 7; |
332 |
|
IA = cpu->cd.mips.cpu_type.piways - 1; |
333 |
|
DA = cpu->cd.mips.cpu_type.pdways - 1; |
334 |
cpu->cd.mips.cop0_config_select1 = |
cpu->cd.mips.cop0_config_select1 = |
335 |
((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25) |
((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25) |
336 |
| (IC << 22) /* IS: I-cache sets per way */ |
| (IC << 22) /* IS: I-cache sets per way */ |
337 |
| (IB << 19) /* IL: I-cache line-size */ |
| (IB << 19) /* IL: I-cache line-size */ |
338 |
| (1 << 16) /* IA: I-cache assoc. (ways-1) */ |
| (IA << 16) /* IA: I-cache assoc. (ways-1) */ |
339 |
| (DC << 13) /* DS: D-cache sets per way */ |
| (DC << 13) /* DS: D-cache sets per way */ |
340 |
| (DB << 10) /* DL: D-cache line-size */ |
| (DB << 10) /* DL: D-cache line-size */ |
341 |
| (1 << 7) /* DA: D-cache assoc. (ways-1) */ |
| (DA << 7) /* DA: D-cache assoc. (ways-1) */ |
342 |
| (16 * 0) /* Existance of PerformanceCounters */ |
| (16 * 0) /* Existance of PerformanceCounters */ |
343 |
| ( 8 * 0) /* Existance of Watch Registers */ |
| ( 8 * 0) /* Existance of Watch Registers */ |
344 |
| ( 4 * m16) /* Existance of MIPS16 */ |
| ( 4 * m16) /* Existance of MIPS16 */ |
535 |
} |
} |
536 |
|
|
537 |
|
|
|
#ifdef BINTRANS |
|
538 |
/* |
/* |
539 |
* old_update_translation_table(): |
* old_update_translation_table(): |
540 |
*/ |
*/ |
541 |
static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, |
static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, |
542 |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
543 |
{ |
{ |
544 |
int a, b; |
int a, b, index; |
545 |
struct vth32_table *tbl1; |
struct vth32_table *tbl1; |
546 |
void *p_r, *p_w; |
void *p_r, *p_w; |
547 |
uint32_t p_paddr; |
uint32_t p_paddr; |
557 |
|
|
558 |
a = (vaddr_page >> 22) & 0x3ff; |
a = (vaddr_page >> 22) & 0x3ff; |
559 |
b = (vaddr_page >> 12) & 0x3ff; |
b = (vaddr_page >> 12) & 0x3ff; |
560 |
|
index = (vaddr_page >> 12) & 0xfffff; |
561 |
|
|
562 |
/* printf("vaddr = %08x, a = %03x, b = %03x\n", |
/* printf("vaddr = %08x, a = %03x, b = %03x\n", |
563 |
(int)vaddr_page,a, b); */ |
(int)vaddr_page,a, b); */ |
564 |
|
|
565 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
566 |
/* printf("tbl1 = %p\n", tbl1); */ |
/* printf("tbl1 = %p\n", tbl1); */ |
567 |
if (tbl1 == cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
if (tbl1 == cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
577 |
memset(tbl1, 0, sizeof(struct vth32_table)); |
memset(tbl1, 0, sizeof(struct vth32_table)); |
578 |
} else { |
} else { |
579 |
tbl1 = cpu->cd.mips.next_free_vth_table; |
tbl1 = cpu->cd.mips.next_free_vth_table; |
580 |
cpu->cd.mips.next_free_vth_table = |
cpu->cd.mips.next_free_vth_table = tbl1->next_free; |
|
tbl1->next_free; |
|
581 |
tbl1->next_free = NULL; |
tbl1->next_free = NULL; |
582 |
} |
} |
583 |
cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1; |
cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1; |
600 |
if (writeflag == -1) { |
if (writeflag == -1) { |
601 |
/* Forced downgrade to read-only: */ |
/* Forced downgrade to read-only: */ |
602 |
tbl1->haddr_entry[b*2 + 1] = NULL; |
tbl1->haddr_entry[b*2 + 1] = NULL; |
603 |
|
if (cpu->cd.mips.host_store == |
604 |
|
cpu->cd.mips.host_store_orig) |
605 |
|
cpu->cd.mips.host_store[index] = NULL; |
606 |
} else if (writeflag==0 && p_w != NULL && host_page != NULL) { |
} else if (writeflag==0 && p_w != NULL && host_page != NULL) { |
607 |
/* Don't degrade a page from writable to readonly. */ |
/* Don't degrade a page from writable to readonly. */ |
608 |
} else { |
} else { |
609 |
if (host_page != NULL) { |
if (host_page != NULL) { |
610 |
tbl1->haddr_entry[b*2] = host_page; |
tbl1->haddr_entry[b*2] = host_page; |
611 |
if (writeflag) |
if (cpu->cd.mips.host_load == |
612 |
|
cpu->cd.mips.host_load_orig) |
613 |
|
cpu->cd.mips.host_load[index] = host_page; |
614 |
|
if (writeflag) { |
615 |
tbl1->haddr_entry[b*2+1] = host_page; |
tbl1->haddr_entry[b*2+1] = host_page; |
616 |
else |
if (cpu->cd.mips.host_store == |
617 |
|
cpu->cd.mips.host_store_orig) |
618 |
|
cpu->cd.mips.host_store[index] = |
619 |
|
host_page; |
620 |
|
} else { |
621 |
tbl1->haddr_entry[b*2+1] = NULL; |
tbl1->haddr_entry[b*2+1] = NULL; |
622 |
|
if (cpu->cd.mips.host_store == |
623 |
|
cpu->cd.mips.host_store_orig) |
624 |
|
cpu->cd.mips.host_store[index] = NULL; |
625 |
|
} |
626 |
} else { |
} else { |
627 |
tbl1->haddr_entry[b*2] = NULL; |
tbl1->haddr_entry[b*2] = NULL; |
628 |
tbl1->haddr_entry[b*2+1] = NULL; |
tbl1->haddr_entry[b*2+1] = NULL; |
629 |
|
if (cpu->cd.mips.host_store == |
630 |
|
cpu->cd.mips.host_store_orig) { |
631 |
|
cpu->cd.mips.host_load[index] = NULL; |
632 |
|
cpu->cd.mips.host_store[index] = NULL; |
633 |
|
} |
634 |
} |
} |
635 |
tbl1->paddr_entry[b] = paddr_page; |
tbl1->paddr_entry[b] = paddr_page; |
636 |
} |
} |
637 |
tbl1->bintrans_chunks[b] = NULL; |
tbl1->bintrans_chunks[b] = NULL; |
638 |
} |
} |
|
#endif |
|
639 |
|
|
640 |
|
|
641 |
/* |
/* |
642 |
* update_translation_table(): |
* mips_update_translation_table(): |
643 |
*/ |
*/ |
644 |
void update_translation_table(struct cpu *cpu, uint64_t vaddr_page, |
void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page, |
645 |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
unsigned char *host_page, int writeflag, uint64_t paddr_page) |
646 |
{ |
{ |
|
#ifdef BINTRANS |
|
647 |
if (!cpu->machine->bintrans_enable) |
if (!cpu->machine->bintrans_enable) |
648 |
return; |
return; |
649 |
|
|
658 |
|
|
659 |
/* TODO */ |
/* TODO */ |
660 |
/* printf("update_translation_table(): TODO\n"); */ |
/* printf("update_translation_table(): TODO\n"); */ |
|
#endif |
|
661 |
} |
} |
662 |
|
|
663 |
|
|
|
#ifdef BINTRANS |
|
664 |
/* |
/* |
665 |
* invalidate_table_entry(): |
* invalidate_table_entry(): |
666 |
*/ |
*/ |
667 |
static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr) |
static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr) |
668 |
{ |
{ |
669 |
int a, b; |
int a, b, index; |
670 |
struct vth32_table *tbl1; |
struct vth32_table *tbl1; |
671 |
void *p_r, *p_w; |
void *p_r, *p_w; |
672 |
uint32_t p_paddr; |
uint32_t p_paddr; |
693 |
|
|
694 |
a = (vaddr >> 22) & 0x3ff; |
a = (vaddr >> 22) & 0x3ff; |
695 |
b = (vaddr >> 12) & 0x3ff; |
b = (vaddr >> 12) & 0x3ff; |
696 |
|
index = (vaddr >> 12) & 0xfffff; |
697 |
|
|
698 |
/* printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */ |
/* printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */ |
699 |
|
|
704 |
p_paddr = tbl1->paddr_entry[b]; |
p_paddr = tbl1->paddr_entry[b]; |
705 |
tbl1->bintrans_chunks[b] = NULL; |
tbl1->bintrans_chunks[b] = NULL; |
706 |
/* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */ |
/* printf("B: p_r=%p p_w=%p\n", p_r,p_w); */ |
707 |
|
cpu->cd.mips.host_load_orig[index] = NULL; |
708 |
|
cpu->cd.mips.host_store_orig[index] = NULL; |
709 |
if (p_r != NULL || p_paddr != 0) { |
if (p_r != NULL || p_paddr != 0) { |
710 |
/* printf("Found a mapping, " |
/* printf("Found a mapping, " |
711 |
"vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */ |
"vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b); */ |
741 |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a]; |
742 |
if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) { |
743 |
for (b=0; b<0x400; b++) { |
for (b=0; b<0x400; b++) { |
744 |
|
int index; |
745 |
|
|
746 |
tbl1->haddr_entry[b*2] = NULL; |
tbl1->haddr_entry[b*2] = NULL; |
747 |
tbl1->haddr_entry[b*2+1] = NULL; |
tbl1->haddr_entry[b*2+1] = NULL; |
748 |
tbl1->paddr_entry[b] = 0; |
tbl1->paddr_entry[b] = 0; |
749 |
tbl1->bintrans_chunks[b] = NULL; |
tbl1->bintrans_chunks[b] = NULL; |
750 |
|
|
751 |
|
if (cpu->cd.mips.host_store == |
752 |
|
cpu->cd.mips.host_store_orig) { |
753 |
|
index = (a << 10) + b; |
754 |
|
cpu->cd.mips.host_load[index] = NULL; |
755 |
|
cpu->cd.mips.host_store[index] = NULL; |
756 |
|
} |
757 |
} |
} |
758 |
} |
} |
759 |
} |
} |
760 |
} |
} |
|
#endif |
|
761 |
|
|
762 |
|
|
763 |
/* |
/* |
767 |
*/ |
*/ |
768 |
void mips_invalidate_translation_caches_paddr(struct cpu *cpu, uint64_t paddr) |
void mips_invalidate_translation_caches_paddr(struct cpu *cpu, uint64_t paddr) |
769 |
{ |
{ |
|
#ifdef BINTRANS |
|
770 |
paddr &= ~0xfff; |
paddr &= ~0xfff; |
771 |
|
|
772 |
if (cpu->machine->bintrans_enable) { |
if (cpu->machine->bintrans_enable) { |
871 |
cpu->bintrans_data_hostpage[i] = NULL; |
cpu->bintrans_data_hostpage[i] = NULL; |
872 |
} |
} |
873 |
#endif |
#endif |
|
|
|
|
#endif |
|
874 |
} |
} |
875 |
|
|
876 |
|
|
889 |
/* printf("inval(all=%i, kernel=%i, addr=%016llx)\n", |
/* printf("inval(all=%i, kernel=%i, addr=%016llx)\n", |
890 |
all, kernelspace, (long long)vaddr); */ |
all, kernelspace, (long long)vaddr); */ |
891 |
|
|
|
#ifdef BINTRANS |
|
892 |
if (!cpu->machine->bintrans_enable) |
if (!cpu->machine->bintrans_enable) |
893 |
goto nobintrans; |
goto nobintrans; |
894 |
|
|
969 |
/* TODO: Don't invalidate everything. */ |
/* TODO: Don't invalidate everything. */ |
970 |
for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++) |
for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++) |
971 |
cpu->cd.mips.bintrans_data_hostpage[i] = NULL; |
cpu->cd.mips.bintrans_data_hostpage[i] = NULL; |
|
#endif |
|
972 |
|
|
973 |
if (kernelspace) |
if (kernelspace) |
974 |
all = 1; |
all = 1; |
1301 |
} |
} |
1302 |
#endif |
#endif |
1303 |
|
|
|
#ifdef BINTRANS |
|
1304 |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && |
if (cpu->cd.mips.cpu_type.mmu_model == MMU3K && |
1305 |
(oldmode & MIPS1_ISOL_CACHES) != |
(oldmode & MIPS1_ISOL_CACHES) != |
1306 |
(tmp & MIPS1_ISOL_CACHES)) { |
(tmp & MIPS1_ISOL_CACHES)) { |
1308 |
treated in bintrans mode by changing |
treated in bintrans mode by changing |
1309 |
the vaddr_to_hostaddr_table0 pointer: */ |
the vaddr_to_hostaddr_table0 pointer: */ |
1310 |
if (tmp & MIPS1_ISOL_CACHES) { |
if (tmp & MIPS1_ISOL_CACHES) { |
1311 |
/* cpu->cd.mips. |
/* 2-level table: */ |
|
dont_run_next_bintrans = 1; */ |
|
1312 |
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
1313 |
tmp & MIPS1_SWAP_CACHES? |
tmp & MIPS1_SWAP_CACHES? |
1314 |
cpu->cd.mips. |
cpu->cd.mips. |
1315 |
vaddr_to_hostaddr_table0_cacheisol_i |
vaddr_to_hostaddr_table0_cacheisol_i |
1316 |
: cpu->cd.mips. |
: cpu->cd.mips. |
1317 |
vaddr_to_hostaddr_table0_cacheisol_d; |
vaddr_to_hostaddr_table0_cacheisol_d; |
1318 |
|
|
1319 |
|
/* 1M-entry table: */ |
1320 |
|
cpu->cd.mips.host_load = |
1321 |
|
cpu->cd.mips.host_store = |
1322 |
|
cpu->cd.mips.huge_r2k3k_cache_table; |
1323 |
} else { |
} else { |
1324 |
|
/* 2-level table: */ |
1325 |
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
cpu->cd.mips.vaddr_to_hostaddr_table0 = |
1326 |
cpu->cd.mips. |
cpu->cd.mips. |
1327 |
vaddr_to_hostaddr_table0_kernel; |
vaddr_to_hostaddr_table0_kernel; |
1328 |
|
|
1329 |
/* TODO: cpu->cd.mips. |
/* TODO: cpu->cd.mips. |
1330 |
vaddr_to_hostaddr_table0_user; */ |
vaddr_to_hostaddr_table0_user; */ |
1331 |
|
|
1332 |
|
/* 1M-entry table: */ |
1333 |
|
cpu->cd.mips.host_load = |
1334 |
|
cpu->cd.mips.host_load_orig; |
1335 |
|
cpu->cd.mips.host_store = |
1336 |
|
cpu->cd.mips.host_store_orig; |
1337 |
} |
} |
1338 |
} |
} |
|
#endif |
|
1339 |
unimpl = 0; |
unimpl = 0; |
1340 |
break; |
break; |
1341 |
case COP0_CAUSE: |
case COP0_CAUSE: |
2456 |
/* if (vaddr < 0x10000000) */ |
/* if (vaddr < 0x10000000) */ |
2457 |
wf = 0; |
wf = 0; |
2458 |
|
|
2459 |
update_translation_table(cpu, vaddr, memblock, |
cpu->update_translation_table(cpu, vaddr, memblock, |
2460 |
wf, paddr); |
wf, paddr); |
2461 |
} |
} |
2462 |
} else { |
} else { |