1 |
/* |
/* |
2 |
* Copyright (C) 2003-2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: cpu_mips.c,v 1.3 2005/09/19 20:10:57 debug Exp $ |
* $Id: cpu_mips.c,v 1.17 2006/02/17 20:27:21 debug Exp $ |
29 |
* |
* |
30 |
* MIPS core CPU emulation. |
* MIPS core CPU emulation. |
31 |
*/ |
*/ |
98 |
#include "cpu_mips16.c" |
#include "cpu_mips16.c" |
99 |
|
|
100 |
|
|
101 |
|
#ifdef EXPERIMENTAL_NEWMIPS |
102 |
|
#define DYNTRANS_DUALMODE_32 |
103 |
|
#define DYNTRANS_DELAYSLOT |
104 |
|
#include "tmp_mips_head.c" |
105 |
|
#endif |
106 |
|
|
107 |
|
|
108 |
/* |
/* |
109 |
* regname(): |
* regname(): |
110 |
* |
* |
164 |
cpu->name = cpu->cd.mips.cpu_type.name; |
cpu->name = cpu->cd.mips.cpu_type.name; |
165 |
cpu->byte_order = EMUL_LITTLE_ENDIAN; |
cpu->byte_order = EMUL_LITTLE_ENDIAN; |
166 |
cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER; |
cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER; |
167 |
cpu->update_translation_table = mips_update_translation_table; |
cpu->update_translation_table = mips_OLD_update_translation_table; |
168 |
cpu->invalidate_translation_caches_paddr = |
cpu->invalidate_translation_caches = |
169 |
mips_invalidate_translation_caches_paddr; |
mips_invalidate_translation_caches_paddr; |
170 |
|
|
171 |
if (cpu->cd.mips.cpu_type.isa_level <= 2 || |
if (cpu->cd.mips.cpu_type.isa_level <= 2 || |
342 |
cpu->translate_address = translate_address_generic; |
cpu->translate_address = translate_address_generic; |
343 |
} |
} |
344 |
|
|
345 |
/* Testing: */ |
/* Testing: */ |
346 |
cpu->cd.mips.host_load = zeroed_alloc(1048576 * |
cpu->cd.mips.host_OLD_load = zeroed_alloc(1048576 * |
347 |
sizeof(unsigned char *)); |
sizeof(unsigned char *)); |
348 |
cpu->cd.mips.host_store = zeroed_alloc(1048576 * |
cpu->cd.mips.host_OLD_store = zeroed_alloc(1048576 * |
349 |
sizeof(unsigned char *)); |
sizeof(unsigned char *)); |
350 |
cpu->cd.mips.host_load_orig = cpu->cd.mips.host_load; |
cpu->cd.mips.host_load_orig = cpu->cd.mips.host_OLD_load; |
351 |
cpu->cd.mips.host_store_orig = cpu->cd.mips.host_store; |
cpu->cd.mips.host_store_orig = cpu->cd.mips.host_OLD_store; |
352 |
|
|
353 |
return 1; |
return 1; |
354 |
} |
} |
355 |
|
|
356 |
|
|
357 |
/* |
/* |
358 |
|
* mips_cpu_dumpinfo(): |
359 |
|
* |
360 |
|
* Debug dump of MIPS-specific CPU data for specific CPU. |
361 |
|
*/ |
362 |
|
void mips_cpu_dumpinfo(struct cpu *cpu) |
363 |
|
{ |
364 |
|
int iadd = DEBUG_INDENTATION; |
365 |
|
struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type; |
366 |
|
|
367 |
|
debug_indentation(iadd); |
368 |
|
|
369 |
|
debug("\n%i-bit %s (MIPS", |
370 |
|
cpu->is_32bit? 32 : 64, |
371 |
|
cpu->byte_order == EMUL_BIG_ENDIAN? "BE" : "LE"); |
372 |
|
|
373 |
|
switch (ct->isa_level) { |
374 |
|
case 1: debug(" ISA I"); break; |
375 |
|
case 2: debug(" ISA II"); break; |
376 |
|
case 3: debug(" ISA III"); break; |
377 |
|
case 4: debug(" ISA IV"); break; |
378 |
|
case 5: debug(" ISA V"); break; |
379 |
|
case 32: |
380 |
|
case 64:debug("%i", ct->isa_level); break; |
381 |
|
default:debug(" ISA level %i", ct->isa_level); |
382 |
|
} |
383 |
|
|
384 |
|
debug("), "); |
385 |
|
if (ct->nr_of_tlb_entries) |
386 |
|
debug("%i TLB entries", ct->nr_of_tlb_entries); |
387 |
|
else |
388 |
|
debug("no TLB"); |
389 |
|
debug("\n"); |
390 |
|
|
391 |
|
if (ct->picache) { |
392 |
|
debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024); |
393 |
|
if (ct->pilinesize) |
394 |
|
debug(", %i bytes per line", 1 << ct->pilinesize); |
395 |
|
if (ct->piways > 1) |
396 |
|
debug(", %i-way", ct->piways); |
397 |
|
else |
398 |
|
debug(", direct-mapped"); |
399 |
|
debug("\n"); |
400 |
|
} |
401 |
|
|
402 |
|
if (ct->pdcache) { |
403 |
|
debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024); |
404 |
|
if (ct->pdlinesize) |
405 |
|
debug(", %i bytes per line", 1 << ct->pdlinesize); |
406 |
|
if (ct->pdways > 1) |
407 |
|
debug(", %i-way", ct->pdways); |
408 |
|
else |
409 |
|
debug(", direct-mapped"); |
410 |
|
debug("\n"); |
411 |
|
} |
412 |
|
|
413 |
|
if (ct->scache) { |
414 |
|
int kb = (1 << ct->scache) / 1024; |
415 |
|
debug("L2 cache: %i %s", |
416 |
|
kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB"); |
417 |
|
if (ct->slinesize) |
418 |
|
debug(", %i bytes per line", 1 << ct->slinesize); |
419 |
|
if (ct->sways > 1) |
420 |
|
debug(", %i-way", ct->sways); |
421 |
|
else |
422 |
|
debug(", direct-mapped"); |
423 |
|
debug("\n"); |
424 |
|
} |
425 |
|
|
426 |
|
debug_indentation(-iadd); |
427 |
|
} |
428 |
|
|
429 |
|
|
430 |
|
/* |
431 |
|
* mips_cpu_list_available_types(): |
432 |
|
* |
433 |
|
* Print a list of available MIPS CPU types. |
434 |
|
*/ |
435 |
|
void mips_cpu_list_available_types(void) |
436 |
|
{ |
437 |
|
int i, j; |
438 |
|
struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS; |
439 |
|
|
440 |
|
i = 0; |
441 |
|
while (cpu_type_defs[i].name != NULL) { |
442 |
|
debug("%s", cpu_type_defs[i].name); |
443 |
|
for (j=10 - strlen(cpu_type_defs[i].name); j>0; j--) |
444 |
|
debug(" "); |
445 |
|
i++; |
446 |
|
if ((i % 6) == 0 || cpu_type_defs[i].name == NULL) |
447 |
|
debug("\n"); |
448 |
|
} |
449 |
|
} |
450 |
|
|
451 |
|
|
452 |
|
/* |
453 |
* mips_cpu_show_full_statistics(): |
* mips_cpu_show_full_statistics(): |
454 |
* |
* |
455 |
* Show detailed statistics on opcode usage on each cpu. |
* Show detailed statistics on opcode usage on each cpu. |
456 |
*/ |
*/ |
457 |
void mips_cpu_show_full_statistics(struct machine *m) |
void mips_cpu_show_full_statistics(struct machine *m) |
458 |
{ |
{ |
459 |
int i, s1, s2, iadd = 4; |
int i, s1, s2, iadd = DEBUG_INDENTATION; |
460 |
|
|
461 |
if (m->bintrans_enable) |
if (m->bintrans_enable) |
462 |
fatal("NOTE: Dynamic binary translation is used; this list" |
fatal("NOTE: Dynamic binary translation is used; this list" |
520 |
{ |
{ |
521 |
int i, j; |
int i, j; |
522 |
|
|
523 |
/* Nicely formatted output: */ |
/* Raw output: */ |
524 |
if (!rawflag) { |
if (rawflag) { |
525 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
|
int pageshift = 12; |
|
|
|
|
526 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
527 |
continue; |
continue; |
528 |
|
|
|
if (m->cpus[i]->cd.mips.cpu_type.rev == MIPS_R4100) |
|
|
pageshift = 10; |
|
|
|
|
529 |
/* Print index, random, and wired: */ |
/* Print index, random, and wired: */ |
530 |
printf("cpu%i: (", i); |
printf("cpu%i: (", i); |
531 |
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
|
532 |
case 1: |
if (m->cpus[i]->is_32bit) |
533 |
case 2: |
printf("index=0x%08x random=0x%08x", (int)m-> |
534 |
printf("index=0x%x random=0x%x", |
cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], |
535 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
(int)m->cpus[i]->cd.mips.coproc[0]->reg |
536 |
reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
[COP0_RANDOM]); |
537 |
>> R2K3K_INDEX_SHIFT), |
else |
538 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
printf("index=0x%016llx random=0x%016llx", |
539 |
reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
(long long)m->cpus[i]->cd.mips.coproc[0]-> |
540 |
>> R2K3K_RANDOM_SHIFT)); |
reg[COP0_INDEX], (long long)m->cpus[i]-> |
541 |
break; |
cd.mips.coproc[0]->reg[COP0_RANDOM]); |
542 |
default: |
|
543 |
printf("index=0x%x random=0x%x", |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
544 |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
printf(" wired=0x%llx", (long long) m->cpus |
545 |
reg[COP0_INDEX] & INDEX_MASK), |
[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); |
|
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
|
|
reg[COP0_RANDOM] & RANDOM_MASK)); |
|
|
printf(" wired=0x%llx", (long long) |
|
|
m->cpus[i]->cd.mips.coproc[0]-> |
|
|
reg[COP0_WIRED]); |
|
|
} |
|
546 |
|
|
547 |
printf(")\n"); |
printf(")\n"); |
548 |
|
|
549 |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
550 |
nr_of_tlb_entries; j++) { |
nr_of_tlb_entries; j++) { |
551 |
uint64_t hi,lo0,lo1,mask; |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == |
552 |
hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi; |
MMU3K) |
553 |
lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0; |
printf("%3i: hi=0x%08x lo=0x%08x\n", j, |
554 |
lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1; |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
555 |
mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask; |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); |
556 |
|
else if (m->cpus[i]->is_32bit) |
557 |
printf("%3i: ", j); |
printf("%3i: hi=0x%08x mask=0x%08x " |
558 |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
"lo0=0x%08x lo1=0x%08x\n", j, |
559 |
case MMU3K: |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
560 |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
561 |
printf("(invalid)\n"); |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
562 |
continue; |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
563 |
} |
else |
564 |
printf("vaddr=0x%08x ", |
printf("%3i: hi=0x%016llx mask=0x%016llx " |
565 |
(int) (hi&R2K3K_ENTRYHI_VPN_MASK)); |
"lo0=0x%016llx lo1=0x%016llx\n", j, |
566 |
if (lo0 & R2K3K_ENTRYLO_G) |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
567 |
printf("(global), "); |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
568 |
else |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
569 |
printf("(asid %02x),", |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
|
(int) ((hi & R2K3K_ENTRYHI_ASID_MASK) |
|
|
>> R2K3K_ENTRYHI_ASID_SHIFT)); |
|
|
printf(" paddr=0x%08x ", |
|
|
(int) (lo0&R2K3K_ENTRYLO_PFN_MASK)); |
|
|
if (lo0 & R2K3K_ENTRYLO_N) |
|
|
printf("N"); |
|
|
if (lo0 & R2K3K_ENTRYLO_D) |
|
|
printf("D"); |
|
|
printf("\n"); |
|
|
break; |
|
|
default: |
|
|
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
|
|
case MMU10K: |
|
|
printf("vaddr=0x%1x..%011llx ", |
|
|
(int) (hi >> 60), |
|
|
(long long) (hi&ENTRYHI_VPN2_MASK_R10K)); |
|
|
break; |
|
|
case MMU32: |
|
|
printf("vaddr=0x%08x ", (int)(hi&ENTRYHI_VPN2_MASK)); |
|
|
break; |
|
|
default:/* R4000 etc. */ |
|
|
printf("vaddr=0x%1x..%010llx ", |
|
|
(int) (hi >> 60), |
|
|
(long long) (hi&ENTRYHI_VPN2_MASK)); |
|
|
} |
|
|
if (hi & TLB_G) |
|
|
printf("(global): "); |
|
|
else |
|
|
printf("(asid %02x):", |
|
|
(int) (hi & ENTRYHI_ASID)); |
|
|
|
|
|
/* TODO: Coherency bits */ |
|
|
|
|
|
if (!(lo0 & ENTRYLO_V)) |
|
|
printf(" p0=(invalid) "); |
|
|
else |
|
|
printf(" p0=0x%09llx ", (long long) |
|
|
(((lo0&ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pageshift)); |
|
|
printf(lo0 & ENTRYLO_D? "D" : " "); |
|
|
|
|
|
if (!(lo1 & ENTRYLO_V)) |
|
|
printf(" p1=(invalid) "); |
|
|
else |
|
|
printf(" p1=0x%09llx ", (long long) |
|
|
(((lo1&ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pageshift)); |
|
|
printf(lo1 & ENTRYLO_D? "D" : " "); |
|
|
mask |= (1 << (pageshift+1)) - 1; |
|
|
switch (mask) { |
|
|
case 0x7ff: printf(" (1KB)"); break; |
|
|
case 0x1fff: printf(" (4KB)"); break; |
|
|
case 0x7fff: printf(" (16KB)"); break; |
|
|
case 0x1ffff: printf(" (64KB)"); break; |
|
|
case 0x7ffff: printf(" (256KB)"); break; |
|
|
case 0x1fffff: printf(" (1MB)"); break; |
|
|
case 0x7fffff: printf(" (4MB)"); break; |
|
|
case 0x1ffffff: printf(" (16MB)"); break; |
|
|
case 0x7ffffff: printf(" (64MB)"); break; |
|
|
default: |
|
|
printf(" (mask=%08x?)", (int)mask); |
|
|
} |
|
|
printf("\n"); |
|
|
} |
|
570 |
} |
} |
571 |
} |
} |
|
|
|
572 |
return; |
return; |
573 |
} |
} |
574 |
|
|
575 |
/* Raw output: */ |
/* Nicely formatted output: */ |
576 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
577 |
|
int pageshift = 12; |
578 |
|
|
579 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
580 |
continue; |
continue; |
581 |
|
|
582 |
|
if (m->cpus[i]->cd.mips.cpu_type.rev == MIPS_R4100) |
583 |
|
pageshift = 10; |
584 |
|
|
585 |
/* Print index, random, and wired: */ |
/* Print index, random, and wired: */ |
586 |
printf("cpu%i: (", i); |
printf("cpu%i: (", i); |
587 |
|
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
588 |
if (m->cpus[i]->is_32bit) |
case 1: |
589 |
printf("index=0x%08x random=0x%08x", |
case 2: printf("index=0x%x random=0x%x", |
590 |
(int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
591 |
(int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_RANDOM]); |
reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
592 |
else |
>> R2K3K_INDEX_SHIFT), |
593 |
printf("index=0x%016llx random=0x%016llx", (long long) |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
594 |
m->cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], |
reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
595 |
(long long)m->cpus[i]->cd.mips.coproc[0]->reg |
>> R2K3K_RANDOM_SHIFT)); |
596 |
[COP0_RANDOM]); |
break; |
597 |
|
default:printf("index=0x%x random=0x%x", |
598 |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
599 |
|
reg[COP0_INDEX] & INDEX_MASK), |
600 |
|
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
601 |
|
reg[COP0_RANDOM] & RANDOM_MASK)); |
602 |
printf(" wired=0x%llx", (long long) |
printf(" wired=0x%llx", (long long) |
603 |
m->cpus[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); |
m->cpus[i]->cd.mips.coproc[0]-> |
604 |
|
reg[COP0_WIRED]); |
605 |
|
} |
606 |
|
|
607 |
printf(")\n"); |
printf(")\n"); |
608 |
|
|
609 |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type.nr_of_tlb_entries; j++) { |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
610 |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == MMU3K) |
nr_of_tlb_entries; j++) { |
611 |
printf("%3i: hi=0x%08x lo=0x%08x\n", |
uint64_t hi,lo0,lo1,mask; |
612 |
j, |
hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi; |
613 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0; |
614 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); |
lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1; |
615 |
else if (m->cpus[i]->is_32bit) |
mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask; |
616 |
printf("%3i: hi=0x%08x mask=0x%08x " |
|
617 |
"lo0=0x%08x lo1=0x%08x\n", j, |
printf("%3i: ", j); |
618 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
619 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
case MMU3K: |
620 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
621 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
printf("(invalid)\n"); |
622 |
else |
continue; |
623 |
printf("%3i: hi=0x%016llx mask=0x%016llx " |
} |
624 |
"lo0=0x%016llx lo1=0x%016llx\n", j, |
printf("vaddr=0x%08x ", |
625 |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
(int) (hi&R2K3K_ENTRYHI_VPN_MASK)); |
626 |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
if (lo0 & R2K3K_ENTRYLO_G) |
627 |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
printf("(global), "); |
628 |
(long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
else |
629 |
|
printf("(asid %02x),", (int) ((hi & |
630 |
|
R2K3K_ENTRYHI_ASID_MASK) |
631 |
|
>> R2K3K_ENTRYHI_ASID_SHIFT)); |
632 |
|
printf(" paddr=0x%08x ", |
633 |
|
(int) (lo0&R2K3K_ENTRYLO_PFN_MASK)); |
634 |
|
if (lo0 & R2K3K_ENTRYLO_N) |
635 |
|
printf("N"); |
636 |
|
if (lo0 & R2K3K_ENTRYLO_D) |
637 |
|
printf("D"); |
638 |
|
printf("\n"); |
639 |
|
break; |
640 |
|
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
641 |
|
case MMU10K: |
642 |
|
printf("vaddr=0x%1x..%011llx ", |
643 |
|
(int) (hi >> 60), (long long) |
644 |
|
(hi&ENTRYHI_VPN2_MASK_R10K)); |
645 |
|
break; |
646 |
|
case MMU32: |
647 |
|
printf("vaddr=0x%08x ", (int) |
648 |
|
(hi&ENTRYHI_VPN2_MASK)); |
649 |
|
break; |
650 |
|
default:/* R4000 etc. */ |
651 |
|
printf("vaddr=0x%1x..%010llx ", |
652 |
|
(int) (hi >> 60), |
653 |
|
(long long) (hi&ENTRYHI_VPN2_MASK)); |
654 |
|
} |
655 |
|
if (hi & TLB_G) |
656 |
|
printf("(global): "); |
657 |
|
else |
658 |
|
printf("(asid %02x):", |
659 |
|
(int) (hi & ENTRYHI_ASID)); |
660 |
|
|
661 |
|
/* TODO: Coherency bits */ |
662 |
|
|
663 |
|
if (!(lo0 & ENTRYLO_V)) |
664 |
|
printf(" p0=(invalid) "); |
665 |
|
else |
666 |
|
printf(" p0=0x%09llx ", (long long) |
667 |
|
(((lo0&ENTRYLO_PFN_MASK) >> |
668 |
|
ENTRYLO_PFN_SHIFT) << pageshift)); |
669 |
|
printf(lo0 & ENTRYLO_D? "D" : " "); |
670 |
|
|
671 |
|
if (!(lo1 & ENTRYLO_V)) |
672 |
|
printf(" p1=(invalid) "); |
673 |
|
else |
674 |
|
printf(" p1=0x%09llx ", (long long) |
675 |
|
(((lo1&ENTRYLO_PFN_MASK) >> |
676 |
|
ENTRYLO_PFN_SHIFT) << pageshift)); |
677 |
|
printf(lo1 & ENTRYLO_D? "D" : " "); |
678 |
|
mask |= (1 << (pageshift+1)) - 1; |
679 |
|
switch (mask) { |
680 |
|
case 0x7ff: printf(" (1KB)"); break; |
681 |
|
case 0x1fff: printf(" (4KB)"); break; |
682 |
|
case 0x7fff: printf(" (16KB)"); break; |
683 |
|
case 0x1ffff: printf(" (64KB)"); break; |
684 |
|
case 0x7ffff: printf(" (256KB)"); break; |
685 |
|
case 0x1fffff: printf(" (1MB)"); break; |
686 |
|
case 0x7fffff: printf(" (4MB)"); break; |
687 |
|
case 0x1ffffff: printf(" (16MB)"); break; |
688 |
|
case 0x7ffffff: printf(" (64MB)"); break; |
689 |
|
default:printf(" (mask=%08x?)", (int)mask); |
690 |
|
} |
691 |
|
printf("\n"); |
692 |
|
} |
693 |
} |
} |
694 |
} |
} |
695 |
} |
} |
1079 |
if (imm >= 32768) |
if (imm >= 32768) |
1080 |
imm -= 65536; |
imm -= 65536; |
1081 |
addr = (dumpaddr + 4) + (imm << 2); |
addr = (dumpaddr + 4) + (imm << 2); |
|
debug("%s\t", hi6_names[hi6]); |
|
1082 |
|
|
1083 |
switch (hi6) { |
if (hi6 == HI6_BEQ && rt == MIPS_GPR_ZERO && |
1084 |
case HI6_BEQ: |
rs == MIPS_GPR_ZERO) |
1085 |
case HI6_BEQL: |
debug("b\t"); |
1086 |
case HI6_BNE: |
else { |
1087 |
case HI6_BNEL: |
debug("%s\t", hi6_names[hi6]); |
1088 |
debug("%s,", regname(cpu->machine, rt)); |
switch (hi6) { |
1089 |
|
case HI6_BEQ: |
1090 |
|
case HI6_BEQL: |
1091 |
|
case HI6_BNE: |
1092 |
|
case HI6_BNEL: |
1093 |
|
debug("%s,", regname(cpu->machine, rt)); |
1094 |
|
} |
1095 |
|
debug("%s,", regname(cpu->machine, rs)); |
1096 |
} |
} |
1097 |
|
|
|
debug("%s,", regname(cpu->machine, rs)); |
|
|
|
|
1098 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
1099 |
debug("0x%08x", (int)addr); |
debug("0x%08x", (int)addr); |
1100 |
else |
else |
1291 |
debug(",%s", regname(cpu->machine, rs)); |
debug(",%s", regname(cpu->machine, rs)); |
1292 |
debug(",%s", regname(cpu->machine, rt)); |
debug(",%s", regname(cpu->machine, rt)); |
1293 |
} else if (special6 == SPECIAL2_MUL) { |
} else if (special6 == SPECIAL2_MUL) { |
1294 |
/* TODO: this is just a guess, I don't have the |
/* Apparently used both on R5900 and MIPS32: */ |
|
docs in front of me */ |
|
1295 |
debug("mul\t%s", regname(cpu->machine, rd)); |
debug("mul\t%s", regname(cpu->machine, rd)); |
1296 |
debug(",%s", regname(cpu->machine, rs)); |
debug(",%s", regname(cpu->machine, rs)); |
1297 |
debug(",%s", regname(cpu->machine, rt)); |
debug(",%s", regname(cpu->machine, rt)); |
1531 |
} |
} |
1532 |
|
|
1533 |
|
|
1534 |
|
#ifndef EXPERIMENTAL_NEWMIPS |
1535 |
|
|
1536 |
#define DYNTRANS_FUNCTION_TRACE mips_cpu_functioncall_trace |
#define DYNTRANS_FUNCTION_TRACE mips_cpu_functioncall_trace |
1537 |
#define DYNTRANS_MIPS |
#define DYNTRANS_MIPS |
1538 |
#define DYNTRANS_ARCH mips |
#define DYNTRANS_ARCH mips |
1541 |
#undef DYNTRANS_ARCH |
#undef DYNTRANS_ARCH |
1542 |
#undef DYNTRANS_FUNCTION_TRACE |
#undef DYNTRANS_FUNCTION_TRACE |
1543 |
|
|
1544 |
|
#endif |
1545 |
|
|
1546 |
|
|
1547 |
/* |
/* |
1548 |
* mips_cpu_interrupt(): |
* mips_cpu_interrupt(): |
1577 |
* Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
* Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
1578 |
* interrupt. Interrupts 0..1 are ignored (software interrupts). |
* interrupt. Interrupts 0..1 are ignored (software interrupts). |
1579 |
* |
* |
1580 |
* If irq_nr is >= 8, then it is machine dependant, and md_interrupt() is |
* If irq_nr is >= 8, then it is machine dependent, and md_interrupt() is |
1581 |
* called. |
* called. |
1582 |
*/ |
*/ |
1583 |
int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) |
int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) |
1690 |
else |
else |
1691 |
fatal("0x%016llx", (long long)cpu->cd.mips.pc_last); |
fatal("0x%016llx", (long long)cpu->cd.mips.pc_last); |
1692 |
fatal(" <%s> ]\n", symbol? symbol : "(no symbol)"); |
fatal(" <%s> ]\n", symbol? symbol : "(no symbol)"); |
|
|
|
|
#ifdef TRACE_NULL_CRASHES |
|
|
/* This can be useful for debugging kernel bugs: */ |
|
|
{ |
|
|
int i = cpu->trace_null_index; |
|
|
do { |
|
|
fatal("TRACE: 0x%016llx\n", |
|
|
cpu->trace_null_addr[i]); |
|
|
i ++; |
|
|
i %= TRACE_NULL_N_ENTRIES; |
|
|
} while (i != cpu->trace_null_index); |
|
|
} |
|
|
cpu->running = 0; |
|
|
cpu->dead = 1; |
|
|
#endif |
|
1693 |
} |
} |
1694 |
|
|
1695 |
/* Clear the exception code bits of the cause register... */ |
/* Clear the exception code bits of the cause register... */ |
1858 |
#include "memory_mips.c" |
#include "memory_mips.c" |
1859 |
|
|
1860 |
|
|
1861 |
|
#ifndef EXPERIMENTAL_NEWMIPS |
1862 |
/* |
/* |
1863 |
* mips_cpu_run_instr(): |
* mips_OLD_cpu_run_instr(): |
1864 |
* |
* |
1865 |
* Execute one instruction on a cpu. |
* Execute one instruction on a cpu. |
1866 |
* |
* |
1870 |
* Return value is the number of instructions executed during this call, |
* Return value is the number of instructions executed during this call, |
1871 |
* 0 if no instruction was executed. |
* 0 if no instruction was executed. |
1872 |
*/ |
*/ |
1873 |
int mips_cpu_run_instr(struct emul *emul, struct cpu *cpu) |
int mips_OLD_cpu_run_instr(struct emul *emul, struct cpu *cpu) |
1874 |
{ |
{ |
1875 |
int quiet_mode_cached = quiet_mode; |
int quiet_mode_cached = quiet_mode; |
1876 |
int instruction_trace_cached = cpu->machine->instruction_trace; |
int instruction_trace_cached = cpu->machine->instruction_trace; |
1942 |
/* Cache the program counter in a local variable: */ |
/* Cache the program counter in a local variable: */ |
1943 |
cached_pc = cpu->pc; |
cached_pc = cpu->pc; |
1944 |
|
|
|
#ifdef TRACE_NULL_CRASHES |
|
|
cpu->trace_null_addr[cpu->trace_null_index] = cached_pc; |
|
|
cpu->trace_null_index ++; |
|
|
cpu->trace_null_index %= TRACE_NULL_N_ENTRIES; |
|
|
#endif |
|
|
|
|
1945 |
/* Hardwire the zero register to 0: */ |
/* Hardwire the zero register to 0: */ |
1946 |
cpu->cd.mips.gpr[MIPS_GPR_ZERO] = 0; |
cpu->cd.mips.gpr[MIPS_GPR_ZERO] = 0; |
1947 |
|
|
2019 |
} |
} |
2020 |
} |
} |
2021 |
|
|
|
|
|
2022 |
/* |
/* |
2023 |
* ROM emulation: (0xbfcXXXXX or 0x9fcXXXXX) |
* ROM emulation: (0xbfcXXXXX or 0x9fcXXXXX) |
2024 |
* |
* |
2029 |
cpu->machine->prom_emulation) { |
cpu->machine->prom_emulation) { |
2030 |
int rom_jal = 1, res = 1; |
int rom_jal = 1, res = 1; |
2031 |
switch (cpu->machine->machine_type) { |
switch (cpu->machine->machine_type) { |
2032 |
case MACHINE_DEC: |
case MACHINE_PMAX: |
2033 |
res = decstation_prom_emul(cpu); |
res = decstation_prom_emul(cpu); |
2034 |
break; |
break; |
2035 |
case MACHINE_PS2: |
case MACHINE_PS2: |
2160 |
} |
} |
2161 |
#endif |
#endif |
2162 |
|
|
|
PREFETCH(cpu->cd.mips.pc_last_host_4k_page + (cached_pc & 0xfff)); |
|
|
|
|
2163 |
#ifdef HALT_IF_PC_ZERO |
#ifdef HALT_IF_PC_ZERO |
2164 |
/* Halt if PC = 0: */ |
/* Halt if PC = 0: */ |
2165 |
if (cached_pc == 0) { |
if (cached_pc == 0) { |
3959 |
which_cache = copz & 3; |
which_cache = copz & 3; |
3960 |
|
|
3961 |
/* |
/* |
3962 |
* TODO: The cache instruction is implementation dependant. |
* TODO: The cache instruction is implementation dependent. |
3963 |
*/ |
*/ |
3964 |
|
|
3965 |
/* |
/* |
4061 |
((cpu->cd.mips.gpr[rs] & 0xffffffffULL) << 32) /* TODO: switch rt and rs? */ |
((cpu->cd.mips.gpr[rs] & 0xffffffffULL) << 32) /* TODO: switch rt and rs? */ |
4062 |
| (cpu->cd.mips.gpr[rt] & 0xffffffffULL); |
| (cpu->cd.mips.gpr[rt] & 0xffffffffULL); |
4063 |
} else if (special6 == SPECIAL2_MUL) { |
} else if (special6 == SPECIAL2_MUL) { |
4064 |
cpu->cd.mips.gpr[rd] = (int64_t)cpu->cd.mips.gpr[rt] * |
/* Apparently used both on R5900 MIPS32: */ |
4065 |
(int64_t)cpu->cd.mips.gpr[rs]; |
cpu->cd.mips.gpr[rd] = (int64_t)(int32_t) ( |
4066 |
|
(int32_t)cpu->cd.mips.gpr[rt] * |
4067 |
|
(int32_t)cpu->cd.mips.gpr[rs] ); |
4068 |
} else if (special6 == SPECIAL2_CLZ) { |
} else if (special6 == SPECIAL2_CLZ) { |
4069 |
/* clz: count leading zeroes */ |
/* clz: count leading zeroes */ |
4070 |
int i, n=0; |
int i, n=0; |
4130 |
|
|
4131 |
/* NOTREACHED */ |
/* NOTREACHED */ |
4132 |
} |
} |
4133 |
|
#endif /* !EXPERIMENTAL_NEWMIPS */ |
4134 |
|
|
4135 |
|
|
4136 |
#define CPU_RUN mips_cpu_run |
|
4137 |
|
#ifdef EXPERIMENTAL_NEWMIPS |
4138 |
|
|
4139 |
|
#include "tmp_mips_tail.c" |
4140 |
|
|
4141 |
|
#else |
4142 |
|
|
4143 |
|
#define CPU_RUN mips_OLD_cpu_run |
4144 |
#define CPU_RUN_MIPS |
#define CPU_RUN_MIPS |
4145 |
#define CPU_RINSTR mips_cpu_run_instr |
#define CPU_RINSTR mips_OLD_cpu_run_instr |
4146 |
#include "cpu_run.c" |
#include "cpu_run.c" |
4147 |
#undef CPU_RINSTR |
#undef CPU_RINSTR |
4148 |
#undef CPU_RUN_MIPS |
#undef CPU_RUN_MIPS |
4149 |
#undef CPU_RUN |
#undef CPU_RUN |
4150 |
|
CPU_OLD_FAMILY_INIT(mips,"MIPS") |
4151 |
|
|
4152 |
|
#endif |
|
/* |
|
|
* mips_cpu_dumpinfo(): |
|
|
* |
|
|
* Debug dump of MIPS-specific CPU data for specific CPU. |
|
|
*/ |
|
|
void mips_cpu_dumpinfo(struct cpu *cpu) |
|
|
{ |
|
|
int iadd = 4; |
|
|
struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type; |
|
|
|
|
|
debug_indentation(iadd); |
|
|
|
|
|
debug("\n%i-bit %s (MIPS", |
|
|
cpu->is_32bit? 32 : 64, |
|
|
cpu->byte_order == EMUL_BIG_ENDIAN? "BE" : "LE"); |
|
|
|
|
|
switch (ct->isa_level) { |
|
|
case 1: debug(" ISA I"); break; |
|
|
case 2: debug(" ISA II"); break; |
|
|
case 3: debug(" ISA III"); break; |
|
|
case 4: debug(" ISA IV"); break; |
|
|
case 5: debug(" ISA V"); break; |
|
|
case 32: |
|
|
case 64:debug("%i", ct->isa_level); break; |
|
|
default:debug(" ISA level %i", ct->isa_level); |
|
|
} |
|
|
|
|
|
debug("), "); |
|
|
if (ct->nr_of_tlb_entries) |
|
|
debug("%i TLB entries", ct->nr_of_tlb_entries); |
|
|
else |
|
|
debug("no TLB"); |
|
|
debug("\n"); |
|
|
|
|
|
if (ct->picache) { |
|
|
debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024); |
|
|
if (ct->pilinesize) |
|
|
debug(", %i bytes per line", 1 << ct->pilinesize); |
|
|
if (ct->piways > 1) |
|
|
debug(", %i-way", ct->piways); |
|
|
else |
|
|
debug(", direct-mapped"); |
|
|
debug("\n"); |
|
|
} |
|
|
|
|
|
if (ct->pdcache) { |
|
|
debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024); |
|
|
if (ct->pdlinesize) |
|
|
debug(", %i bytes per line", 1 << ct->pdlinesize); |
|
|
if (ct->pdways > 1) |
|
|
debug(", %i-way", ct->pdways); |
|
|
else |
|
|
debug(", direct-mapped"); |
|
|
debug("\n"); |
|
|
} |
|
|
|
|
|
if (ct->scache) { |
|
|
int kb = (1 << ct->scache) / 1024; |
|
|
debug("L2 cache: %i %s", |
|
|
kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB"); |
|
|
if (ct->slinesize) |
|
|
debug(", %i bytes per line", 1 << ct->slinesize); |
|
|
if (ct->sways > 1) |
|
|
debug(", %i-way", ct->sways); |
|
|
else |
|
|
debug(", direct-mapped"); |
|
|
debug("\n"); |
|
|
} |
|
|
|
|
|
debug_indentation(-iadd); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* mips_cpu_list_available_types(): |
|
|
* |
|
|
* Print a list of available MIPS CPU types. |
|
|
*/ |
|
|
void mips_cpu_list_available_types(void) |
|
|
{ |
|
|
int i, j; |
|
|
struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS; |
|
|
|
|
|
i = 0; |
|
|
while (cpu_type_defs[i].name != NULL) { |
|
|
debug("%s", cpu_type_defs[i].name); |
|
|
for (j=10 - strlen(cpu_type_defs[i].name); j>0; j--) |
|
|
debug(" "); |
|
|
i++; |
|
|
if ((i % 6) == 0 || cpu_type_defs[i].name == NULL) |
|
|
debug("\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
CPU_FAMILY_INIT(mips,"MIPS") |
|
4153 |
|
|
4154 |
|
|
4155 |
#endif /* ENABLE_MIPS */ |
#endif /* ENABLE_MIPS */ |