1 |
/* |
/* |
2 |
* Copyright (C) 2003-2006 Anders Gavare. All rights reserved. |
* Copyright (C) 2003-2007 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.69 2006/10/07 02:05:21 debug Exp $ |
* $Id: cpu_mips.c,v 1.79 2007/04/28 09:19:51 debug Exp $ |
29 |
* |
* |
30 |
* MIPS core CPU emulation. |
* MIPS core CPU emulation. |
31 |
*/ |
*/ |
88 |
* Convert a register number into either 'r0', 'r31' etc, or a symbolic |
* Convert a register number into either 'r0', 'r31' etc, or a symbolic |
89 |
* name, depending on machine->show_symbolic_register_names. |
* name, depending on machine->show_symbolic_register_names. |
90 |
* |
* |
91 |
* NOTE: _NOT_ reentrant. |
* NOTE: This helper function is _NOT_ reentrant. |
92 |
*/ |
*/ |
93 |
static char *regname(struct machine *machine, int r) |
static char *regname(struct machine *machine, int r) |
94 |
{ |
{ |
304 |
debug(")"); |
debug(")"); |
305 |
} |
} |
306 |
|
|
307 |
|
/* Register the CPU's interrupts: */ |
308 |
|
for (i=2; i<8; i++) { |
309 |
|
struct interrupt template; |
310 |
|
char name[50]; |
311 |
|
snprintf(name, sizeof(name), "%s.%i", cpu->path, i); |
312 |
|
memset(&template, 0, sizeof(template)); |
313 |
|
template.line = 1 << (STATUS_IM_SHIFT + i); |
314 |
|
template.name = name; |
315 |
|
template.extra = cpu; |
316 |
|
template.interrupt_assert = mips_cpu_interrupt_assert; |
317 |
|
template.interrupt_deassert = mips_cpu_interrupt_deassert; |
318 |
|
interrupt_handler_register(&template); |
319 |
|
|
320 |
|
if (i == 7) |
321 |
|
INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare); |
322 |
|
} |
323 |
|
|
324 |
/* System coprocessor (0), and FPU (1): */ |
/* System coprocessor (0), and FPU (1): */ |
325 |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
326 |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
533 |
/* Raw output: */ |
/* Raw output: */ |
534 |
if (rawflag) { |
if (rawflag) { |
535 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
536 |
|
struct mips_coproc *cop0 = |
537 |
|
m->cpus[i]->cd.mips.coproc[0]; |
538 |
|
|
539 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
540 |
continue; |
continue; |
541 |
|
|
543 |
printf("cpu%i: (", i); |
printf("cpu%i: (", i); |
544 |
|
|
545 |
if (m->cpus[i]->is_32bit) |
if (m->cpus[i]->is_32bit) |
546 |
printf("index=0x%08x random=0x%08x", (int)m-> |
printf("index=0x%08x random=0x%08x", |
547 |
cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], |
(int) cop0->reg[COP0_INDEX], |
548 |
(int)m->cpus[i]->cd.mips.coproc[0]->reg |
(int) cop0->reg[COP0_RANDOM]); |
|
[COP0_RANDOM]); |
|
549 |
else |
else |
550 |
printf("index=0x%016"PRIx64 |
printf("index=0x%016"PRIx64 |
551 |
" random=0x%016"PRIx64, |
" random=0x%016"PRIx64, |
552 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]-> |
(uint64_t) cop0->reg[COP0_INDEX], |
553 |
reg[COP0_INDEX], (uint64_t)m->cpus[i]-> |
(uint64_t) cop0->reg[COP0_RANDOM]); |
|
cd.mips.coproc[0]->reg[COP0_RANDOM]); |
|
554 |
|
|
555 |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
556 |
printf(" wired=0x%"PRIx64, (uint64_t) m->cpus |
printf(" wired=0x%"PRIx64, |
557 |
[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); |
(uint64_t) cop0->reg[COP0_WIRED]); |
558 |
|
|
559 |
printf(")\n"); |
printf(")\n"); |
560 |
|
|
562 |
nr_of_tlb_entries; j++) { |
nr_of_tlb_entries; j++) { |
563 |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == |
564 |
MMU3K) |
MMU3K) |
565 |
printf("%3i: hi=0x%08x lo=0x%08x\n", j, |
printf("%3i: hi=0x%08"PRIx32" lo=0x%08" |
566 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
PRIx32"\n", j, |
567 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); |
(uint32_t) cop0->tlbs[j].hi, |
568 |
|
(uint32_t) cop0->tlbs[j].lo0); |
569 |
else if (m->cpus[i]->is_32bit) |
else if (m->cpus[i]->is_32bit) |
570 |
printf("%3i: hi=0x%08x mask=0x%08x " |
printf("%3i: hi=0x%08"PRIx32" mask=0x" |
571 |
"lo0=0x%08x lo1=0x%08x\n", j, |
"%08"PRIx32" lo0=0x%08"PRIx32 |
572 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
" lo1=0x%08"PRIx32"\n", j, |
573 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
(uint32_t) cop0->tlbs[j].hi, |
574 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
(uint32_t) cop0->tlbs[j].mask, |
575 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
(uint32_t) cop0->tlbs[j].lo0, |
576 |
|
(uint32_t) cop0->tlbs[j].lo1); |
577 |
else |
else |
578 |
printf("%3i: hi=0x%016"PRIx64" mask=0x%016"PRIx64" " |
printf("%3i: hi=0x%016"PRIx64" mask=" |
579 |
"lo0=0x%016"PRIx64" lo1=0x%016"PRIx64"\n", j, |
"0x%016"PRIx64" lo0=0x%016"PRIx64 |
580 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
" lo1=0x%016"PRIx64"\n", j, |
581 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
(uint64_t) cop0->tlbs[j].hi, |
582 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
(uint64_t) cop0->tlbs[j].mask, |
583 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
(uint64_t) cop0->tlbs[j].lo0, |
584 |
|
(uint64_t) cop0->tlbs[j].lo1); |
585 |
} |
} |
586 |
} |
} |
587 |
|
|
588 |
return; |
return; |
589 |
} |
} |
590 |
|
|
591 |
/* Nicely formatted output: */ |
/* Nicely formatted output: */ |
592 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
593 |
int pageshift = 12; |
int pageshift = 12; |
594 |
|
struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0]; |
595 |
|
|
596 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
597 |
continue; |
continue; |
604 |
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
605 |
case 1: |
case 1: |
606 |
case 2: printf("index=0x%x random=0x%x", |
case 2: printf("index=0x%x random=0x%x", |
607 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
(int) ((cop0->reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
|
reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
|
608 |
>> R2K3K_INDEX_SHIFT), |
>> R2K3K_INDEX_SHIFT), |
609 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
(int) ((cop0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
|
reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
|
610 |
>> R2K3K_RANDOM_SHIFT)); |
>> R2K3K_RANDOM_SHIFT)); |
611 |
break; |
break; |
612 |
default:printf("index=0x%x random=0x%x", |
default:printf("index=0x%x random=0x%x", |
613 |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
(int) (cop0->reg[COP0_INDEX] & INDEX_MASK), |
614 |
reg[COP0_INDEX] & INDEX_MASK), |
(int) (cop0->reg[COP0_RANDOM] & RANDOM_MASK)); |
615 |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
printf(" wired=0x%"PRIx64, |
616 |
reg[COP0_RANDOM] & RANDOM_MASK)); |
(uint64_t) cop0->reg[COP0_WIRED]); |
|
printf(" wired=0x%"PRIx64, (uint64_t) |
|
|
m->cpus[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); |
|
617 |
} |
} |
618 |
|
|
619 |
printf(")\n"); |
printf(")\n"); |
620 |
|
|
621 |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
622 |
nr_of_tlb_entries; j++) { |
nr_of_tlb_entries; j++) { |
623 |
uint64_t hi,lo0,lo1,mask; |
uint64_t hi = cop0->tlbs[j].hi; |
624 |
hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi; |
uint64_t lo0 = cop0->tlbs[j].lo0; |
625 |
lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0; |
uint64_t lo1 = cop0->tlbs[j].lo1; |
626 |
lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1; |
uint64_t mask = cop0->tlbs[j].mask; |
627 |
mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask; |
uint64_t psize; |
628 |
|
|
629 |
|
mask |= (1 << (pageshift+1)) - 1; |
630 |
|
/* here mask = e.g. 0x1fff for 4KB pages */ |
631 |
|
|
632 |
printf("%3i: ", j); |
printf("%3i: ", j); |
633 |
|
|
634 |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
635 |
case MMU3K: |
case MMU3K: |
636 |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
656 |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
657 |
case MMU32: |
case MMU32: |
658 |
printf("vaddr=0x%08"PRIx32" ", |
printf("vaddr=0x%08"PRIx32" ", |
659 |
(uint32_t) hi); |
(uint32_t) (hi & ~mask)); |
660 |
break; |
break; |
661 |
case MMU10K: |
default:/* R4x00, R1x000, MIPS64, etc. */ |
|
default:/* R4000 etc. */ |
|
662 |
printf("vaddr=%016"PRIx64" ", |
printf("vaddr=%016"PRIx64" ", |
663 |
(uint64_t) hi); |
(uint64_t) (hi & ~mask)); |
664 |
} |
} |
665 |
if (hi & TLB_G) |
if (hi & TLB_G) |
666 |
printf("(global): "); |
printf("(global): "); |
672 |
|
|
673 |
if (!(lo0 & ENTRYLO_V)) |
if (!(lo0 & ENTRYLO_V)) |
674 |
printf(" p0=(invalid) "); |
printf(" p0=(invalid) "); |
675 |
else |
else { |
676 |
printf(" p0=0x%09"PRIx64" ", (uint64_t) |
uint64_t paddr = lo0 & ENTRYLO_PFN_MASK; |
677 |
(((lo0&ENTRYLO_PFN_MASK) >> |
paddr >>= ENTRYLO_PFN_SHIFT; |
678 |
ENTRYLO_PFN_SHIFT) << pageshift)); |
paddr <<= pageshift; |
679 |
|
paddr &= ~(mask >> 1); |
680 |
|
printf(" p0=0x%09"PRIx64" ", |
681 |
|
(uint64_t) paddr); |
682 |
|
} |
683 |
printf(lo0 & ENTRYLO_D? "D" : " "); |
printf(lo0 & ENTRYLO_D? "D" : " "); |
684 |
|
|
685 |
if (!(lo1 & ENTRYLO_V)) |
if (!(lo1 & ENTRYLO_V)) |
686 |
printf(" p1=(invalid) "); |
printf(" p1=(invalid) "); |
687 |
else |
else { |
688 |
printf(" p1=0x%09"PRIx64" ", (uint64_t) |
uint64_t paddr = lo1 & ENTRYLO_PFN_MASK; |
689 |
(((lo1&ENTRYLO_PFN_MASK) >> |
paddr >>= ENTRYLO_PFN_SHIFT; |
690 |
ENTRYLO_PFN_SHIFT) << pageshift)); |
paddr <<= pageshift; |
691 |
printf(lo1 & ENTRYLO_D? "D" : " "); |
paddr &= ~(mask >> 1); |
692 |
mask |= (1 << (pageshift+1)) - 1; |
printf(" p1=0x%09"PRIx64" ", |
693 |
switch (mask) { |
(uint64_t) paddr); |
|
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); |
|
694 |
} |
} |
695 |
|
printf(lo1 & ENTRYLO_D? "D" : " "); |
696 |
|
|
697 |
|
/* convert e.g. 0x1fff to 4096 */ |
698 |
|
psize = (mask + 1) >> 1; |
699 |
|
|
700 |
|
if (psize >= 1024 && psize <= 256*1024) |
701 |
|
printf(" (%iKB)", (int) (psize >> 10)); |
702 |
|
else if (psize >= 1024*1024 && psize <= |
703 |
|
64*1024*1024) |
704 |
|
printf(" (%iMB)", (int) (psize >> 20)); |
705 |
|
else |
706 |
|
printf(" (?)"); |
707 |
|
|
708 |
printf("\n"); |
printf("\n"); |
709 |
} |
} |
710 |
} |
} |
1306 |
if (cache_op==2) debug("index store tag"), showtag=1; |
if (cache_op==2) debug("index store tag"), showtag=1; |
1307 |
if (cache_op==3) debug("create dirty exclusive"); |
if (cache_op==3) debug("create dirty exclusive"); |
1308 |
if (cache_op==4) debug("hit invalidate"); |
if (cache_op==4) debug("hit invalidate"); |
1309 |
if (cache_op==5) debug("fill OR hit writeback invalidate"); |
if (cache_op==5) debug("fill OR hit writeback invalidate"); |
1310 |
if (cache_op==6) debug("hit writeback"); |
if (cache_op==6) debug("hit writeback"); |
1311 |
if (cache_op==7) debug("hit set virtual"); |
if (cache_op==7) debug("hit set virtual"); |
1312 |
if (running) |
if (running) |
1587 |
" "); |
" "); |
1588 |
else |
else |
1589 |
debug(" %3s=%016"PRIx64"%016"PRIx64, |
debug(" %3s=%016"PRIx64"%016"PRIx64, |
1590 |
regname(cpu->machine, r), |
regname(cpu->machine, r), (uint64_t) |
1591 |
(uint64_t)cpu->cd.mips.gpr_quadhi[r], |
cpu->cd.mips.gpr_quadhi[r], |
1592 |
(uint64_t)cpu->cd.mips.gpr[r]); |
(uint64_t)cpu->cd.mips.gpr[r]); |
1593 |
if ((i & 1) == 1) |
if ((i & 1) == 1) |
1594 |
debug("\n"); |
debug("\n"); |
1652 |
debug(" c%i,%02i", coprocnr, i); |
debug(" c%i,%02i", coprocnr, i); |
1653 |
|
|
1654 |
if (bits32) |
if (bits32) |
1655 |
debug("=%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); |
debug("=%08x", (int)cpu->cd.mips. |
1656 |
|
coproc[coprocnr]->reg[i]); |
1657 |
else { |
else { |
1658 |
if (coprocnr == 0 && (i == COP0_COUNT |
if (coprocnr == 0 && (i == COP0_COUNT |
1659 |
|| i == COP0_COMPARE || i == COP0_INDEX |
|| i == COP0_COMPARE || i == COP0_INDEX |
1660 |
|| i == COP0_RANDOM || i == COP0_WIRED)) |
|| i == COP0_RANDOM || i == COP0_WIRED)) |
1661 |
debug(" = 0x%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); |
debug(" = 0x%08x", |
1662 |
|
(int) cpu->cd.mips.coproc[ |
1663 |
|
coprocnr]->reg[i]); |
1664 |
else |
else |
1665 |
debug(" = 0x%016"PRIx64, (uint64_t) |
debug(" = 0x%016"PRIx64, (uint64_t) |
1666 |
cpu->cd.mips.coproc[coprocnr]->reg[i]); |
cpu->cd.mips.coproc[ |
1667 |
|
coprocnr]->reg[i]); |
1668 |
} |
} |
1669 |
|
|
1670 |
if ((i & nm1) == nm1) |
if ((i & nm1) == nm1) |
1680 |
debug("cpu%i: ", cpu->cpu_id); |
debug("cpu%i: ", cpu->cpu_id); |
1681 |
debug("config_select1 = 0x"); |
debug("config_select1 = 0x"); |
1682 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
1683 |
debug("%08"PRIx32, (uint32_t)cpu->cd.mips.cop0_config_select1); |
debug("%08"PRIx32, |
1684 |
|
(uint32_t)cpu->cd.mips.cop0_config_select1); |
1685 |
else |
else |
1686 |
debug("%016"PRIx64, (uint64_t)cpu->cd.mips.cop0_config_select1); |
debug("%016"PRIx64, |
1687 |
|
(uint64_t)cpu->cd.mips.cop0_config_select1); |
1688 |
debug("\n"); |
debug("\n"); |
1689 |
} |
} |
1690 |
|
|
1718 |
} |
} |
1719 |
|
|
1720 |
|
|
|
static void add_response_word(struct cpu *cpu, char *r, uint64_t value, |
|
|
size_t maxlen, int len) |
|
|
{ |
|
|
char *format = (len == 4)? "%08"PRIx64 : "%016"PRIx64; |
|
|
if (len == 4) |
|
|
value &= 0xffffffffULL; |
|
|
if (cpu->byte_order == EMUL_LITTLE_ENDIAN) { |
|
|
if (len == 4) { |
|
|
value = ((value & 0xff) << 24) + |
|
|
((value & 0xff00) << 8) + |
|
|
((value & 0xff0000) >> 8) + |
|
|
((value & 0xff000000) >> 24); |
|
|
} else { |
|
|
value = ((value & 0xff) << 56) + |
|
|
((value & 0xff00) << 40) + |
|
|
((value & 0xff0000) << 24) + |
|
|
((value & 0xff000000ULL) << 8) + |
|
|
((value & 0xff00000000ULL) >> 8) + |
|
|
((value & 0xff0000000000ULL) >> 24) + |
|
|
((value & 0xff000000000000ULL) >> 40) + |
|
|
((value & 0xff00000000000000ULL) >> 56); |
|
|
} |
|
|
} |
|
|
snprintf(r + strlen(r), maxlen - strlen(r), format, (uint64_t)value); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* mips_cpu_gdb_stub(): |
|
|
* |
|
|
* Execute a "remote GDB" command. Returns 1 on success, 0 on error. |
|
|
*/ |
|
|
char *mips_cpu_gdb_stub(struct cpu *cpu, char *cmd) |
|
|
{ |
|
|
if (strcmp(cmd, "g") == 0) { |
|
|
/* 76 registers: gprs, sr, lo, hi, badvaddr, cause, pc, |
|
|
fprs, fsr, fir, fp. */ |
|
|
int i; |
|
|
char *r; |
|
|
size_t wlen = cpu->is_32bit? |
|
|
sizeof(uint32_t) : sizeof(uint64_t); |
|
|
size_t len = 1 + 76 * wlen; |
|
|
r = malloc(len); |
|
|
if (r == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
|
r[0] = '\0'; |
|
|
for (i=0; i<32; i++) |
|
|
add_response_word(cpu, r, cpu->cd.mips.gpr[i], |
|
|
len, wlen); |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[0]->reg[COP0_STATUS], len, wlen); |
|
|
add_response_word(cpu, r, cpu->cd.mips.lo, len, wlen); |
|
|
add_response_word(cpu, r, cpu->cd.mips.hi, len, wlen); |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[0]->reg[COP0_BADVADDR], len, wlen); |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE], len, wlen); |
|
|
add_response_word(cpu, r, cpu->pc, len, wlen); |
|
|
for (i=0; i<32; i++) |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[1]->reg[i], len, wlen); |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[1]->reg[31] /* fcsr */, len, wlen); |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.coproc[1]->reg[0] /* fcir */, len, wlen); |
|
|
|
|
|
/* TODO: fp = gpr 30? */ |
|
|
add_response_word(cpu, r, cpu->cd.mips.gpr[30], len, wlen); |
|
|
|
|
|
return r; |
|
|
} |
|
|
|
|
|
if (cmd[0] == 'p') { |
|
|
int regnr = strtol(cmd + 1, NULL, 16); |
|
|
size_t wlen = cpu->is_32bit? sizeof(uint32_t):sizeof(uint64_t); |
|
|
size_t len = 2 * wlen + 1; |
|
|
char *r = malloc(len); |
|
|
r[0] = '\0'; |
|
|
if (regnr >= 0 && regnr <= 31) { |
|
|
add_response_word(cpu, r, |
|
|
cpu->cd.mips.gpr[regnr], len, wlen); |
|
|
} else if (regnr == 0x20) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_STATUS], len, wlen); |
|
|
} else if (regnr == 0x21) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.lo, len, wlen); |
|
|
} else if (regnr == 0x22) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.hi, len, wlen); |
|
|
} else if (regnr == 0x23) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_BADVADDR], len, wlen); |
|
|
} else if (regnr == 0x24) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[0]-> |
|
|
reg[COP0_CAUSE], len, wlen); |
|
|
} else if (regnr == 0x25) { |
|
|
add_response_word(cpu, r, cpu->pc, len, wlen); |
|
|
} else if (regnr >= 0x26 && regnr <= 0x45 && |
|
|
cpu->cd.mips.coproc[1] != NULL) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> |
|
|
reg[regnr - 0x26], len, wlen); |
|
|
} else if (regnr == 0x46) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> |
|
|
fcr[MIPS_FPU_FCSR], len, wlen); |
|
|
} else if (regnr == 0x47) { |
|
|
add_response_word(cpu, r, cpu->cd.mips.coproc[1]-> |
|
|
fcr[MIPS_FPU_FCIR], len, wlen); |
|
|
} else { |
|
|
/* Unimplemented: */ |
|
|
add_response_word(cpu, r, 0xcc000 + regnr, len, wlen); |
|
|
} |
|
|
return r; |
|
|
} |
|
|
|
|
|
fatal("mips_cpu_gdb_stub(): cmd='%s' TODO\n", cmd); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
1721 |
/* |
/* |
1722 |
* mips_cpu_interrupt(): |
* mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert(): |
|
* |
|
|
* Cause an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
|
|
* interrupt. 0 and 1 are ignored (software interrupts). |
|
1723 |
* |
* |
1724 |
* If irq_nr is >= 8, then this function calls md_interrupt(). |
* Assert or deassert a MIPS CPU interrupt by masking in or out bits |
1725 |
|
* in the CAUSE register of coprocessor 0. |
1726 |
*/ |
*/ |
1727 |
int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) |
void mips_cpu_interrupt_assert(struct interrupt *interrupt) |
1728 |
{ |
{ |
1729 |
if (irq_nr >= 8) { |
struct cpu *cpu = interrupt->extra; |
1730 |
if (cpu->machine->md_interrupt != NULL) |
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line; |
|
cpu->machine->md_interrupt(cpu->machine, |
|
|
cpu, irq_nr, 1); |
|
|
else |
|
|
fatal("mips_cpu_interrupt(): irq_nr = %i, " |
|
|
"but md_interrupt = NULL ?\n", irq_nr); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (irq_nr < 2) |
|
|
return 0; |
|
|
|
|
|
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= |
|
|
((1 << irq_nr) << STATUS_IM_SHIFT); |
|
|
|
|
|
return 1; |
|
1731 |
} |
} |
1732 |
|
void mips_cpu_interrupt_deassert(struct interrupt *interrupt) |
|
|
|
|
/* |
|
|
* mips_cpu_interrupt_ack(): |
|
|
* |
|
|
* Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
|
|
* interrupt. Interrupts 0..1 are ignored (software interrupts). |
|
|
* |
|
|
* If irq_nr is >= 8, then it is machine dependent, and md_interrupt() is |
|
|
* called. |
|
|
*/ |
|
|
int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) |
|
1733 |
{ |
{ |
1734 |
if (irq_nr >= 8) { |
struct cpu *cpu = interrupt->extra; |
1735 |
if (cpu->machine->md_interrupt != NULL) |
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~interrupt->line; |
|
cpu->machine->md_interrupt(cpu->machine, cpu, |
|
|
irq_nr, 0); |
|
|
else |
|
|
fatal("mips_cpu_interrupt_ack(): irq_nr = %i, " |
|
|
"but md_interrupt = NULL ?\n", irq_nr); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (irq_nr < 2) |
|
|
return 0; |
|
|
|
|
|
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= |
|
|
~((1 << irq_nr) << STATUS_IM_SHIFT); |
|
|
|
|
|
return 1; |
|
1736 |
} |
} |
1737 |
|
|
1738 |
|
|
1784 |
switch (exccode) { |
switch (exccode) { |
1785 |
|
|
1786 |
case EXCEPTION_INT: |
case EXCEPTION_INT: |
1787 |
debug(" cause_im=0x%02x", (int)((reg[COP0_CAUSE] & CAUSE_IP_MASK) >> CAUSE_IP_SHIFT)); |
debug(" cause_im=0x%02x", (int) |
1788 |
|
((reg[COP0_CAUSE] & CAUSE_IP_MASK) |
1789 |
|
>> CAUSE_IP_SHIFT)); |
1790 |
break; |
break; |
1791 |
|
|
1792 |
case EXCEPTION_SYS: |
case EXCEPTION_SYS: |
1876 |
|
|
1877 |
if (exc_model == EXC3K) { |
if (exc_model == EXC3K) { |
1878 |
reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; |
reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; |
1879 |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << R2K3K_CONTEXT_BADVPN_SHIFT) & R2K3K_CONTEXT_BADVPN_MASK); |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << |
1880 |
|
R2K3K_CONTEXT_BADVPN_SHIFT) & |
1881 |
|
R2K3K_CONTEXT_BADVPN_MASK); |
1882 |
|
|
1883 |
reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
1884 |
| (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT); |
| (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT); |
1888 |
reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI]; |
reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI]; |
1889 |
} else { |
} else { |
1890 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { |
1891 |
reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK_R4100; |
reg[COP0_CONTEXT] &= |
1892 |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK_R4100); |
~CONTEXT_BADVPN2_MASK_R4100; |
1893 |
|
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << |
1894 |
|
CONTEXT_BADVPN2_SHIFT) & |
1895 |
|
CONTEXT_BADVPN2_MASK_R4100); |
1896 |
|
|
1897 |
/* TODO: fix these */ |
/* TODO: fix these */ |
1898 |
reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; |
reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; |