1 |
/* |
/* |
2 |
* Cisco 7200 (Predator) simulation platform. |
* Cisco router simulation platform. |
3 |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
* Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) |
4 |
* |
* |
5 |
* XXX TODO: proper context save/restore for CPUs. |
* XXX TODO: proper context save/restore for CPUs. |
16 |
#include <assert.h> |
#include <assert.h> |
17 |
|
|
18 |
#include "rbtree.h" |
#include "rbtree.h" |
19 |
#include "mips64.h" |
#include "cpu.h" |
20 |
#include "dynamips.h" |
#include "mips64_mem.h" |
|
#include "cp0.h" |
|
21 |
#include "mips64_exec.h" |
#include "mips64_exec.h" |
22 |
|
#include "mips64_jit.h" |
23 |
|
#include "dynamips.h" |
24 |
#include "memory.h" |
#include "memory.h" |
25 |
#include "device.h" |
#include "device.h" |
26 |
|
|
68 |
memset(&cpu->cp0.tlb,0,MIPS64_TLB_MAX_ENTRIES*sizeof(tlb_entry_t)); |
memset(&cpu->cp0.tlb,0,MIPS64_TLB_MAX_ENTRIES*sizeof(tlb_entry_t)); |
69 |
|
|
70 |
/* Restart the MTS subsystem */ |
/* Restart the MTS subsystem */ |
71 |
mts_shutdown(cpu); |
mips64_set_addr_mode(cpu,32/*64*/); /* zzz */ |
72 |
mts64_init(cpu); |
cpu->gen->mts_rebuild(cpu->gen); |
|
mts_init_memop_vectors(cpu); |
|
|
cpu->mts_rebuild(cpu); |
|
73 |
|
|
74 |
/* Flush JIT structures */ |
/* Flush JIT structures */ |
75 |
mips64_jit_flush(cpu,0); |
mips64_jit_flush(cpu,0); |
79 |
/* Initialize a MIPS64 processor */ |
/* Initialize a MIPS64 processor */ |
80 |
int mips64_init(cpu_mips_t *cpu) |
int mips64_init(cpu_mips_t *cpu) |
81 |
{ |
{ |
|
cpu->state = MIPS_CPU_SUSPENDED; |
|
82 |
cpu->addr_bus_mask = 0xFFFFFFFFFFFFFFFFULL; |
cpu->addr_bus_mask = 0xFFFFFFFFFFFFFFFFULL; |
83 |
cpu->cp0.reg[MIPS_CP0_PRID] = MIPS_PRID_R4600; |
cpu->cp0.reg[MIPS_CP0_PRID] = MIPS_PRID_R4600; |
84 |
cpu->cp0.tlb_entries = MIPS64_TLB_STD_ENTRIES; |
cpu->cp0.tlb_entries = MIPS64_TLB_STD_ENTRIES; |
85 |
|
|
86 |
/* Initialize idle timer */ |
/* Initialize idle timer */ |
87 |
cpu->idle_max = 1500; |
cpu->gen->idle_max = 1500; |
88 |
cpu->idle_sleep_time = 50000; |
cpu->gen->idle_sleep_time = 30000; |
89 |
|
|
90 |
/* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */ |
/* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */ |
91 |
cpu->timer_irq_check_itv = 1000; |
cpu->timer_irq_check_itv = 1000; |
94 |
/* Enable fast memory operations */ |
/* Enable fast memory operations */ |
95 |
cpu->fast_memop = TRUE; |
cpu->fast_memop = TRUE; |
96 |
|
|
97 |
|
/* Enable/Disable direct block jump */ |
98 |
|
cpu->exec_blk_direct_jump = cpu->vm->exec_blk_direct_jump; |
99 |
|
|
100 |
/* Create the IRQ lock (for non-jit architectures) */ |
/* Create the IRQ lock (for non-jit architectures) */ |
101 |
pthread_mutex_init(&cpu->irq_lock,NULL); |
pthread_mutex_init(&cpu->irq_lock,NULL); |
102 |
|
|
103 |
/* Idle loop mutex and condition */ |
/* Idle loop mutex and condition */ |
104 |
pthread_mutex_init(&cpu->idle_mutex,NULL); |
pthread_mutex_init(&cpu->gen->idle_mutex,NULL); |
105 |
pthread_cond_init(&cpu->idle_cond,NULL); |
pthread_cond_init(&cpu->gen->idle_cond,NULL); |
106 |
|
|
107 |
|
/* Set the CPU methods */ |
108 |
|
cpu->gen->reg_set = (void *)mips64_reg_set; |
109 |
|
cpu->gen->reg_dump = (void *)mips64_dump_regs; |
110 |
|
cpu->gen->mmu_dump = (void *)mips64_tlb_dump; |
111 |
|
cpu->gen->mmu_raw_dump = (void *)mips64_tlb_raw_dump; |
112 |
|
cpu->gen->add_breakpoint = (void *)mips64_add_breakpoint; |
113 |
|
cpu->gen->remove_breakpoint = (void *)mips64_remove_breakpoint; |
114 |
|
cpu->gen->set_idle_pc = (void *)mips64_set_idle_pc; |
115 |
|
cpu->gen->get_idling_pc = (void *)mips64_get_idling_pc; |
116 |
|
|
117 |
/* Set the startup parameters */ |
/* Set the startup parameters */ |
118 |
mips64_reset(cpu); |
mips64_reset(cpu); |
123 |
void mips64_delete(cpu_mips_t *cpu) |
void mips64_delete(cpu_mips_t *cpu) |
124 |
{ |
{ |
125 |
if (cpu) { |
if (cpu) { |
126 |
mts_shutdown(cpu); |
mips64_mem_shutdown(cpu); |
127 |
mips64_jit_shutdown(cpu); |
mips64_jit_shutdown(cpu); |
|
free(cpu); |
|
128 |
} |
} |
129 |
} |
} |
130 |
|
|
137 |
cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES; |
cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES; |
138 |
} |
} |
139 |
|
|
140 |
/* Virtual idle loop */ |
/* Set idle PC value */ |
141 |
void mips64_idle_loop(cpu_mips_t *cpu) |
void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr) |
|
{ |
|
|
struct timespec t_spc; |
|
|
m_tmcnt_t expire; |
|
|
|
|
|
expire = m_gettime_usec() + cpu->idle_sleep_time; |
|
|
|
|
|
pthread_mutex_lock(&cpu->idle_mutex); |
|
|
t_spc.tv_sec = expire / 1000000; |
|
|
t_spc.tv_nsec = (expire % 1000000) * 1000; |
|
|
pthread_cond_timedwait(&cpu->idle_cond,&cpu->idle_mutex,&t_spc); |
|
|
pthread_mutex_unlock(&cpu->idle_mutex); |
|
|
} |
|
|
|
|
|
/* Break idle wait state */ |
|
|
void mips64_idle_break_wait(cpu_mips_t *cpu) |
|
142 |
{ |
{ |
143 |
pthread_cond_signal(&cpu->idle_cond); |
CPU_MIPS64(cpu)->idle_pc = addr; |
144 |
} |
} |
145 |
|
|
146 |
/* Timer IRQ */ |
/* Timer IRQ */ |
157 |
threshold = cpu->timer_irq_freq * 10; |
threshold = cpu->timer_irq_freq * 10; |
158 |
expire = m_gettime_usec() + interval; |
expire = m_gettime_usec() + interval; |
159 |
|
|
160 |
while(cpu->state != MIPS_CPU_HALTED) { |
while(cpu->gen->state != CPU_STATE_HALTED) { |
161 |
pthread_mutex_lock(&umutex); |
pthread_mutex_lock(&umutex); |
162 |
t_spc.tv_sec = expire / 1000000; |
t_spc.tv_sec = expire / 1000000; |
163 |
t_spc.tv_nsec = (expire % 1000000) * 1000; |
t_spc.tv_nsec = (expire % 1000000) * 1000; |
165 |
pthread_mutex_unlock(&umutex); |
pthread_mutex_unlock(&umutex); |
166 |
|
|
167 |
if (likely(!cpu->irq_disable) && |
if (likely(!cpu->irq_disable) && |
168 |
likely(cpu->state == MIPS_CPU_RUNNING)) |
likely(cpu->gen->state == CPU_STATE_RUNNING)) |
169 |
{ |
{ |
170 |
cpu->timer_irq_pending++; |
cpu->timer_irq_pending++; |
171 |
|
|
187 |
return NULL; |
return NULL; |
188 |
} |
} |
189 |
|
|
190 |
|
#define IDLE_HASH_SIZE 8192 |
191 |
|
|
192 |
/* Idle PC hash item */ |
/* Idle PC hash item */ |
193 |
struct mips64_idle_pc { |
struct mips64_idle_pc_hash { |
194 |
m_uint64_t pc; |
m_uint64_t pc; |
195 |
u_int count; |
u_int count; |
196 |
struct mips64_idle_pc *next; |
struct mips64_idle_pc_hash *next; |
197 |
}; |
}; |
198 |
|
|
|
#define IDLE_HASH_SIZE 8192 |
|
|
#define IDLE_MAX_RES 10 |
|
|
|
|
199 |
/* Determine an "idling" PC */ |
/* Determine an "idling" PC */ |
200 |
int mips64_get_idling_pc(cpu_mips_t *cpu) |
int mips64_get_idling_pc(cpu_gen_t *cpu) |
201 |
{ |
{ |
202 |
struct mips64_idle_pc *res[IDLE_MAX_RES]; |
cpu_mips_t *mcpu = CPU_MIPS64(cpu); |
203 |
struct mips64_idle_pc **pc_hash,*p; |
struct mips64_idle_pc_hash **pc_hash,*p; |
204 |
|
struct cpu_idle_pc *res; |
205 |
u_int h_index,res_count; |
u_int h_index,res_count; |
206 |
m_uint64_t cur_pc; |
m_uint64_t cur_pc; |
207 |
int i; |
int i; |
208 |
|
|
209 |
if (cpu->idle_pc != 0) { |
cpu->idle_pc_prop_count = 0; |
210 |
|
|
211 |
|
if (mcpu->idle_pc != 0) { |
212 |
printf("\nYou already use an idle PC, using the calibration would give " |
printf("\nYou already use an idle PC, using the calibration would give " |
213 |
"incorrect results.\n"); |
"incorrect results.\n"); |
214 |
return(-1); |
return(-1); |
216 |
|
|
217 |
printf("\nPlease wait while gathering statistics...\n"); |
printf("\nPlease wait while gathering statistics...\n"); |
218 |
|
|
219 |
pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc *)); |
pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *)); |
220 |
|
|
221 |
/* Disable IRQ */ |
/* Disable IRQ */ |
222 |
cpu->irq_disable = TRUE; |
mcpu->irq_disable = TRUE; |
223 |
|
|
224 |
/* Take 1000 measures, each mesure every 10ms */ |
/* Take 1000 measures, each mesure every 10ms */ |
225 |
for(i=0;i<1000;i++) { |
for(i=0;i<1000;i++) { |
226 |
cur_pc = cpu->pc; |
cur_pc = mcpu->pc; |
227 |
h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1); |
h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1); |
228 |
|
|
229 |
for(p=pc_hash[h_index];p;p=p->next) |
for(p=pc_hash[h_index];p;p=p->next) |
245 |
} |
} |
246 |
|
|
247 |
/* Select PCs */ |
/* Select PCs */ |
|
memset(res,0,sizeof(res)); |
|
|
|
|
248 |
for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) { |
for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) { |
249 |
for(p=pc_hash[i];p;p=p->next) |
for(p=pc_hash[i];p;p=p->next) |
250 |
if ((p->count >= 20) && (p->count <= 80)) { |
if ((p->count >= 20) && (p->count <= 80)) { |
251 |
res[res_count++] = p; |
res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++]; |
252 |
|
|
253 |
|
res->pc = p->pc; |
254 |
|
res->count = p->count; |
255 |
|
|
256 |
if (res_count >= IDLE_MAX_RES) |
if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES) |
257 |
goto done; |
goto done; |
258 |
} |
} |
259 |
} |
} |
260 |
|
|
261 |
done: |
done: |
262 |
/* Set idle PC */ |
/* Set idle PC */ |
263 |
if (res_count) { |
if (cpu->idle_pc_prop_count) { |
264 |
printf("Done. Suggested idling PC:\n"); |
printf("Done. Suggested idling PC:\n"); |
265 |
|
|
266 |
for(i=0;i<res_count;i++) |
for(i=0;i<cpu->idle_pc_prop_count;i++) { |
267 |
printf(" 0x%llx (count=%u)\n",res[i]->pc,res[i]->count); |
printf(" 0x%llx (count=%u)\n", |
268 |
|
cpu->idle_pc_prop[i].pc, |
269 |
|
cpu->idle_pc_prop[i].count); |
270 |
|
} |
271 |
|
|
272 |
printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n", |
printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n", |
273 |
res[0]->pc); |
cpu->idle_pc_prop[0].pc); |
274 |
} else { |
} else { |
275 |
printf("Done. No suggestion for idling PC\n"); |
printf("Done. No suggestion for idling PC\n"); |
276 |
|
|
277 |
|
for(i=0;i<IDLE_HASH_SIZE;i++) |
278 |
|
for(p=pc_hash[i];p;p=p->next) { |
279 |
|
printf(" 0x%16.16llx (%3u)\n",p->pc,p->count); |
280 |
|
|
281 |
|
if (cpu->idle_pc_prop_count < CPU_IDLE_PC_MAX_RES) { |
282 |
|
res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++]; |
283 |
|
|
284 |
|
res->pc = p->pc; |
285 |
|
res->count = p->count; |
286 |
|
} |
287 |
|
} |
288 |
|
|
289 |
|
printf("\n"); |
290 |
} |
} |
291 |
|
|
292 |
/* Re-enable IRQ */ |
/* Re-enable IRQ */ |
293 |
cpu->irq_disable = FALSE; |
mcpu->irq_disable = FALSE; |
294 |
return(0); |
return(0); |
295 |
} |
} |
296 |
|
|
297 |
|
/* Set an IRQ (VM IRQ standard routing) */ |
298 |
|
void mips64_vm_set_irq(vm_instance_t *vm,u_int irq) |
299 |
|
{ |
300 |
|
cpu_mips_t *boot_cpu; |
301 |
|
|
302 |
|
boot_cpu = CPU_MIPS64(vm->boot_cpu); |
303 |
|
|
304 |
|
if (boot_cpu->irq_disable) { |
305 |
|
boot_cpu->irq_pending = 0; |
306 |
|
return; |
307 |
|
} |
308 |
|
|
309 |
|
mips64_set_irq(boot_cpu,irq); |
310 |
|
|
311 |
|
if (boot_cpu->irq_idle_preempt[irq]) |
312 |
|
cpu_idle_break_wait(vm->boot_cpu); |
313 |
|
} |
314 |
|
|
315 |
|
/* Clear an IRQ (VM IRQ standard routing) */ |
316 |
|
void mips64_vm_clear_irq(vm_instance_t *vm,u_int irq) |
317 |
|
{ |
318 |
|
cpu_mips_t *boot_cpu; |
319 |
|
|
320 |
|
boot_cpu = CPU_MIPS64(vm->boot_cpu); |
321 |
|
mips64_clear_irq(boot_cpu,irq); |
322 |
|
} |
323 |
|
|
324 |
/* Update the IRQ flag (inline) */ |
/* Update the IRQ flag (inline) */ |
325 |
static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu) |
static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu) |
326 |
{ |
{ |
471 |
fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code) |
fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code) |
472 |
{ |
{ |
473 |
printf("MIPS64: BREAK instruction (code=%u)\n",code); |
printf("MIPS64: BREAK instruction (code=%u)\n",code); |
474 |
mips64_dump_regs(cpu); |
mips64_dump_regs(cpu->gen); |
475 |
|
|
476 |
/* XXX TODO: Branch Delay slot */ |
/* XXX TODO: Branch Delay slot */ |
477 |
mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0); |
mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0); |
530 |
/* Virtual breakpoint */ |
/* Virtual breakpoint */ |
531 |
fastcall void mips64_run_breakpoint(cpu_mips_t *cpu) |
fastcall void mips64_run_breakpoint(cpu_mips_t *cpu) |
532 |
{ |
{ |
533 |
cpu_log(cpu,"BREAKPOINT", |
cpu_log(cpu->gen,"BREAKPOINT", |
534 |
"Virtual breakpoint reached at PC=0x%llx\n",cpu->pc); |
"Virtual breakpoint reached at PC=0x%llx\n",cpu->pc); |
535 |
|
|
536 |
printf("[[[ Virtual Breakpoint reached at PC=0x%llx ]]]\n",cpu->pc); |
printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n", |
537 |
mips64_dump_regs(cpu); |
cpu->pc,cpu->gpr[MIPS_GPR_RA]); |
538 |
memlog_dump(cpu); |
|
539 |
|
mips64_dump_regs(cpu->gen); |
540 |
|
memlog_dump(cpu->gen); |
541 |
|
} |
542 |
|
|
543 |
|
/* Add a virtual breakpoint */ |
544 |
|
int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc) |
545 |
|
{ |
546 |
|
cpu_mips_t *mcpu = CPU_MIPS64(cpu); |
547 |
|
int i; |
548 |
|
|
549 |
|
for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) |
550 |
|
if (!mcpu->breakpoints[i]) |
551 |
|
break; |
552 |
|
|
553 |
|
if (i == MIPS64_MAX_BREAKPOINTS) |
554 |
|
return(-1); |
555 |
|
|
556 |
|
mcpu->breakpoints[i] = pc; |
557 |
|
mcpu->breakpoints_enabled = TRUE; |
558 |
|
return(0); |
559 |
|
} |
560 |
|
|
561 |
|
/* Remove a virtual breakpoint */ |
562 |
|
void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc) |
563 |
|
{ |
564 |
|
cpu_mips_t *mcpu = CPU_MIPS64(cpu); |
565 |
|
int i,j; |
566 |
|
|
567 |
|
for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) |
568 |
|
if (mcpu->breakpoints[i] == pc) |
569 |
|
{ |
570 |
|
for(j=i;j<MIPS64_MAX_BREAKPOINTS-1;j++) |
571 |
|
mcpu->breakpoints[j] = mcpu->breakpoints[j+1]; |
572 |
|
|
573 |
|
mcpu->breakpoints[MIPS64_MAX_BREAKPOINTS-1] = 0; |
574 |
|
} |
575 |
|
|
576 |
|
for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++) |
577 |
|
if (mcpu->breakpoints[i] != 0) |
578 |
|
return; |
579 |
|
|
580 |
|
mcpu->breakpoints_enabled = FALSE; |
581 |
} |
} |
582 |
|
|
583 |
/* Debugging for register-jump to address 0 */ |
/* Debugging for register-jump to address 0 */ |
584 |
fastcall void mips64_debug_jr0(cpu_mips_t *cpu) |
fastcall void mips64_debug_jr0(cpu_mips_t *cpu) |
585 |
{ |
{ |
586 |
printf("MIPS64: cpu %p jumping to address 0...\n",cpu); |
printf("MIPS64: cpu %p jumping to address 0...\n",cpu); |
587 |
mips64_dump_regs(cpu); |
mips64_dump_regs(cpu->gen); |
588 |
|
} |
589 |
|
|
590 |
|
/* Set a register */ |
591 |
|
void mips64_reg_set(cpu_gen_t *cpu,u_int reg,m_uint64_t val) |
592 |
|
{ |
593 |
|
if (reg < MIPS64_GPR_NR) |
594 |
|
CPU_MIPS64(cpu)->gpr[reg] = val; |
595 |
} |
} |
596 |
|
|
597 |
/* Dump registers of a MIPS64 processor */ |
/* Dump registers of a MIPS64 processor */ |
598 |
void mips64_dump_regs(cpu_mips_t *cpu) |
void mips64_dump_regs(cpu_gen_t *cpu) |
599 |
{ |
{ |
600 |
|
cpu_mips_t *mcpu = CPU_MIPS64(cpu); |
601 |
mips_insn_t *ptr,insn; |
mips_insn_t *ptr,insn; |
602 |
char buffer[80]; |
char buffer[80]; |
603 |
int i; |
int i; |
606 |
|
|
607 |
for(i=0;i<MIPS64_GPR_NR/2;i++) { |
for(i=0;i<MIPS64_GPR_NR/2;i++) { |
608 |
printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n", |
printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n", |
609 |
mips64_gpr_reg_names[i*2], i*2, cpu->gpr[i*2], |
mips64_gpr_reg_names[i*2], i*2, mcpu->gpr[i*2], |
610 |
mips64_gpr_reg_names[(i*2)+1], (i*2)+1, cpu->gpr[(i*2)+1]); |
mips64_gpr_reg_names[(i*2)+1], (i*2)+1, mcpu->gpr[(i*2)+1]); |
611 |
} |
} |
612 |
|
|
613 |
printf(" lo = 0x%16.16llx, hi = 0x%16.16llx\n", cpu->lo, cpu->hi); |
printf(" lo = 0x%16.16llx, hi = 0x%16.16llx\n", mcpu->lo, mcpu->hi); |
614 |
printf(" pc = 0x%16.16llx, ll_bit = %u\n", cpu->pc, cpu->ll_bit); |
printf(" pc = 0x%16.16llx, ll_bit = %u\n", mcpu->pc, mcpu->ll_bit); |
615 |
|
|
616 |
/* Fetch the current instruction */ |
/* Fetch the current instruction */ |
617 |
ptr = cpu->mem_op_lookup(cpu,cpu->pc); |
ptr = mcpu->mem_op_lookup(mcpu,mcpu->pc); |
618 |
if (ptr) { |
if (ptr) { |
619 |
insn = vmtoh32(*ptr); |
insn = vmtoh32(*ptr); |
620 |
|
|
621 |
if (mips64_dump_insn(buffer,sizeof(buffer),1,cpu->pc,insn) != -1) |
if (mips64_dump_insn(buffer,sizeof(buffer),1,mcpu->pc,insn) != -1) |
622 |
printf(" Instruction: %s\n",buffer); |
printf(" Instruction: %s\n",buffer); |
623 |
} |
} |
624 |
|
|
626 |
|
|
627 |
for(i=0;i<MIPS64_CP0_REG_NR/2;i++) { |
for(i=0;i<MIPS64_CP0_REG_NR/2;i++) { |
628 |
printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n", |
printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n", |
629 |
mips64_cp0_reg_names[i*2], i*2, cp0_get_reg(cpu,i*2), |
mips64_cp0_reg_names[i*2], i*2, |
630 |
mips64_cp0_reg_names[(i*2)+1], (i*2)+1, cp0_get_reg(cpu,(i*2)+1)); |
mips64_cp0_get_reg(mcpu,i*2), |
631 |
|
mips64_cp0_reg_names[(i*2)+1], (i*2)+1, |
632 |
|
mips64_cp0_get_reg(mcpu,(i*2)+1)); |
633 |
} |
} |
634 |
|
|
635 |
printf("\n IRQ count: %llu, IRQ false positives: %llu, " |
printf("\n IRQ count: %llu, IRQ false positives: %llu, " |
636 |
"IRQ Pending: %u\n", |
"IRQ Pending: %u\n", |
637 |
cpu->irq_count,cpu->irq_fp_count,cpu->irq_pending); |
mcpu->irq_count,mcpu->irq_fp_count,mcpu->irq_pending); |
638 |
|
|
639 |
printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n", |
printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n", |
640 |
cpu->timer_irq_count,cpu->timer_irq_pending,cpu->timer_drift); |
mcpu->timer_irq_count,mcpu->timer_irq_pending,mcpu->timer_drift); |
641 |
|
|
642 |
|
printf(" Device access count: %llu\n",cpu->dev_access_counter); |
643 |
printf("\n"); |
printf("\n"); |
644 |
} |
} |
645 |
|
|
783 |
} |
} |
784 |
|
|
785 |
/* cp0 register ? */ |
/* cp0 register ? */ |
786 |
if ((index = cp0_get_reg_index(buffer)) != -1) { |
if ((index = mips64_cp0_get_reg_index(buffer)) != -1) { |
787 |
cpu->cp0.reg[index] = mips64_hex_u64(value,NULL); |
cpu->cp0.reg[index] = mips64_hex_u64(value,NULL); |
788 |
continue; |
continue; |
789 |
} |
} |
841 |
} |
} |
842 |
} |
} |
843 |
|
|
844 |
cp0_map_all_tlb_to_mts(cpu); |
mips64_cp0_map_all_tlb_to_mts(cpu); |
845 |
|
|
846 |
mips64_dump_regs(cpu); |
mips64_dump_regs(cpu->gen); |
847 |
tlb_dump(cpu); |
mips64_tlb_dump(cpu->gen); |
848 |
|
|
849 |
fclose(fd); |
fclose(fd); |
850 |
return(0); |
return(0); |
855 |
{ |
{ |
856 |
struct stat file_info; |
struct stat file_info; |
857 |
size_t len,clen; |
size_t len,clen; |
858 |
|
m_uint32_t remain; |
859 |
void *haddr; |
void *haddr; |
860 |
FILE *bfd; |
FILE *bfd; |
861 |
|
|
889 |
else |
else |
890 |
clen = len; |
clen = len; |
891 |
|
|
892 |
|
remain = MIPS_MIN_PAGE_SIZE; |
893 |
|
remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_MASK)); |
894 |
|
|
895 |
|
clen = m_min(clen,remain); |
896 |
|
|
897 |
if (fread((u_char *)haddr,clen,1,bfd) != 1) |
if (fread((u_char *)haddr,clen,1,bfd) != 1) |
898 |
break; |
break; |
899 |
|
|
900 |
vaddr += MIPS_MIN_PAGE_SIZE; |
vaddr += clen; |
901 |
len -= clen; |
len -= clen; |
902 |
} |
} |
903 |
|
|
906 |
} |
} |
907 |
|
|
908 |
/* Load an ELF image into the simulated memory */ |
/* Load an ELF image into the simulated memory */ |
909 |
int mips64_load_elf_image(cpu_mips_t *cpu,char *filename, |
int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load, |
910 |
m_uint32_t *entry_point) |
m_uint32_t *entry_point) |
911 |
{ |
{ |
912 |
m_uint64_t vaddr; |
m_uint64_t vaddr; |
913 |
|
m_uint32_t remain; |
914 |
void *haddr; |
void *haddr; |
915 |
Elf32_Ehdr *ehdr; |
Elf32_Ehdr *ehdr; |
916 |
Elf32_Shdr *shdr; |
Elf32_Shdr *shdr; |
959 |
return(-1); |
return(-1); |
960 |
} |
} |
961 |
|
|
962 |
for(i=0;i<ehdr->e_shnum;i++) { |
if (!skip_load) { |
963 |
scn = elf_getscn(img_elf,i); |
for(i=0;i<ehdr->e_shnum;i++) { |
964 |
|
scn = elf_getscn(img_elf,i); |
965 |
|
|
966 |
|
shdr = elf32_getshdr(scn); |
967 |
|
name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name); |
968 |
|
len = shdr->sh_size; |
969 |
|
|
970 |
|
if (!(shdr->sh_flags & SHF_ALLOC) || !len) |
971 |
|
continue; |
972 |
|
|
973 |
|
fseek(bfd,shdr->sh_offset,SEEK_SET); |
974 |
|
vaddr = sign_extend(shdr->sh_addr,32); |
975 |
|
|
976 |
|
if (cpu->vm->debug_level > 0) { |
977 |
|
printf(" * Adding section at virtual address 0x%8.8llx " |
978 |
|
"(len=0x%8.8lx)\n",vaddr & 0xFFFFFFFF,(u_long)len); |
979 |
|
} |
980 |
|
|
981 |
|
while(len > 0) |
982 |
|
{ |
983 |
|
haddr = cpu->mem_op_lookup(cpu,vaddr); |
984 |
|
|
985 |
|
if (!haddr) { |
986 |
|
fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n", |
987 |
|
vaddr); |
988 |
|
return(-1); |
989 |
|
} |
990 |
|
|
991 |
shdr = elf32_getshdr(scn); |
if (len > MIPS_MIN_PAGE_SIZE) |
992 |
name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name); |
clen = MIPS_MIN_PAGE_SIZE; |
993 |
len = shdr->sh_size; |
else |
994 |
|
clen = len; |
995 |
|
|
996 |
if (!(shdr->sh_flags & SHF_ALLOC) || !len) |
remain = PPC32_MIN_PAGE_SIZE; |
997 |
continue; |
remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK)); |
998 |
|
|
999 |
fseek(bfd,shdr->sh_offset,SEEK_SET); |
clen = m_min(clen,remain); |
|
vaddr = sign_extend(shdr->sh_addr,32); |
|
1000 |
|
|
1001 |
if (cpu->vm->debug_level > 0) { |
if (fread((u_char *)haddr,clen,1,bfd) < 1) |
1002 |
printf(" * Adding section at virtual address 0x%8.8llx " |
break; |
|
"(len=0x%8.8lx)\n",vaddr & 0xFFFFFFFF,(u_long)len); |
|
|
} |
|
1003 |
|
|
1004 |
while(len > 0) |
vaddr += clen; |
1005 |
{ |
len -= clen; |
|
haddr = cpu->mem_op_lookup(cpu,vaddr); |
|
|
|
|
|
if (!haddr) { |
|
|
fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n", |
|
|
vaddr); |
|
|
return(-1); |
|
1006 |
} |
} |
|
|
|
|
if (len > MIPS_MIN_PAGE_SIZE) |
|
|
clen = MIPS_MIN_PAGE_SIZE; |
|
|
else |
|
|
clen = len; |
|
|
|
|
|
clen = fread((u_char *)haddr,clen,1,bfd); |
|
|
|
|
|
if (clen != 1) |
|
|
break; |
|
|
|
|
|
vaddr += MIPS_MIN_PAGE_SIZE; |
|
|
len -= clen; |
|
1007 |
} |
} |
1008 |
|
} else { |
1009 |
|
printf("ELF loading skipped, using a ghost RAM file.\n"); |
1010 |
} |
} |
1011 |
|
|
1012 |
printf("ELF entry point: 0x%x\n",ehdr->e_entry); |
printf("ELF entry point: 0x%x\n",ehdr->e_entry); |
1078 |
FILE *fd; |
FILE *fd; |
1079 |
|
|
1080 |
if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) { |
if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) { |
1081 |
fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->id); |
fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->gen->id); |
1082 |
return(-1); |
return(-1); |
1083 |
} |
} |
1084 |
|
|