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.63 2006/08/12 11:43:13 debug Exp $ |
* $Id: cpu_mips.c,v 1.84 2007/06/28 13:36:46 debug Exp $ |
29 |
* |
* |
30 |
* MIPS core CPU emulation. |
* MIPS core CPU emulation. |
31 |
*/ |
*/ |
50 |
#include "memory.h" |
#include "memory.h" |
51 |
#include "mips_cpu_types.h" |
#include "mips_cpu_types.h" |
52 |
#include "opcodes_mips.h" |
#include "opcodes_mips.h" |
53 |
|
#include "settings.h" |
54 |
#include "symbol.h" |
#include "symbol.h" |
55 |
|
|
56 |
|
|
|
extern volatile int single_step; |
|
|
|
|
57 |
static char *exception_names[] = EXCEPTION_NAMES; |
static char *exception_names[] = EXCEPTION_NAMES; |
58 |
|
|
59 |
static char *hi6_names[] = HI6_NAMES; |
static char *hi6_names[] = HI6_NAMES; |
60 |
static char *regimm_names[] = REGIMM_NAMES; |
static char *regimm_names[] = REGIMM_NAMES; |
61 |
static char *special_names[] = SPECIAL_NAMES; |
static char *special_names[] = SPECIAL_NAMES; |
62 |
|
static char *special_rot_names[] = SPECIAL_ROT_NAMES; |
63 |
static char *special2_names[] = SPECIAL2_NAMES; |
static char *special2_names[] = SPECIAL2_NAMES; |
64 |
static char *mmi_names[] = MMI_NAMES; |
static char *mmi_names[] = MMI_NAMES; |
65 |
static char *mmi0_names[] = MMI0_NAMES; |
static char *mmi0_names[] = MMI0_NAMES; |
81 |
|
|
82 |
|
|
83 |
/* |
/* |
|
* regname(): |
|
|
* |
|
|
* Convert a register number into either 'r0', 'r31' etc, or a symbolic |
|
|
* name, depending on machine->show_symbolic_register_names. |
|
|
* |
|
|
* NOTE: _NOT_ reentrant. |
|
|
*/ |
|
|
static char *regname(struct machine *machine, int r) |
|
|
{ |
|
|
static char ch[4]; |
|
|
ch[3] = ch[2] = '\0'; |
|
|
|
|
|
if (r<0 || r>=32) |
|
|
strlcpy(ch, "xx", sizeof(ch)); |
|
|
else if (machine->show_symbolic_register_names) |
|
|
strlcpy(ch, regnames[r], sizeof(ch)); |
|
|
else |
|
|
snprintf(ch, sizeof(ch), "r%i", r); |
|
|
|
|
|
return ch; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
84 |
* mips_cpu_new(): |
* mips_cpu_new(): |
85 |
* |
* |
86 |
* Create a new MIPS cpu object. |
* Create a new MIPS cpu object. |
156 |
x = DEFAULT_PCACHE_SIZE; |
x = DEFAULT_PCACHE_SIZE; |
157 |
if (cpu->cd.mips.cpu_type.pdcache) |
if (cpu->cd.mips.cpu_type.pdcache) |
158 |
x = cpu->cd.mips.cpu_type.pdcache; |
x = cpu->cd.mips.cpu_type.pdcache; |
159 |
if (machine->cache_pdcache == 0) |
if (cpu->cd.mips.cache_pdcache == 0) |
160 |
machine->cache_pdcache = x; |
cpu->cd.mips.cache_pdcache = x; |
161 |
|
|
162 |
x = DEFAULT_PCACHE_SIZE; |
x = DEFAULT_PCACHE_SIZE; |
163 |
if (cpu->cd.mips.cpu_type.picache) |
if (cpu->cd.mips.cpu_type.picache) |
164 |
x = cpu->cd.mips.cpu_type.picache; |
x = cpu->cd.mips.cpu_type.picache; |
165 |
if (machine->cache_picache == 0) |
if (cpu->cd.mips.cache_picache == 0) |
166 |
machine->cache_picache = x; |
cpu->cd.mips.cache_picache = x; |
167 |
|
|
168 |
if (machine->cache_secondary == 0) |
if (cpu->cd.mips.cache_secondary == 0) |
169 |
machine->cache_secondary = cpu->cd.mips.cpu_type.scache; |
cpu->cd.mips.cache_secondary = cpu->cd.mips.cpu_type.scache; |
170 |
|
|
171 |
linesize = DEFAULT_PCACHE_LINESIZE; |
linesize = DEFAULT_PCACHE_LINESIZE; |
172 |
if (cpu->cd.mips.cpu_type.pdlinesize) |
if (cpu->cd.mips.cpu_type.pdlinesize) |
173 |
linesize = cpu->cd.mips.cpu_type.pdlinesize; |
linesize = cpu->cd.mips.cpu_type.pdlinesize; |
174 |
if (machine->cache_pdcache_linesize == 0) |
if (cpu->cd.mips.cache_pdcache_linesize == 0) |
175 |
machine->cache_pdcache_linesize = linesize; |
cpu->cd.mips.cache_pdcache_linesize = linesize; |
176 |
|
|
177 |
linesize = DEFAULT_PCACHE_LINESIZE; |
linesize = DEFAULT_PCACHE_LINESIZE; |
178 |
if (cpu->cd.mips.cpu_type.pilinesize) |
if (cpu->cd.mips.cpu_type.pilinesize) |
179 |
linesize = cpu->cd.mips.cpu_type.pilinesize; |
linesize = cpu->cd.mips.cpu_type.pilinesize; |
180 |
if (machine->cache_picache_linesize == 0) |
if (cpu->cd.mips.cache_picache_linesize == 0) |
181 |
machine->cache_picache_linesize = linesize; |
cpu->cd.mips.cache_picache_linesize = linesize; |
182 |
|
|
183 |
linesize = 0; |
linesize = 0; |
184 |
if (cpu->cd.mips.cpu_type.slinesize) |
if (cpu->cd.mips.cpu_type.slinesize) |
185 |
linesize = cpu->cd.mips.cpu_type.slinesize; |
linesize = cpu->cd.mips.cpu_type.slinesize; |
186 |
if (machine->cache_secondary_linesize == 0) |
if (cpu->cd.mips.cache_secondary_linesize == 0) |
187 |
machine->cache_secondary_linesize = linesize; |
cpu->cd.mips.cache_secondary_linesize = linesize; |
188 |
|
|
189 |
|
|
190 |
/* |
/* |
193 |
for (i=CACHE_DATA; i<=CACHE_INSTRUCTION; i++) { |
for (i=CACHE_DATA; i<=CACHE_INSTRUCTION; i++) { |
194 |
switch (i) { |
switch (i) { |
195 |
case CACHE_DATA: |
case CACHE_DATA: |
196 |
x = 1 << machine->cache_pdcache; |
x = 1 << cpu->cd.mips.cache_pdcache; |
197 |
linesize = 1 << machine->cache_pdcache_linesize; |
linesize = 1 << cpu->cd.mips.cache_pdcache_linesize; |
198 |
break; |
break; |
199 |
case CACHE_INSTRUCTION: |
case CACHE_INSTRUCTION: |
200 |
x = 1 << machine->cache_picache; |
x = 1 << cpu->cd.mips.cache_picache; |
201 |
linesize = 1 << machine->cache_picache_linesize; |
linesize = 1 << cpu->cd.mips.cache_picache_linesize; |
202 |
break; |
break; |
203 |
} |
} |
204 |
|
|
212 |
size_per_cache_line = sizeof(struct r3000_cache_line); |
size_per_cache_line = sizeof(struct r3000_cache_line); |
213 |
break; |
break; |
214 |
default: |
default: |
215 |
size_per_cache_line = sizeof(struct r4000_cache_line); |
size_per_cache_line = 32; /* TODO */ |
216 |
} |
} |
217 |
|
|
218 |
cpu->cd.mips.cache_mask[i] = cpu->cd.mips.cache_size[i] - 1; |
cpu->cd.mips.cache_mask[i] = cpu->cd.mips.cache_size[i] - 1; |
|
cpu->cd.mips.cache_miss_penalty[i] = 10; /* TODO ? */ |
|
219 |
|
|
220 |
cpu->cd.mips.cache[i] = malloc(cpu->cd.mips.cache_size[i]); |
CHECK_ALLOCATION(cpu->cd.mips.cache[i] = |
221 |
if (cpu->cd.mips.cache[i] == NULL) { |
malloc(cpu->cd.mips.cache_size[i])); |
|
fprintf(stderr, "out of memory\n"); |
|
|
} |
|
222 |
|
|
223 |
n_cache_lines = cpu->cd.mips.cache_size[i] / |
n_cache_lines = cpu->cd.mips.cache_size[i] / |
224 |
cpu->cd.mips.cache_linesize[i]; |
cpu->cd.mips.cache_linesize[i]; |
225 |
tags_size = n_cache_lines * size_per_cache_line; |
tags_size = n_cache_lines * size_per_cache_line; |
226 |
|
|
227 |
cpu->cd.mips.cache_tags[i] = malloc(tags_size); |
CHECK_ALLOCATION(cpu->cd.mips.cache_tags[i] = |
228 |
if (cpu->cd.mips.cache_tags[i] == NULL) { |
malloc(tags_size)); |
|
fprintf(stderr, "out of memory\n"); |
|
|
} |
|
229 |
|
|
230 |
/* Initialize the cache tags: */ |
/* Initialize the cache tags: */ |
231 |
switch (cpu->cd.mips.cpu_type.rev) { |
switch (cpu->cd.mips.cpu_type.rev) { |
251 |
* Secondary cache: |
* Secondary cache: |
252 |
*/ |
*/ |
253 |
secondary_cache_size = 0; |
secondary_cache_size = 0; |
254 |
if (machine->cache_secondary) |
if (cpu->cd.mips.cache_secondary) |
255 |
secondary_cache_size = 1 << machine->cache_secondary; |
secondary_cache_size = 1 << cpu->cd.mips.cache_secondary; |
256 |
/* TODO: linesize... */ |
/* TODO: linesize... */ |
257 |
|
|
258 |
if (cpu_id == 0) { |
if (cpu_id == 0) { |
273 |
debug(")"); |
debug(")"); |
274 |
} |
} |
275 |
|
|
276 |
|
/* Register the CPU's interrupts: */ |
277 |
|
for (i=2; i<8; i++) { |
278 |
|
struct interrupt template; |
279 |
|
char name[50]; |
280 |
|
snprintf(name, sizeof(name), "%s.%i", cpu->path, i); |
281 |
|
memset(&template, 0, sizeof(template)); |
282 |
|
template.line = 1 << (STATUS_IM_SHIFT + i); |
283 |
|
template.name = name; |
284 |
|
template.extra = cpu; |
285 |
|
template.interrupt_assert = mips_cpu_interrupt_assert; |
286 |
|
template.interrupt_deassert = mips_cpu_interrupt_deassert; |
287 |
|
interrupt_handler_register(&template); |
288 |
|
|
289 |
|
if (i == 7) |
290 |
|
INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare); |
291 |
|
} |
292 |
|
|
293 |
/* System coprocessor (0), and FPU (1): */ |
/* System coprocessor (0), and FPU (1): */ |
294 |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0); |
295 |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1); |
311 |
cpu->translate_v2p = translate_v2p_generic; |
cpu->translate_v2p = translate_v2p_generic; |
312 |
} |
} |
313 |
|
|
314 |
|
if (cpu->machine->prom_emulation) { |
315 |
|
/* |
316 |
|
* Default behaviour of jumping to 0xbfc00000 should be |
317 |
|
* a reboot, unless machine-specific initialization code |
318 |
|
* overrides this. |
319 |
|
* |
320 |
|
* Note: Specifically big-endian machines should override |
321 |
|
* this, since the default MIPS CPU is little-endian! |
322 |
|
*/ |
323 |
|
store_32bit_word(cpu, 0xffffffff9fc00000ULL, 0x00c0de0d); |
324 |
|
} |
325 |
|
|
326 |
|
/* Add all register names to the settings: */ |
327 |
|
CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc); |
328 |
|
CPU_SETTINGS_ADD_REGISTER64("hi", cpu->cd.mips.hi); |
329 |
|
CPU_SETTINGS_ADD_REGISTER64("lo", cpu->cd.mips.lo); |
330 |
|
for (i=0; i<N_MIPS_GPRS; i++) |
331 |
|
CPU_SETTINGS_ADD_REGISTER64(regnames[i], cpu->cd.mips.gpr[i]); |
332 |
|
/* TODO: Write via special handler function! */ |
333 |
|
for (i=0; i<N_MIPS_COPROC_REGS; i++) |
334 |
|
CPU_SETTINGS_ADD_REGISTER64(cop0_names[i], |
335 |
|
cpu->cd.mips.coproc[0]->reg[i]); |
336 |
|
|
337 |
return 1; |
return 1; |
338 |
} |
} |
339 |
|
|
502 |
/* Raw output: */ |
/* Raw output: */ |
503 |
if (rawflag) { |
if (rawflag) { |
504 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
505 |
|
struct mips_coproc *cop0 = |
506 |
|
m->cpus[i]->cd.mips.coproc[0]; |
507 |
|
|
508 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
509 |
continue; |
continue; |
510 |
|
|
512 |
printf("cpu%i: (", i); |
printf("cpu%i: (", i); |
513 |
|
|
514 |
if (m->cpus[i]->is_32bit) |
if (m->cpus[i]->is_32bit) |
515 |
printf("index=0x%08x random=0x%08x", (int)m-> |
printf("index=0x%08x random=0x%08x", |
516 |
cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX], |
(int) cop0->reg[COP0_INDEX], |
517 |
(int)m->cpus[i]->cd.mips.coproc[0]->reg |
(int) cop0->reg[COP0_RANDOM]); |
|
[COP0_RANDOM]); |
|
518 |
else |
else |
519 |
printf("index=0x%016"PRIx64 |
printf("index=0x%016"PRIx64 |
520 |
" random=0x%016"PRIx64, |
" random=0x%016"PRIx64, |
521 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]-> |
(uint64_t) cop0->reg[COP0_INDEX], |
522 |
reg[COP0_INDEX], (uint64_t)m->cpus[i]-> |
(uint64_t) cop0->reg[COP0_RANDOM]); |
|
cd.mips.coproc[0]->reg[COP0_RANDOM]); |
|
523 |
|
|
524 |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3) |
525 |
printf(" wired=0x%"PRIx64, (uint64_t) m->cpus |
printf(" wired=0x%"PRIx64, |
526 |
[i]->cd.mips.coproc[0]->reg[COP0_WIRED]); |
(uint64_t) cop0->reg[COP0_WIRED]); |
527 |
|
|
528 |
printf(")\n"); |
printf(")\n"); |
529 |
|
|
531 |
nr_of_tlb_entries; j++) { |
nr_of_tlb_entries; j++) { |
532 |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == |
if (m->cpus[i]->cd.mips.cpu_type.mmu_model == |
533 |
MMU3K) |
MMU3K) |
534 |
printf("%3i: hi=0x%08x lo=0x%08x\n", j, |
printf("%3i: hi=0x%08"PRIx32" lo=0x%08" |
535 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
PRIx32"\n", j, |
536 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0); |
(uint32_t) cop0->tlbs[j].hi, |
537 |
|
(uint32_t) cop0->tlbs[j].lo0); |
538 |
else if (m->cpus[i]->is_32bit) |
else if (m->cpus[i]->is_32bit) |
539 |
printf("%3i: hi=0x%08x mask=0x%08x " |
printf("%3i: hi=0x%08"PRIx32" mask=0x" |
540 |
"lo0=0x%08x lo1=0x%08x\n", j, |
"%08"PRIx32" lo0=0x%08"PRIx32 |
541 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
" lo1=0x%08"PRIx32"\n", j, |
542 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
(uint32_t) cop0->tlbs[j].hi, |
543 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
(uint32_t) cop0->tlbs[j].mask, |
544 |
(int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
(uint32_t) cop0->tlbs[j].lo0, |
545 |
|
(uint32_t) cop0->tlbs[j].lo1); |
546 |
else |
else |
547 |
printf("%3i: hi=0x%016"PRIx64" mask=0x%016"PRIx64" " |
printf("%3i: hi=0x%016"PRIx64" mask=" |
548 |
"lo0=0x%016"PRIx64" lo1=0x%016"PRIx64"\n", j, |
"0x%016"PRIx64" lo0=0x%016"PRIx64 |
549 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi, |
" lo1=0x%016"PRIx64"\n", j, |
550 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask, |
(uint64_t) cop0->tlbs[j].hi, |
551 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0, |
(uint64_t) cop0->tlbs[j].mask, |
552 |
(uint64_t)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1); |
(uint64_t) cop0->tlbs[j].lo0, |
553 |
|
(uint64_t) cop0->tlbs[j].lo1); |
554 |
} |
} |
555 |
} |
} |
556 |
|
|
557 |
return; |
return; |
558 |
} |
} |
559 |
|
|
560 |
/* Nicely formatted output: */ |
/* Nicely formatted output: */ |
561 |
for (i=0; i<m->ncpus; i++) { |
for (i=0; i<m->ncpus; i++) { |
562 |
int pageshift = 12; |
int pageshift = 12; |
563 |
|
struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0]; |
564 |
|
|
565 |
if (x >= 0 && i != x) |
if (x >= 0 && i != x) |
566 |
continue; |
continue; |
573 |
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
switch (m->cpus[i]->cd.mips.cpu_type.isa_level) { |
574 |
case 1: |
case 1: |
575 |
case 2: printf("index=0x%x random=0x%x", |
case 2: printf("index=0x%x random=0x%x", |
576 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
(int) ((cop0->reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
|
reg[COP0_INDEX] & R2K3K_INDEX_MASK) |
|
577 |
>> R2K3K_INDEX_SHIFT), |
>> R2K3K_INDEX_SHIFT), |
578 |
(int) ((m->cpus[i]->cd.mips.coproc[0]-> |
(int) ((cop0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
|
reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) |
|
579 |
>> R2K3K_RANDOM_SHIFT)); |
>> R2K3K_RANDOM_SHIFT)); |
580 |
break; |
break; |
581 |
default:printf("index=0x%x random=0x%x", |
default:printf("index=0x%x random=0x%x", |
582 |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
(int) (cop0->reg[COP0_INDEX] & INDEX_MASK), |
583 |
reg[COP0_INDEX] & INDEX_MASK), |
(int) (cop0->reg[COP0_RANDOM] & RANDOM_MASK)); |
584 |
(int) (m->cpus[i]->cd.mips.coproc[0]-> |
printf(" wired=0x%"PRIx64, |
585 |
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]); |
|
586 |
} |
} |
587 |
|
|
588 |
printf(")\n"); |
printf(")\n"); |
589 |
|
|
590 |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
for (j=0; j<m->cpus[i]->cd.mips.cpu_type. |
591 |
nr_of_tlb_entries; j++) { |
nr_of_tlb_entries; j++) { |
592 |
uint64_t hi,lo0,lo1,mask; |
uint64_t hi = cop0->tlbs[j].hi; |
593 |
hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi; |
uint64_t lo0 = cop0->tlbs[j].lo0; |
594 |
lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0; |
uint64_t lo1 = cop0->tlbs[j].lo1; |
595 |
lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1; |
uint64_t mask = cop0->tlbs[j].mask; |
596 |
mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask; |
uint64_t psize; |
597 |
|
|
598 |
|
mask |= (1 << (pageshift+1)) - 1; |
599 |
|
/* here mask = e.g. 0x1fff for 4KB pages */ |
600 |
|
|
601 |
printf("%3i: ", j); |
printf("%3i: ", j); |
602 |
|
|
603 |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) { |
604 |
case MMU3K: |
case MMU3K: |
605 |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
if (!(lo0 & R2K3K_ENTRYLO_V)) { |
623 |
printf("\n"); |
printf("\n"); |
624 |
break; |
break; |
625 |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){ |
|
case MMU10K: |
|
|
printf("vaddr=0x%1x..%011"PRIx64" ", |
|
|
(int) (hi >> 60), (uint64_t) |
|
|
(hi&ENTRYHI_VPN2_MASK_R10K)); |
|
|
break; |
|
626 |
case MMU32: |
case MMU32: |
627 |
printf("vaddr=0x%08"PRIx32" ", |
printf("vaddr=0x%08"PRIx32" ", |
628 |
(uint32_t)(hi&ENTRYHI_VPN2_MASK)); |
(uint32_t) (hi & ~mask)); |
629 |
break; |
break; |
630 |
default:/* R4000 etc. */ |
default:/* R4x00, R1x000, MIPS64, etc. */ |
631 |
printf("vaddr=0x%1x..%010"PRIx64" ", |
printf("vaddr=%016"PRIx64" ", |
632 |
(int) (hi >> 60), |
(uint64_t) (hi & ~mask)); |
|
(uint64_t) (hi&ENTRYHI_VPN2_MASK)); |
|
633 |
} |
} |
634 |
if (hi & TLB_G) |
if (hi & TLB_G) |
635 |
printf("(global): "); |
printf("(global): "); |
641 |
|
|
642 |
if (!(lo0 & ENTRYLO_V)) |
if (!(lo0 & ENTRYLO_V)) |
643 |
printf(" p0=(invalid) "); |
printf(" p0=(invalid) "); |
644 |
else |
else { |
645 |
printf(" p0=0x%09"PRIx64" ", (uint64_t) |
uint64_t paddr = lo0 & ENTRYLO_PFN_MASK; |
646 |
(((lo0&ENTRYLO_PFN_MASK) >> |
paddr >>= ENTRYLO_PFN_SHIFT; |
647 |
ENTRYLO_PFN_SHIFT) << pageshift)); |
paddr <<= pageshift; |
648 |
|
paddr &= ~(mask >> 1); |
649 |
|
printf(" p0=0x%09"PRIx64" ", |
650 |
|
(uint64_t) paddr); |
651 |
|
} |
652 |
printf(lo0 & ENTRYLO_D? "D" : " "); |
printf(lo0 & ENTRYLO_D? "D" : " "); |
653 |
|
|
654 |
if (!(lo1 & ENTRYLO_V)) |
if (!(lo1 & ENTRYLO_V)) |
655 |
printf(" p1=(invalid) "); |
printf(" p1=(invalid) "); |
656 |
else |
else { |
657 |
printf(" p1=0x%09"PRIx64" ", (uint64_t) |
uint64_t paddr = lo1 & ENTRYLO_PFN_MASK; |
658 |
(((lo1&ENTRYLO_PFN_MASK) >> |
paddr >>= ENTRYLO_PFN_SHIFT; |
659 |
ENTRYLO_PFN_SHIFT) << pageshift)); |
paddr <<= pageshift; |
660 |
printf(lo1 & ENTRYLO_D? "D" : " "); |
paddr &= ~(mask >> 1); |
661 |
mask |= (1 << (pageshift+1)) - 1; |
printf(" p1=0x%09"PRIx64" ", |
662 |
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); |
|
663 |
} |
} |
664 |
printf("\n"); |
printf(lo1 & ENTRYLO_D? "D" : " "); |
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* mips_cpu_register_match(): |
|
|
*/ |
|
|
void mips_cpu_register_match(struct machine *m, char *name, |
|
|
int writeflag, uint64_t *valuep, int *match_register) |
|
|
{ |
|
|
int cpunr = 0; |
|
|
|
|
|
/* CPU number: */ |
|
665 |
|
|
666 |
/* TODO */ |
/* convert e.g. 0x1fff to 4096 */ |
667 |
|
psize = (mask + 1) >> 1; |
668 |
|
|
669 |
/* Register name: */ |
if (psize >= 1024 && psize <= 256*1024) |
670 |
if (strcasecmp(name, "pc") == 0) { |
printf(" (%iKB)", (int) (psize >> 10)); |
671 |
if (writeflag) { |
else if (psize >= 1024*1024 && psize <= |
672 |
m->cpus[cpunr]->pc = *valuep; |
64*1024*1024) |
673 |
if (m->cpus[cpunr]->delay_slot) { |
printf(" (%iMB)", (int) (psize >> 20)); |
|
printf("NOTE: Clearing the delay slot" |
|
|
" flag! (It was set before.)\n"); |
|
|
m->cpus[cpunr]->delay_slot = 0; |
|
|
} |
|
|
if (m->cpus[cpunr]->cd.mips.nullify_next) { |
|
|
printf("NOTE: Clearing the nullify-ne" |
|
|
"xt flag! (It was set before.)\n"); |
|
|
m->cpus[cpunr]->cd.mips.nullify_next = 0; |
|
|
} |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->pc; |
|
|
*match_register = 1; |
|
|
} else if (strcasecmp(name, "hi") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.mips.hi = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.hi; |
|
|
*match_register = 1; |
|
|
} else if (strcasecmp(name, "lo") == 0) { |
|
|
if (writeflag) |
|
|
m->cpus[cpunr]->cd.mips.lo = *valuep; |
|
|
else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.lo; |
|
|
*match_register = 1; |
|
|
} else if (name[0] == 'r' && isdigit((int)name[1])) { |
|
|
int nr = atoi(name + 1); |
|
|
if (nr >= 0 && nr < N_MIPS_GPRS) { |
|
|
if (writeflag) { |
|
|
if (nr != 0) |
|
|
m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep; |
|
674 |
else |
else |
675 |
printf("WARNING: Attempt to modify r0.\n"); |
printf(" (?)"); |
|
} else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; |
|
|
*match_register = 1; |
|
|
} |
|
|
} else { |
|
|
/* Check for a symbolic name such as "t6" or "at": */ |
|
|
int nr; |
|
|
for (nr=0; nr<N_MIPS_GPRS; nr++) |
|
|
if (strcmp(name, regnames[nr]) == 0) { |
|
|
if (writeflag) { |
|
|
if (nr != 0) |
|
|
m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep; |
|
|
else |
|
|
printf("WARNING: Attempt to modify r0.\n"); |
|
|
} else |
|
|
*valuep = m->cpus[cpunr]->cd.mips.gpr[nr]; |
|
|
*match_register = 1; |
|
|
} |
|
|
} |
|
676 |
|
|
677 |
if (!(*match_register)) { |
printf("\n"); |
|
/* Check for a symbolic coproc0 name: */ |
|
|
int nr; |
|
|
for (nr=0; nr<32; nr++) |
|
|
if (strcmp(name, cop0_names[nr]) == 0) { |
|
|
if (writeflag) { |
|
|
coproc_register_write(m->cpus[cpunr], |
|
|
m->cpus[cpunr]->cd.mips.coproc[0], nr, |
|
|
valuep, 1, 0); |
|
|
} else { |
|
|
/* TODO: Use coproc_register_read instead? */ |
|
|
*valuep = m->cpus[cpunr]->cd.mips.coproc[0]->reg[nr]; |
|
|
} |
|
|
*match_register = 1; |
|
678 |
} |
} |
679 |
} |
} |
|
|
|
|
/* TODO: Coprocessor 1,2,3 registers. */ |
|
|
|
|
|
/* Only return lowest 32 bits when doing 32-bit emulation: */ |
|
|
if (!writeflag && m->cpus[cpunr]->is_32bit) |
|
|
*valuep = (uint32_t) (*valuep); |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* cpu_flags(): |
|
|
* |
|
|
* Returns a pointer to a string containing "(d)" "(j)" "(dj)" or "", |
|
|
* depending on the cpu's current delay_slot and last_was_jumptoself |
|
|
* flags. |
|
|
*/ |
|
|
static const char *cpu_flags(struct cpu *cpu) |
|
|
{ |
|
|
if (cpu->delay_slot) { |
|
|
if (cpu->cd.mips.last_was_jumptoself) |
|
|
return " (dj)"; |
|
|
else |
|
|
return " (d)"; |
|
|
} else { |
|
|
if (cpu->cd.mips.last_was_jumptoself) |
|
|
return " (j)"; |
|
|
else |
|
|
return ""; |
|
680 |
} |
} |
681 |
} |
} |
682 |
|
|
698 |
int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, |
int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr, |
699 |
int running, uint64_t dumpaddr) |
int running, uint64_t dumpaddr) |
700 |
{ |
{ |
701 |
int hi6, special6, regimm5; |
int hi6, special6, regimm5, sub; |
702 |
int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; |
int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag; |
703 |
uint64_t addr, offset; |
uint64_t addr, offset; |
704 |
uint32_t instrword; |
uint32_t instrword; |
740 |
debug(": %02x%02x%02x%02x", |
debug(": %02x%02x%02x%02x", |
741 |
instr[3], instr[2], instr[1], instr[0]); |
instr[3], instr[2], instr[1], instr[0]); |
742 |
|
|
743 |
if (running) |
if (running && cpu->delay_slot) |
744 |
debug("%s", cpu_flags(cpu)); |
debug(" (d)"); |
745 |
|
|
746 |
debug("\t"); |
debug("\t"); |
747 |
|
|
749 |
* Decode the instruction: |
* Decode the instruction: |
750 |
*/ |
*/ |
751 |
|
|
|
if (cpu->cd.mips.nullify_next && running) { |
|
|
debug("(nullified)"); |
|
|
goto disasm_ret; |
|
|
} |
|
|
|
|
752 |
hi6 = (instr[3] >> 2) & 0x3f; |
hi6 = (instr[3] >> 2) & 0x3f; |
753 |
|
|
754 |
switch (hi6) { |
switch (hi6) { |
764 |
case SPECIAL_DSLL32: |
case SPECIAL_DSLL32: |
765 |
case SPECIAL_DSRL32: |
case SPECIAL_DSRL32: |
766 |
case SPECIAL_DSRA32: |
case SPECIAL_DSRA32: |
767 |
|
sub = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
768 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
769 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
770 |
sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
778 |
debug("ehb"); |
debug("ehb"); |
779 |
else |
else |
780 |
debug("nop (weird, sa=%i)", sa); |
debug("nop (weird, sa=%i)", sa); |
781 |
goto disasm_ret; |
break; |
782 |
} else |
} |
783 |
|
|
784 |
|
switch (sub) { |
785 |
|
case 0x00: |
786 |
|
debug("%s\t%s,", special_names[special6], |
787 |
|
regnames[rd]); |
788 |
|
debug("%s,%i", regnames[rt], sa); |
789 |
|
break; |
790 |
|
case 0x01: |
791 |
debug("%s\t%s,", |
debug("%s\t%s,", |
792 |
special_names[special6], |
special_rot_names[special6], |
793 |
regname(cpu->machine, rd)); |
regnames[rd]); |
794 |
debug("%s,%i", regname(cpu->machine, rt), sa); |
debug("%s,%i", regnames[rt], sa); |
795 |
|
break; |
796 |
|
default:debug("UNIMPLEMENTED special, sub=0x%02x\n", |
797 |
|
sub); |
798 |
|
} |
799 |
break; |
break; |
800 |
case SPECIAL_DSRLV: |
case SPECIAL_DSRLV: |
801 |
case SPECIAL_DSRAV: |
case SPECIAL_DSRAV: |
806 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
807 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
808 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
809 |
debug("%s\t%s", |
sub = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3); |
810 |
special_names[special6], regname(cpu->machine, rd)); |
|
811 |
debug(",%s", regname(cpu->machine, rt)); |
switch (sub) { |
812 |
debug(",%s", regname(cpu->machine, rs)); |
case 0x00: |
813 |
|
debug("%s\t%s", special_names[special6], |
814 |
|
regnames[rd]); |
815 |
|
debug(",%s", regnames[rt]); |
816 |
|
debug(",%s", regnames[rs]); |
817 |
|
break; |
818 |
|
case 0x01: |
819 |
|
debug("%s\t%s", special_rot_names[special6], |
820 |
|
regnames[rd]); |
821 |
|
debug(",%s", regnames[rt]); |
822 |
|
debug(",%s", regnames[rs]); |
823 |
|
break; |
824 |
|
default:debug("UNIMPLEMENTED special, sub=0x%02x\n", |
825 |
|
sub); |
826 |
|
} |
827 |
break; |
break; |
828 |
case SPECIAL_JR: |
case SPECIAL_JR: |
829 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
830 |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
831 |
cpu->cd.mips.gpr[rs], &offset); |
cpu->cd.mips.gpr[rs], &offset); |
832 |
debug("jr\t%s", regname(cpu->machine, rs)); |
/* .hb = hazard barrier hint on MIPS32/64 rev 2 */ |
833 |
|
debug("jr%s\t%s", |
834 |
|
(instr[1] & 0x04) ? ".hb" : "", |
835 |
|
regnames[rs]); |
836 |
if (running && symbol != NULL) |
if (running && symbol != NULL) |
837 |
debug("\t<%s>", symbol); |
debug("\t<%s>", symbol); |
838 |
break; |
break; |
841 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
842 |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
symbol = get_symbol_name(&cpu->machine->symbol_context, |
843 |
cpu->cd.mips.gpr[rs], &offset); |
cpu->cd.mips.gpr[rs], &offset); |
844 |
debug("jalr\t%s", regname(cpu->machine, rd)); |
/* .hb = hazard barrier hint on MIPS32/64 rev 2 */ |
845 |
debug(",%s", regname(cpu->machine, rs)); |
debug("jalr%s\t%s", |
846 |
|
(instr[1] & 0x04) ? ".hb" : "", |
847 |
|
regnames[rd]); |
848 |
|
debug(",%s", regnames[rs]); |
849 |
if (running && symbol != NULL) |
if (running && symbol != NULL) |
850 |
debug("\t<%s>", symbol); |
debug("\t<%s>", symbol); |
851 |
break; |
break; |
852 |
case SPECIAL_MFHI: |
case SPECIAL_MFHI: |
853 |
case SPECIAL_MFLO: |
case SPECIAL_MFLO: |
854 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
855 |
debug("%s\t%s", special_names[special6], |
debug("%s\t%s", special_names[special6], regnames[rd]); |
|
regname(cpu->machine, rd)); |
|
856 |
break; |
break; |
857 |
case SPECIAL_MTLO: |
case SPECIAL_MTLO: |
858 |
case SPECIAL_MTHI: |
case SPECIAL_MTHI: |
859 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
860 |
debug("%s\t%s", special_names[special6], |
debug("%s\t%s", special_names[special6], regnames[rs]); |
|
regname(cpu->machine, rs)); |
|
861 |
break; |
break; |
862 |
case SPECIAL_ADD: |
case SPECIAL_ADD: |
863 |
case SPECIAL_ADDU: |
case SPECIAL_ADDU: |
882 |
special6 == SPECIAL_SUBU) && rt == 0) { |
special6 == SPECIAL_SUBU) && rt == 0) { |
883 |
/* Special case 1: addu/subu with |
/* Special case 1: addu/subu with |
884 |
rt = the zero register ==> move */ |
rt = the zero register ==> move */ |
885 |
debug("move\t%s", regname(cpu->machine, rd)); |
debug("move\t%s", regnames[rd]); |
886 |
debug(",%s", regname(cpu->machine, rs)); |
debug(",%s", regnames[rs]); |
887 |
} else if (special6 == SPECIAL_ADDU && cpu->is_32bit |
} else if (special6 == SPECIAL_ADDU && cpu->is_32bit |
888 |
&& rs == 0) { |
&& rs == 0) { |
889 |
/* Special case 2: addu with |
/* Special case 2: addu with |
890 |
rs = the zero register ==> move */ |
rs = the zero register ==> move */ |
891 |
debug("move\t%s", regname(cpu->machine, rd)); |
debug("move\t%s", regnames[rd]); |
892 |
debug(",%s", regname(cpu->machine, rt)); |
debug(",%s", regnames[rt]); |
893 |
} else { |
} else { |
894 |
debug("%s\t%s", special_names[special6], |
debug("%s\t%s", special_names[special6], |
895 |
regname(cpu->machine, rd)); |
regnames[rd]); |
896 |
debug(",%s", regname(cpu->machine, rs)); |
debug(",%s", regnames[rs]); |
897 |
debug(",%s", regname(cpu->machine, rt)); |
debug(",%s", regnames[rt]); |
898 |
} |
} |
899 |
break; |
break; |
900 |
case SPECIAL_MULT: |
case SPECIAL_MULT: |
919 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
920 |
if (special6 == SPECIAL_MULT || |
if (special6 == SPECIAL_MULT || |
921 |
special6 == SPECIAL_MULTU) |
special6 == SPECIAL_MULTU) |
922 |
debug("%s,", |
debug("%s,", regnames[rd]); |
|
regname(cpu->machine, rd)); |
|
923 |
else |
else |
924 |
debug("WEIRD_R5900_RD,"); |
debug("WEIRD_R5900_RD,"); |
925 |
} else { |
} else { |
926 |
debug("WEIRD_RD_NONZERO,"); |
debug("WEIRD_RD_NONZERO,"); |
927 |
} |
} |
928 |
} |
} |
929 |
debug("%s", regname(cpu->machine, rs)); |
debug("%s", regnames[rs]); |
930 |
debug(",%s", regname(cpu->machine, rt)); |
debug(",%s", regnames[rt]); |
931 |
break; |
break; |
932 |
case SPECIAL_SYNC: |
case SPECIAL_SYNC: |
933 |
imm = ((instr[1] & 7) << 2) + (instr[0] >> 6); |
imm = ((instr[1] & 7) << 2) + (instr[0] >> 6); |
952 |
case SPECIAL_MFSA: |
case SPECIAL_MFSA: |
953 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
954 |
rd = (instr[1] >> 3) & 31; |
rd = (instr[1] >> 3) & 31; |
955 |
debug("mfsa\t%s", regname(cpu->machine, rd)); |
debug("mfsa\t%s", regnames[rd]); |
956 |
} else { |
} else { |
957 |
debug("unimplemented special 0x28"); |
debug("unimplemented special 0x28"); |
958 |
} |
} |
961 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) { |
962 |
rs = ((instr[3] & 3) << 3) + |
rs = ((instr[3] & 3) << 3) + |
963 |
((instr[2] >> 5) & 7); |
((instr[2] >> 5) & 7); |
964 |
debug("mtsa\t%s", regname(cpu->machine, rs)); |
debug("mtsa\t%s", regnames[rs]); |
965 |
} else { |
} else { |
966 |
debug("unimplemented special 0x29"); |
debug("unimplemented special 0x29"); |
967 |
} |
} |
995 |
case HI6_BEQL: |
case HI6_BEQL: |
996 |
case HI6_BNE: |
case HI6_BNE: |
997 |
case HI6_BNEL: |
case HI6_BNEL: |
998 |
debug("%s,", regname(cpu->machine, rt)); |
debug("%s,", regnames[rt]); |
999 |
} |
} |
1000 |
debug("%s,", regname(cpu->machine, rs)); |
debug("%s,", regnames[rs]); |
1001 |
} |
} |
1002 |
|
|
1003 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
1024 |
imm = (instr[1] << 8) + instr[0]; |
imm = (instr[1] << 8) + instr[0]; |
1025 |
if (imm >= 32768) |
if (imm >= 32768) |
1026 |
imm -= 65536; |
imm -= 65536; |
1027 |
debug("%s\t%s,", hi6_names[hi6], regname(cpu->machine, rt)); |
debug("%s\t%s,", hi6_names[hi6], regnames[rt]); |
1028 |
debug("%s,", regname(cpu->machine, rs)); |
debug("%s,", regnames[rs]); |
1029 |
if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI) |
if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI) |
1030 |
debug("0x%04x", imm & 0xffff); |
debug("0x%04x", imm & 0xffff); |
1031 |
else |
else |
1034 |
case HI6_LUI: |
case HI6_LUI: |
1035 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
1036 |
imm = (instr[1] << 8) + instr[0]; |
imm = (instr[1] << 8) + instr[0]; |
1037 |
debug("lui\t%s,0x%x", regname(cpu->machine, rt), imm); |
debug("lui\t%s,0x%x", regnames[rt], imm); |
1038 |
break; |
break; |
1039 |
case HI6_LB: |
case HI6_LB: |
1040 |
case HI6_LBU: |
case HI6_LBU: |
1078 |
} |
} |
1079 |
if (hi6 == HI6_SQ_SPECIAL3 && |
if (hi6 == HI6_SQ_SPECIAL3 && |
1080 |
cpu->cd.mips.cpu_type.rev != MIPS_R5900) { |
cpu->cd.mips.cpu_type.rev != MIPS_R5900) { |
1081 |
|
int msbd, lsb, sub10; |
1082 |
special6 = instr[0] & 0x3f; |
special6 = instr[0] & 0x3f; |
|
debug("%s", special3_names[special6]); |
|
1083 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
1084 |
rt = instr[2] & 31; |
rt = instr[2] & 31; |
1085 |
rd = (instr[1] >> 3) & 31; |
rd = msbd = (instr[1] >> 3) & 31; |
1086 |
|
lsb = ((instr[1] & 7) << 2) | (instr[0] >> 6); |
1087 |
|
sub10 = (rs << 5) | lsb; |
1088 |
|
|
1089 |
switch (special6) { |
switch (special6) { |
1090 |
|
|
1091 |
|
case SPECIAL3_EXT: |
1092 |
|
case SPECIAL3_DEXT: |
1093 |
|
case SPECIAL3_DEXTM: |
1094 |
|
case SPECIAL3_DEXTU: |
1095 |
|
debug("%s", special3_names[special6]); |
1096 |
|
if (special6 == SPECIAL3_DEXTM) |
1097 |
|
msbd += 32; |
1098 |
|
if (special6 == SPECIAL3_DEXTU) |
1099 |
|
lsb += 32; |
1100 |
|
debug("\t%s", regnames[rt]); |
1101 |
|
debug(",%s", regnames[rs]); |
1102 |
|
debug(",%i,%i", lsb, msbd + 1); |
1103 |
|
break; |
1104 |
|
|
1105 |
|
case SPECIAL3_INS: |
1106 |
|
case SPECIAL3_DINS: |
1107 |
|
case SPECIAL3_DINSM: |
1108 |
|
case SPECIAL3_DINSU: |
1109 |
|
debug("%s", special3_names[special6]); |
1110 |
|
if (special6 == SPECIAL3_DINSM) |
1111 |
|
msbd += 32; |
1112 |
|
if (special6 == SPECIAL3_DINSU) { |
1113 |
|
lsb += 32; |
1114 |
|
msbd += 32; |
1115 |
|
} |
1116 |
|
msbd -= lsb; |
1117 |
|
debug("\t%s", regnames[rt]); |
1118 |
|
debug(",%s", regnames[rs]); |
1119 |
|
debug(",%i,%i", lsb, msbd + 1); |
1120 |
|
break; |
1121 |
|
|
1122 |
|
case SPECIAL3_BSHFL: |
1123 |
|
switch (sub10) { |
1124 |
|
case BSHFL_WSBH: |
1125 |
|
case BSHFL_SEB: |
1126 |
|
case BSHFL_SEH: |
1127 |
|
switch (sub10) { |
1128 |
|
case BSHFL_WSBH: debug("wsbh"); break; |
1129 |
|
case BSHFL_SEB: debug("seb"); break; |
1130 |
|
case BSHFL_SEH: debug("seh"); break; |
1131 |
|
} |
1132 |
|
debug("\t%s", regnames[rd]); |
1133 |
|
debug(",%s", regnames[rt]); |
1134 |
|
break; |
1135 |
|
default:debug("%s", special3_names[special6]); |
1136 |
|
debug("\t(UNIMPLEMENTED)"); |
1137 |
|
} |
1138 |
|
break; |
1139 |
|
|
1140 |
|
case SPECIAL3_DBSHFL: |
1141 |
|
switch (sub10) { |
1142 |
|
case BSHFL_DSBH: |
1143 |
|
case BSHFL_DSHD: |
1144 |
|
switch (sub10) { |
1145 |
|
case BSHFL_DSBH: debug("dsbh"); break; |
1146 |
|
case BSHFL_DSHD: debug("dshd"); break; |
1147 |
|
} |
1148 |
|
debug("\t%s", regnames[rd]); |
1149 |
|
debug(",%s", regnames[rt]); |
1150 |
|
break; |
1151 |
|
default:debug("%s", special3_names[special6]); |
1152 |
|
debug("\t(UNIMPLEMENTED)"); |
1153 |
|
} |
1154 |
|
break; |
1155 |
|
|
1156 |
case SPECIAL3_RDHWR: |
case SPECIAL3_RDHWR: |
1157 |
debug("\t%s", regname(cpu->machine, rt)); |
debug("%s", special3_names[special6]); |
1158 |
|
debug("\t%s", regnames[rt]); |
1159 |
debug(",hwr%i", rd); |
debug(",hwr%i", rd); |
1160 |
break; |
break; |
1161 |
|
|
1162 |
default: |
default:debug("%s", special3_names[special6]); |
1163 |
debug("\t(UNIMPLEMENTED)"); |
debug("\t(UNIMPLEMENTED)"); |
1164 |
} |
} |
1165 |
break; |
break; |
1177 |
/* TODO: Which ISAs? IV? V? 32? 64? */ |
/* TODO: Which ISAs? IV? V? 32? 64? */ |
1178 |
if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) { |
if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) { |
1179 |
debug("pref\t0x%x,%i(%s)", |
debug("pref\t0x%x,%i(%s)", |
1180 |
rt, imm, regname(cpu->machine, rs)); |
rt, imm, regnames[rs]); |
1181 |
|
|
1182 |
if (running) { |
if (running) { |
1183 |
debug("\t[0x%016"PRIx64" = %s]", |
debug("\t[0x%016"PRIx64" = %s]", |
1197 |
hi6 == HI6_LDC1 || hi6 == HI6_LDC2) |
hi6 == HI6_LDC1 || hi6 == HI6_LDC2) |
1198 |
debug("r%i", rt); |
debug("r%i", rt); |
1199 |
else |
else |
1200 |
debug("%s", regname(cpu->machine, rt)); |
debug("%s", regnames[rt]); |
1201 |
|
|
1202 |
debug(",%i(%s)", imm, regname(cpu->machine, rs)); |
debug(",%i(%s)", imm, regnames[rs]); |
1203 |
|
|
1204 |
if (running) { |
if (running) { |
1205 |
debug("\t["); |
debug("\t["); |
1259 |
cache_op = copz >> 2; |
cache_op = copz >> 2; |
1260 |
which_cache = copz & 3; |
which_cache = copz & 3; |
1261 |
showtag = 0; |
showtag = 0; |
1262 |
debug("cache\t0x%02x,0x%04x(%s)", copz, imm, |
debug("cache\t0x%02x,0x%04x(%s)", copz, imm, regnames[rt]); |
|
regname(cpu->machine, rt)); |
|
1263 |
if (which_cache==0) debug(" [ primary I-cache"); |
if (which_cache==0) debug(" [ primary I-cache"); |
1264 |
if (which_cache==1) debug(" [ primary D-cache"); |
if (which_cache==1) debug(" [ primary D-cache"); |
1265 |
if (which_cache==2) debug(" [ secondary I-cache"); |
if (which_cache==2) debug(" [ secondary I-cache"); |
1270 |
if (cache_op==2) debug("index store tag"), showtag=1; |
if (cache_op==2) debug("index store tag"), showtag=1; |
1271 |
if (cache_op==3) debug("create dirty exclusive"); |
if (cache_op==3) debug("create dirty exclusive"); |
1272 |
if (cache_op==4) debug("hit invalidate"); |
if (cache_op==4) debug("hit invalidate"); |
1273 |
if (cache_op==5) debug("fill OR hit writeback invalidate"); |
if (cache_op==5) debug("fill OR hit writeback invalidate"); |
1274 |
if (cache_op==6) debug("hit writeback"); |
if (cache_op==6) debug("hit writeback"); |
1275 |
if (cache_op==7) debug("hit set virtual"); |
if (cache_op==7) debug("hit set virtual"); |
1276 |
if (running) |
if (running) |
1302 |
case MMI_MADD: |
case MMI_MADD: |
1303 |
case MMI_MADDU: |
case MMI_MADDU: |
1304 |
if (rd != MIPS_GPR_ZERO) { |
if (rd != MIPS_GPR_ZERO) { |
1305 |
debug("%s,", regname(cpu->machine, rd)); |
debug("%s,", regnames[rd]); |
1306 |
} |
} |
1307 |
debug("%s", regname(cpu->machine, rs)); |
debug("%s,%s", regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1308 |
break; |
break; |
1309 |
|
|
1310 |
case MMI_MMI0: |
case MMI_MMI0: |
1319 |
case MMI0_PPACB: |
case MMI0_PPACB: |
1320 |
case MMI0_PPACH: |
case MMI0_PPACH: |
1321 |
case MMI0_PPACW: |
case MMI0_PPACW: |
1322 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s,%s", regnames[rd], |
1323 |
debug(",%s", regname(cpu->machine, rs)); |
regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1324 |
break; |
break; |
1325 |
|
|
1326 |
default:debug("(UNIMPLEMENTED)"); |
default:debug("(UNIMPLEMENTED)"); |
1336 |
case MMI1_PEXTUW: |
case MMI1_PEXTUW: |
1337 |
case MMI1_PMINH: |
case MMI1_PMINH: |
1338 |
case MMI1_PMINW: |
case MMI1_PMINW: |
1339 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s,%s", regnames[rd], |
1340 |
debug(",%s", regname(cpu->machine, rs)); |
regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1341 |
break; |
break; |
1342 |
|
|
1343 |
default:debug("(UNIMPLEMENTED)"); |
default:debug("(UNIMPLEMENTED)"); |
1350 |
|
|
1351 |
case MMI2_PMFHI: |
case MMI2_PMFHI: |
1352 |
case MMI2_PMFLO: |
case MMI2_PMFLO: |
1353 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s", regnames[rd]); |
1354 |
break; |
break; |
1355 |
|
|
1356 |
case MMI2_PHMADH: |
case MMI2_PHMADH: |
1363 |
case MMI2_PMULTH: |
case MMI2_PMULTH: |
1364 |
case MMI2_PMULTW: |
case MMI2_PMULTW: |
1365 |
case MMI2_PSLLVW: |
case MMI2_PSLLVW: |
1366 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s,%s", regnames[rd], |
1367 |
debug(",%s", regname(cpu->machine, rs)); |
regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1368 |
break; |
break; |
1369 |
|
|
1370 |
default:debug("(UNIMPLEMENTED)"); |
default:debug("(UNIMPLEMENTED)"); |
1377 |
|
|
1378 |
case MMI3_PMTHI: |
case MMI3_PMTHI: |
1379 |
case MMI3_PMTLO: |
case MMI3_PMTLO: |
1380 |
debug("%s", regname(cpu->machine, rs)); |
debug("%s", regnames[rs]); |
1381 |
break; |
break; |
1382 |
|
|
1383 |
case MMI3_PINTEH: |
case MMI3_PINTEH: |
1386 |
case MMI3_PNOR: |
case MMI3_PNOR: |
1387 |
case MMI3_POR: |
case MMI3_POR: |
1388 |
case MMI3_PSRAVW: |
case MMI3_PSRAVW: |
1389 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s,%s", regnames[rd], |
1390 |
debug(",%s", regname(cpu->machine, rs)); |
regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1391 |
break; |
break; |
1392 |
|
|
1393 |
default:debug("(UNIMPLEMENTED)"); |
default:debug("(UNIMPLEMENTED)"); |
1410 |
case SPECIAL2_MSUBU: |
case SPECIAL2_MSUBU: |
1411 |
if (rd != MIPS_GPR_ZERO) { |
if (rd != MIPS_GPR_ZERO) { |
1412 |
debug("WEIRD_NONZERO_RD(%s),", |
debug("WEIRD_NONZERO_RD(%s),", |
1413 |
regname(cpu->machine, rd)); |
regnames[rd]); |
1414 |
} |
} |
1415 |
debug("%s", regname(cpu->machine, rs)); |
debug("%s,%s", regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1416 |
break; |
break; |
1417 |
|
|
1418 |
case SPECIAL2_MUL: |
case SPECIAL2_MUL: |
1419 |
/* Apparently used both on R5900 and MIPS32: */ |
/* Apparently used both on R5900 and MIPS32: */ |
1420 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s,%s", regnames[rd], |
1421 |
debug(",%s", regname(cpu->machine, rs)); |
regnames[rs], regnames[rt]); |
|
debug(",%s", regname(cpu->machine, rt)); |
|
1422 |
break; |
break; |
1423 |
|
|
1424 |
case SPECIAL2_CLZ: |
case SPECIAL2_CLZ: |
1425 |
case SPECIAL2_CLO: |
case SPECIAL2_CLO: |
1426 |
case SPECIAL2_DCLZ: |
case SPECIAL2_DCLZ: |
1427 |
case SPECIAL2_DCLO: |
case SPECIAL2_DCLO: |
1428 |
debug("%s", regname(cpu->machine, rd)); |
debug("%s,%s", regnames[rd], regnames[rs]); |
|
debug(",%s", regname(cpu->machine, rs)); |
|
1429 |
break; |
break; |
1430 |
|
|
1431 |
default: |
default: |
1435 |
|
|
1436 |
case HI6_REGIMM: |
case HI6_REGIMM: |
1437 |
regimm5 = instr[2] & 0x1f; |
regimm5 = instr[2] & 0x1f; |
1438 |
|
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
1439 |
|
imm = (instr[1] << 8) + instr[0]; |
1440 |
|
if (imm >= 32768) |
1441 |
|
imm -= 65536; |
1442 |
|
|
1443 |
switch (regimm5) { |
switch (regimm5) { |
1444 |
|
|
1445 |
case REGIMM_BLTZ: |
case REGIMM_BLTZ: |
1446 |
case REGIMM_BGEZ: |
case REGIMM_BGEZ: |
1447 |
case REGIMM_BLTZL: |
case REGIMM_BLTZL: |
1450 |
case REGIMM_BLTZALL: |
case REGIMM_BLTZALL: |
1451 |
case REGIMM_BGEZAL: |
case REGIMM_BGEZAL: |
1452 |
case REGIMM_BGEZALL: |
case REGIMM_BGEZALL: |
1453 |
rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7); |
debug("%s\t%s,", regimm_names[regimm5], regnames[rs]); |
|
imm = (instr[1] << 8) + instr[0]; |
|
|
if (imm >= 32768) |
|
|
imm -= 65536; |
|
|
|
|
|
debug("%s\t%s,", regimm_names[regimm5], |
|
|
regname(cpu->machine, rs)); |
|
1454 |
|
|
1455 |
addr = (dumpaddr + 4) + (imm << 2); |
addr = (dumpaddr + 4) + (imm << 2); |
1456 |
|
|
1459 |
else |
else |
1460 |
debug("0x%016"PRIx64, (uint64_t) addr); |
debug("0x%016"PRIx64, (uint64_t) addr); |
1461 |
break; |
break; |
1462 |
|
|
1463 |
|
case REGIMM_SYNCI: |
1464 |
|
debug("%s\t%i(%s)", regimm_names[regimm5], |
1465 |
|
imm, regnames[rs]); |
1466 |
|
break; |
1467 |
|
|
1468 |
default: |
default: |
1469 |
debug("unimplemented regimm5 = 0x%02x", regimm5); |
debug("unimplemented regimm5 = 0x%02x", regimm5); |
1470 |
} |
} |
1542 |
" "); |
" "); |
1543 |
else |
else |
1544 |
debug(" %3s=%016"PRIx64"%016"PRIx64, |
debug(" %3s=%016"PRIx64"%016"PRIx64, |
1545 |
regname(cpu->machine, r), |
regnames[r], (uint64_t) |
1546 |
(uint64_t)cpu->cd.mips.gpr_quadhi[r], |
cpu->cd.mips.gpr_quadhi[r], |
1547 |
(uint64_t)cpu->cd.mips.gpr[r]); |
(uint64_t)cpu->cd.mips.gpr[r]); |
1548 |
if ((i & 1) == 1) |
if ((i & 1) == 1) |
1549 |
debug("\n"); |
debug("\n"); |
1556 |
if (i == MIPS_GPR_ZERO) |
if (i == MIPS_GPR_ZERO) |
1557 |
debug(" "); |
debug(" "); |
1558 |
else |
else |
1559 |
debug(" %3s = %08"PRIx32, |
debug(" %3s = %08"PRIx32, regnames[i], |
|
regname(cpu->machine, i), |
|
1560 |
(uint32_t)cpu->cd.mips.gpr[i]); |
(uint32_t)cpu->cd.mips.gpr[i]); |
1561 |
if ((i & 3) == 3) |
if ((i & 3) == 3) |
1562 |
debug("\n"); |
debug("\n"); |
1571 |
debug(" "); |
debug(" "); |
1572 |
else |
else |
1573 |
debug(" %3s = 0x%016"PRIx64, |
debug(" %3s = 0x%016"PRIx64, |
1574 |
regname(cpu->machine, r), |
regnames[r], |
1575 |
(uint64_t)cpu->cd.mips.gpr[r]); |
(uint64_t)cpu->cd.mips.gpr[r]); |
1576 |
if ((i & 1) == 1) |
if ((i & 1) == 1) |
1577 |
debug("\n"); |
debug("\n"); |
1599 |
if ((i & nm1) == 0) |
if ((i & nm1) == 0) |
1600 |
debug("cpu%i:", cpu->cpu_id); |
debug("cpu%i:", cpu->cpu_id); |
1601 |
|
|
1602 |
if (cpu->machine->show_symbolic_register_names && |
if (coprocnr == 0) |
|
coprocnr == 0) |
|
1603 |
debug(" %8s", cop0_names[i]); |
debug(" %8s", cop0_names[i]); |
1604 |
else |
else |
1605 |
debug(" c%i,%02i", coprocnr, i); |
debug(" c%i,%02i", coprocnr, i); |
1606 |
|
|
1607 |
if (bits32) |
if (bits32) |
1608 |
debug("=%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); |
debug("=%08x", (int)cpu->cd.mips. |
1609 |
|
coproc[coprocnr]->reg[i]); |
1610 |
else { |
else { |
1611 |
if (coprocnr == 0 && (i == COP0_COUNT |
if (coprocnr == 0 && (i == COP0_COUNT |
1612 |
|| i == COP0_COMPARE || i == COP0_INDEX |
|| i == COP0_COMPARE || i == COP0_INDEX |
1613 |
|| i == COP0_RANDOM || i == COP0_WIRED)) |
|| i == COP0_RANDOM || i == COP0_WIRED)) |
1614 |
debug(" = 0x%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]); |
debug(" = 0x%08x", |
1615 |
|
(int) cpu->cd.mips.coproc[ |
1616 |
|
coprocnr]->reg[i]); |
1617 |
else |
else |
1618 |
debug(" = 0x%016"PRIx64, (uint64_t) |
debug(" = 0x%016"PRIx64, (uint64_t) |
1619 |
cpu->cd.mips.coproc[coprocnr]->reg[i]); |
cpu->cd.mips.coproc[ |
1620 |
|
coprocnr]->reg[i]); |
1621 |
} |
} |
1622 |
|
|
1623 |
if ((i & nm1) == nm1) |
if ((i & nm1) == nm1) |
1633 |
debug("cpu%i: ", cpu->cpu_id); |
debug("cpu%i: ", cpu->cpu_id); |
1634 |
debug("config_select1 = 0x"); |
debug("config_select1 = 0x"); |
1635 |
if (cpu->is_32bit) |
if (cpu->is_32bit) |
1636 |
debug("%08"PRIx32, (uint32_t)cpu->cd.mips.cop0_config_select1); |
debug("%08"PRIx32, |
1637 |
|
(uint32_t)cpu->cd.mips.cop0_config_select1); |
1638 |
else |
else |
1639 |
debug("%016"PRIx64, (uint64_t)cpu->cd.mips.cop0_config_select1); |
debug("%016"PRIx64, |
1640 |
|
(uint64_t)cpu->cd.mips.cop0_config_select1); |
1641 |
debug("\n"); |
debug("\n"); |
1642 |
} |
} |
1643 |
|
|
1671 |
} |
} |
1672 |
|
|
1673 |
|
|
|
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); |
|
|
} |
|
|
|
|
|
|
|
1674 |
/* |
/* |
1675 |
* mips_cpu_gdb_stub(): |
* mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert(): |
1676 |
* |
* |
1677 |
* Execute a "remote GDB" command. Returns 1 on success, 0 on error. |
* Assert or deassert a MIPS CPU interrupt by masking in or out bits |
1678 |
|
* in the CAUSE register of coprocessor 0. |
1679 |
*/ |
*/ |
1680 |
char *mips_cpu_gdb_stub(struct cpu *cpu, char *cmd) |
void mips_cpu_interrupt_assert(struct interrupt *interrupt) |
1681 |
{ |
{ |
1682 |
if (strcmp(cmd, "g") == 0) { |
struct cpu *cpu = interrupt->extra; |
1683 |
/* 76 registers: gprs, sr, lo, hi, badvaddr, cause, pc, |
cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line; |
|
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; |
|
1684 |
} |
} |
1685 |
|
void mips_cpu_interrupt_deassert(struct interrupt *interrupt) |
|
|
|
|
/* |
|
|
* mips_cpu_interrupt(): |
|
|
* |
|
|
* Cause an interrupt. If irq_nr is 2..7, then it is a MIPS hardware |
|
|
* interrupt. 0 and 1 are ignored (software interrupts). |
|
|
* |
|
|
* If irq_nr is >= 8, then this function calls md_interrupt(). |
|
|
*/ |
|
|
int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) |
|
1686 |
{ |
{ |
1687 |
if (irq_nr >= 8) { |
struct cpu *cpu = interrupt->extra; |
1688 |
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; |
|
|
} |
|
|
|
|
|
|
|
|
/* |
|
|
* 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) |
|
|
{ |
|
|
if (irq_nr >= 8) { |
|
|
if (cpu->machine->md_interrupt != NULL) |
|
|
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; |
|
1689 |
} |
} |
1690 |
|
|
1691 |
|
|
1737 |
switch (exccode) { |
switch (exccode) { |
1738 |
|
|
1739 |
case EXCEPTION_INT: |
case EXCEPTION_INT: |
1740 |
debug(" cause_im=0x%02x", (int)((reg[COP0_CAUSE] & CAUSE_IP_MASK) >> CAUSE_IP_SHIFT)); |
debug(" cause_im=0x%02x", (int) |
1741 |
|
((reg[COP0_CAUSE] & CAUSE_IP_MASK) |
1742 |
|
>> CAUSE_IP_SHIFT)); |
1743 |
break; |
break; |
1744 |
|
|
1745 |
case EXCEPTION_SYS: |
case EXCEPTION_SYS: |
1829 |
|
|
1830 |
if (exc_model == EXC3K) { |
if (exc_model == EXC3K) { |
1831 |
reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; |
reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK; |
1832 |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << R2K3K_CONTEXT_BADVPN_SHIFT) & R2K3K_CONTEXT_BADVPN_MASK); |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << |
1833 |
|
R2K3K_CONTEXT_BADVPN_SHIFT) & |
1834 |
|
R2K3K_CONTEXT_BADVPN_MASK); |
1835 |
|
|
1836 |
reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK) |
1837 |
| (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT); |
| (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT); |
1841 |
reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI]; |
reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI]; |
1842 |
} else { |
} else { |
1843 |
if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { |
if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) { |
1844 |
reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK_R4100; |
reg[COP0_CONTEXT] &= |
1845 |
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK_R4100); |
~CONTEXT_BADVPN2_MASK_R4100; |
1846 |
|
reg[COP0_CONTEXT] |= ((vaddr_vpn2 << |
1847 |
|
CONTEXT_BADVPN2_SHIFT) & |
1848 |
|
CONTEXT_BADVPN2_MASK_R4100); |
1849 |
|
|
1850 |
/* TODO: fix these */ |
/* TODO: fix these */ |
1851 |
reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; |
reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK; |
1885 |
/* debug("[ warning: cpu%i exception while EXL is set," |
/* debug("[ warning: cpu%i exception while EXL is set," |
1886 |
" not setting EPC ]\n", cpu->cpu_id); */ |
" not setting EPC ]\n", cpu->cpu_id); */ |
1887 |
} else { |
} else { |
1888 |
if (cpu->delay_slot || cpu->cd.mips.nullify_next) { |
if (cpu->delay_slot) { |
1889 |
reg[COP0_EPC] = cpu->pc - 4; |
reg[COP0_EPC] = cpu->pc - 4; |
1890 |
reg[COP0_CAUSE] |= CAUSE_BD; |
reg[COP0_CAUSE] |= CAUSE_BD; |
|
|
|
|
/* TODO: Should the BD flag actually be set |
|
|
on nullified slots? */ |
|
1891 |
} else { |
} else { |
1892 |
reg[COP0_EPC] = cpu->pc; |
reg[COP0_EPC] = cpu->pc; |
1893 |
reg[COP0_CAUSE] &= ~CAUSE_BD; |
reg[COP0_CAUSE] &= ~CAUSE_BD; |
1899 |
else |
else |
1900 |
cpu->delay_slot = NOT_DELAYED; |
cpu->delay_slot = NOT_DELAYED; |
1901 |
|
|
|
cpu->cd.mips.nullify_next = 0; |
|
|
|
|
1902 |
/* TODO: This is true for MIPS64, but how about others? */ |
/* TODO: This is true for MIPS64, but how about others? */ |
1903 |
if (reg[COP0_STATUS] & STATUS_BEV) |
if (reg[COP0_STATUS] & STATUS_BEV) |
1904 |
base = 0xffffffffbfc00200ULL; |
base = 0xffffffffbfc00200ULL; |