/[dynamips]/trunk/mips64.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (show annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
Original Path: upstream/dynamips-0.2.7-RC1/mips64.c
File MIME type: text/plain
File size: 26590 byte(s)
dynamips-0.2.7-RC1

1 /*
2 * Cisco router simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * XXX TODO: proper context save/restore for CPUs.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <sys/mman.h>
15 #include <fcntl.h>
16 #include <assert.h>
17
18 #include "rbtree.h"
19 #include "cpu.h"
20 #include "mips64_mem.h"
21 #include "mips64_exec.h"
22 #include "mips64_jit.h"
23 #include "dynamips.h"
24 #include "memory.h"
25 #include "device.h"
26
27 /* MIPS general purpose registers names */
28 char *mips64_gpr_reg_names[MIPS64_GPR_NR] = {
29 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3",
30 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
31 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
32 "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra",
33 };
34
35 /* Cacheability and Coherency Attribute */
36 static int cca_cache_status[8] = {
37 1, 1, 0, 1, 0, 1, 0, 0,
38 };
39
40 /* Get register index given its name */
41 int mips64_get_reg_index(char *name)
42 {
43 int i;
44
45 for(i=0;i<MIPS64_GPR_NR;i++)
46 if (!strcmp(mips64_gpr_reg_names[i],name))
47 return(i);
48
49 return(-1);
50 }
51
52 /* Get cacheability info */
53 int mips64_cca_cached(m_uint8_t val)
54 {
55 return(cca_cache_status[val & 0x03]);
56 }
57
58 /* Reset a MIPS64 CPU */
59 int mips64_reset(cpu_mips_t *cpu)
60 {
61 cpu->pc = MIPS_ROM_PC;
62 cpu->gpr[MIPS_GPR_SP] = MIPS_ROM_SP;
63 cpu->cp0.reg[MIPS_CP0_STATUS] = MIPS_CP0_STATUS_BEV;
64 cpu->cp0.reg[MIPS_CP0_CAUSE] = 0;
65 cpu->cp0.reg[MIPS_CP0_CONFIG] = 0x00c08ff0ULL;
66
67 /* Clear the complete TLB */
68 memset(&cpu->cp0.tlb,0,MIPS64_TLB_MAX_ENTRIES*sizeof(tlb_entry_t));
69
70 /* Restart the MTS subsystem */
71 mips64_set_addr_mode(cpu,64);
72 cpu->gen->mts_rebuild(cpu->gen);
73
74 /* Flush JIT structures */
75 mips64_jit_flush(cpu,0);
76 return(0);
77 }
78
79 /* Initialize a MIPS64 processor */
80 int mips64_init(cpu_mips_t *cpu)
81 {
82 cpu->addr_bus_mask = 0xFFFFFFFFFFFFFFFFULL;
83 cpu->cp0.reg[MIPS_CP0_PRID] = MIPS_PRID_R4600;
84 cpu->cp0.tlb_entries = MIPS64_TLB_STD_ENTRIES;
85
86 /* Initialize idle timer */
87 cpu->gen->idle_max = 1500;
88 cpu->gen->idle_sleep_time = 30000;
89
90 /* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */
91 cpu->timer_irq_check_itv = 1000;
92 cpu->timer_irq_freq = 250;
93
94 /* Enable fast memory operations */
95 cpu->fast_memop = TRUE;
96
97 /* Create the IRQ lock (for non-jit architectures) */
98 pthread_mutex_init(&cpu->irq_lock,NULL);
99
100 /* Idle loop mutex and condition */
101 pthread_mutex_init(&cpu->gen->idle_mutex,NULL);
102 pthread_cond_init(&cpu->gen->idle_cond,NULL);
103
104 /* Set the CPU methods */
105 cpu->gen->reg_set = (void *)mips64_reg_set;
106 cpu->gen->reg_dump = (void *)mips64_dump_regs;
107 cpu->gen->mmu_dump = (void *)mips64_tlb_dump;
108 cpu->gen->mmu_raw_dump = (void *)mips64_tlb_raw_dump;
109 cpu->gen->add_breakpoint = (void *)mips64_add_breakpoint;
110 cpu->gen->remove_breakpoint = (void *)mips64_remove_breakpoint;
111 cpu->gen->set_idle_pc = (void *)mips64_set_idle_pc;
112 cpu->gen->get_idling_pc = (void *)mips64_get_idling_pc;
113
114 /* Set the startup parameters */
115 mips64_reset(cpu);
116 return(0);
117 }
118
119 /* Delete a MIPS64 processor */
120 void mips64_delete(cpu_mips_t *cpu)
121 {
122 if (cpu) {
123 mips64_mem_shutdown(cpu);
124 mips64_jit_shutdown(cpu);
125 }
126 }
127
128 /* Set the CPU PRID register */
129 void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid)
130 {
131 cpu->cp0.reg[MIPS_CP0_PRID] = prid;
132
133 if ((prid == MIPS_PRID_R7000) || (prid == MIPS_PRID_BCM1250))
134 cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES;
135 }
136
137 /* Set idle PC value */
138 void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr)
139 {
140 CPU_MIPS64(cpu)->idle_pc = addr;
141 }
142
143 /* Timer IRQ */
144 void *mips64_timer_irq_run(cpu_mips_t *cpu)
145 {
146 pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;
147 pthread_cond_t ucond = PTHREAD_COND_INITIALIZER;
148 struct timespec t_spc;
149 m_tmcnt_t expire;
150 u_int interval;
151 u_int threshold;
152
153 interval = 1000000 / cpu->timer_irq_freq;
154 threshold = cpu->timer_irq_freq * 10;
155 expire = m_gettime_usec() + interval;
156
157 while(cpu->gen->state != CPU_STATE_HALTED) {
158 pthread_mutex_lock(&umutex);
159 t_spc.tv_sec = expire / 1000000;
160 t_spc.tv_nsec = (expire % 1000000) * 1000;
161 pthread_cond_timedwait(&ucond,&umutex,&t_spc);
162 pthread_mutex_unlock(&umutex);
163
164 if (likely(!cpu->irq_disable) &&
165 likely(cpu->gen->state == CPU_STATE_RUNNING))
166 {
167 cpu->timer_irq_pending++;
168
169 if (unlikely(cpu->timer_irq_pending > threshold)) {
170 cpu->timer_irq_pending = 0;
171 cpu->timer_drift++;
172 #if 0
173 printf("Timer IRQ not accurate (%u pending IRQ): "
174 "reduce the \"--timer-irq-check-itv\" parameter "
175 "(current value: %u)\n",
176 cpu->timer_irq_pending,cpu->timer_irq_check_itv);
177 #endif
178 }
179 }
180
181 expire += interval;
182 }
183
184 return NULL;
185 }
186
187 #define IDLE_HASH_SIZE 8192
188
189 /* Idle PC hash item */
190 struct mips64_idle_pc_hash {
191 m_uint64_t pc;
192 u_int count;
193 struct mips64_idle_pc_hash *next;
194 };
195
196 /* Determine an "idling" PC */
197 int mips64_get_idling_pc(cpu_gen_t *cpu)
198 {
199 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
200 struct mips64_idle_pc_hash **pc_hash,*p;
201 struct cpu_idle_pc *res;
202 u_int h_index,res_count;
203 m_uint64_t cur_pc;
204 int i;
205
206 cpu->idle_pc_prop_count = 0;
207
208 if (mcpu->idle_pc != 0) {
209 printf("\nYou already use an idle PC, using the calibration would give "
210 "incorrect results.\n");
211 return(-1);
212 }
213
214 printf("\nPlease wait while gathering statistics...\n");
215
216 pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *));
217
218 /* Disable IRQ */
219 mcpu->irq_disable = TRUE;
220
221 /* Take 1000 measures, each mesure every 10ms */
222 for(i=0;i<1000;i++) {
223 cur_pc = mcpu->pc;
224 h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1);
225
226 for(p=pc_hash[h_index];p;p=p->next)
227 if (p->pc == cur_pc) {
228 p->count++;
229 break;
230 }
231
232 if (!p) {
233 if ((p = malloc(sizeof(*p)))) {
234 p->pc = cur_pc;
235 p->count = 1;
236 p->next = pc_hash[h_index];
237 pc_hash[h_index] = p;
238 }
239 }
240
241 usleep(10000);
242 }
243
244 /* Select PCs */
245 for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) {
246 for(p=pc_hash[i];p;p=p->next)
247 if ((p->count >= 20) && (p->count <= 80)) {
248 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
249
250 res->pc = p->pc;
251 res->count = p->count;
252
253 if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)
254 goto done;
255 }
256 }
257
258 done:
259 /* Set idle PC */
260 if (cpu->idle_pc_prop_count) {
261 printf("Done. Suggested idling PC:\n");
262
263 for(i=0;i<cpu->idle_pc_prop_count;i++) {
264 printf(" 0x%llx (count=%u)\n",
265 cpu->idle_pc_prop[i].pc,
266 cpu->idle_pc_prop[i].count);
267 }
268
269 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
270 cpu->idle_pc_prop[0].pc);
271 } else {
272 printf("Done. No suggestion for idling PC\n");
273 }
274
275 /* Re-enable IRQ */
276 mcpu->irq_disable = FALSE;
277 return(0);
278 }
279
280 /* Set an IRQ (VM IRQ standard routing) */
281 void mips64_vm_set_irq(vm_instance_t *vm,u_int irq)
282 {
283 cpu_mips_t *boot_cpu;
284
285 boot_cpu = CPU_MIPS64(vm->boot_cpu);
286
287 if (boot_cpu->irq_disable) {
288 boot_cpu->irq_pending = 0;
289 return;
290 }
291
292 mips64_set_irq(boot_cpu,irq);
293
294 if (boot_cpu->irq_idle_preempt[irq])
295 cpu_idle_break_wait(vm->boot_cpu);
296 }
297
298 /* Clear an IRQ (VM IRQ standard routing) */
299 void mips64_vm_clear_irq(vm_instance_t *vm,u_int irq)
300 {
301 cpu_mips_t *boot_cpu;
302
303 boot_cpu = CPU_MIPS64(vm->boot_cpu);
304 mips64_clear_irq(boot_cpu,irq);
305 }
306
307 /* Update the IRQ flag (inline) */
308 static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu)
309 {
310 mips_cp0_t *cp0 = &cpu->cp0;
311 m_uint32_t imask,sreg_mask;
312 m_uint32_t cause;
313
314 cpu->irq_pending = FALSE;
315
316 cause = cp0->reg[MIPS_CP0_CAUSE] & ~MIPS_CP0_CAUSE_IMASK;
317 cp0->reg[MIPS_CP0_CAUSE] = cause | cpu->irq_cause;
318
319 sreg_mask = MIPS_CP0_STATUS_IE|MIPS_CP0_STATUS_EXL|MIPS_CP0_STATUS_ERL;
320
321 if ((cp0->reg[MIPS_CP0_STATUS] & sreg_mask) == MIPS_CP0_STATUS_IE) {
322 imask = cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IMASK;
323 if (unlikely(cp0->reg[MIPS_CP0_CAUSE] & imask)) {
324 cpu->irq_pending = TRUE;
325 return(TRUE);
326 }
327 }
328
329 return(FALSE);
330 }
331
332 /* Update the IRQ flag */
333 void mips64_update_irq_flag(cpu_mips_t *cpu)
334 {
335 mips64_update_irq_flag_fast(cpu);
336 }
337
338 /* Generate an exception */
339 void mips64_trigger_exception(cpu_mips_t *cpu,u_int exc_code,int bd_slot)
340 {
341 mips_cp0_t *cp0 = &cpu->cp0;
342 m_uint64_t cause,vector;
343
344 /* we don't set EPC if EXL is set */
345 if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))
346 {
347 cp0->reg[MIPS_CP0_EPC] = cpu->pc;
348
349 /* keep IM, set exception code and bd slot */
350 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
351
352 if (bd_slot)
353 cause |= MIPS_CP0_CAUSE_BD_SLOT;
354 else
355 cause &= ~MIPS_CP0_CAUSE_BD_SLOT;
356
357 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
358 cp0->reg[MIPS_CP0_CAUSE] = cause;
359
360 /* XXX properly set vector */
361 vector = 0x180ULL;
362 }
363 else
364 {
365 /* keep IM and set exception code */
366 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
367 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
368 cp0->reg[MIPS_CP0_CAUSE] = cause;
369
370 /* set vector */
371 vector = 0x180ULL;
372 }
373
374 /* Set EXL bit in status register */
375 cp0->reg[MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_EXL;
376
377 /* Use bootstrap vectors ? */
378 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_BEV)
379 cpu->pc = 0xffffffffbfc00200ULL + vector;
380 else
381 cpu->pc = 0xffffffff80000000ULL + vector;
382
383 /* Clear the pending IRQ flag */
384 cpu->irq_pending = 0;
385 }
386
387 /*
388 * Increment count register and trigger the timer IRQ if value in compare
389 * register is the same.
390 */
391 fastcall void mips64_exec_inc_cp0_cnt(cpu_mips_t *cpu)
392 {
393 cpu->cp0_virt_cnt_reg++;
394
395 #if 0 /* TIMER_IRQ */
396 mips_cp0_t *cp0 = &cpu->cp0;
397
398 if (unlikely((cpu->cp0_virt_cnt_reg == cpu->cp0_virt_cmp_reg))) {
399 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
400 mips64_set_irq(cpu,7);
401 mips64_update_irq_flag_fast(cpu);
402 }
403 #endif
404 }
405
406 /* Trigger the Timer IRQ */
407 fastcall void mips64_trigger_timer_irq(cpu_mips_t *cpu)
408 {
409 mips_cp0_t *cp0 = &cpu->cp0;
410
411 cpu->timer_irq_count++;
412
413 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
414 mips64_set_irq(cpu,7);
415 mips64_update_irq_flag_fast(cpu);
416 }
417
418 /* Execute ERET instruction */
419 fastcall void mips64_exec_eret(cpu_mips_t *cpu)
420 {
421 mips_cp0_t *cp0 = &cpu->cp0;
422
423 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_ERL) {
424 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL;
425 cpu->pc = cp0->reg[MIPS_CP0_ERR_EPC];
426 } else {
427 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_EXL;
428 cpu->pc = cp0->reg[MIPS_CP0_EPC];
429 }
430
431 /* We have to clear the LLbit */
432 cpu->ll_bit = 0;
433
434 /* Update the pending IRQ flag */
435 mips64_update_irq_flag_fast(cpu);
436 }
437
438 /* Execute SYSCALL instruction */
439 fastcall void mips64_exec_syscall(cpu_mips_t *cpu)
440 {
441 #if DEBUG_SYSCALL
442 printf("MIPS64: SYSCALL at PC=0x%llx (RA=0x%llx)\n"
443 " a0=0x%llx, a1=0x%llx, a2=0x%llx, a3=0x%llx\n",
444 cpu->pc, cpu->gpr[MIPS_GPR_RA],
445 cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],
446 cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);
447 #endif
448
449 /* XXX TODO: Branch Delay slot */
450 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_SYSCALL,0);
451 }
452
453 /* Execute BREAK instruction */
454 fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code)
455 {
456 printf("MIPS64: BREAK instruction (code=%u)\n",code);
457 mips64_dump_regs(cpu->gen);
458
459 /* XXX TODO: Branch Delay slot */
460 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0);
461 }
462
463 /* Trigger a Trap Exception */
464 fastcall void mips64_trigger_trap_exception(cpu_mips_t *cpu)
465 {
466 /* XXX TODO: Branch Delay slot */
467 printf("MIPS64: TRAP exception, CPU=%p\n",cpu);
468 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_TRAP,0);
469 }
470
471 /* Trigger IRQs */
472 fastcall void mips64_trigger_irq(cpu_mips_t *cpu)
473 {
474 if (unlikely(cpu->irq_disable)) {
475 cpu->irq_pending = 0;
476 return;
477 }
478
479 cpu->irq_count++;
480 if (mips64_update_irq_flag_fast(cpu))
481 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_INTERRUPT,0);
482 else
483 cpu->irq_fp_count++;
484 }
485
486 /* DMFC1 */
487 fastcall void mips64_exec_dmfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
488 {
489 cpu->gpr[gp_reg] = cpu->fpu.reg[cp1_reg];
490 }
491
492 /* DMTC1 */
493 fastcall void mips64_exec_dmtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
494 {
495 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg];
496 }
497
498 /* MFC1 */
499 fastcall void mips64_exec_mfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
500 {
501 m_int64_t val;
502
503 val = cpu->fpu.reg[cp1_reg] & 0xffffffff;
504 cpu->gpr[gp_reg] = sign_extend(val,32);
505 }
506
507 /* MTC1 */
508 fastcall void mips64_exec_mtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
509 {
510 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg] & 0xffffffff;
511 }
512
513 /* Virtual breakpoint */
514 fastcall void mips64_run_breakpoint(cpu_mips_t *cpu)
515 {
516 cpu_log(cpu->gen,"BREAKPOINT",
517 "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);
518
519 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
520 cpu->pc,cpu->gpr[MIPS_GPR_RA]);
521
522 mips64_dump_regs(cpu->gen);
523 memlog_dump(cpu->gen);
524 }
525
526 /* Add a virtual breakpoint */
527 int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
528 {
529 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
530 int i;
531
532 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
533 if (!mcpu->breakpoints[i])
534 break;
535
536 if (i == MIPS64_MAX_BREAKPOINTS)
537 return(-1);
538
539 mcpu->breakpoints[i] = pc;
540 mcpu->breakpoints_enabled = TRUE;
541 return(0);
542 }
543
544 /* Remove a virtual breakpoint */
545 void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
546 {
547 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
548 int i,j;
549
550 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
551 if (mcpu->breakpoints[i] == pc)
552 {
553 for(j=i;j<MIPS64_MAX_BREAKPOINTS-1;j++)
554 mcpu->breakpoints[j] = mcpu->breakpoints[j+1];
555
556 mcpu->breakpoints[MIPS64_MAX_BREAKPOINTS-1] = 0;
557 }
558
559 for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
560 if (mcpu->breakpoints[i] != 0)
561 return;
562
563 mcpu->breakpoints_enabled = FALSE;
564 }
565
566 /* Debugging for register-jump to address 0 */
567 fastcall void mips64_debug_jr0(cpu_mips_t *cpu)
568 {
569 printf("MIPS64: cpu %p jumping to address 0...\n",cpu);
570 mips64_dump_regs(cpu->gen);
571 }
572
573 /* Set a register */
574 void mips64_reg_set(cpu_gen_t *cpu,u_int reg,m_uint64_t val)
575 {
576 if (reg < MIPS64_GPR_NR)
577 CPU_MIPS64(cpu)->gpr[reg] = val;
578 }
579
580 /* Dump registers of a MIPS64 processor */
581 void mips64_dump_regs(cpu_gen_t *cpu)
582 {
583 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
584 mips_insn_t *ptr,insn;
585 char buffer[80];
586 int i;
587
588 printf("MIPS64 Registers:\n");
589
590 for(i=0;i<MIPS64_GPR_NR/2;i++) {
591 printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n",
592 mips64_gpr_reg_names[i*2], i*2, mcpu->gpr[i*2],
593 mips64_gpr_reg_names[(i*2)+1], (i*2)+1, mcpu->gpr[(i*2)+1]);
594 }
595
596 printf(" lo = 0x%16.16llx, hi = 0x%16.16llx\n", mcpu->lo, mcpu->hi);
597 printf(" pc = 0x%16.16llx, ll_bit = %u\n", mcpu->pc, mcpu->ll_bit);
598
599 /* Fetch the current instruction */
600 ptr = mcpu->mem_op_lookup(mcpu,mcpu->pc);
601 if (ptr) {
602 insn = vmtoh32(*ptr);
603
604 if (mips64_dump_insn(buffer,sizeof(buffer),1,mcpu->pc,insn) != -1)
605 printf(" Instruction: %s\n",buffer);
606 }
607
608 printf("\nCP0 Registers:\n");
609
610 for(i=0;i<MIPS64_CP0_REG_NR/2;i++) {
611 printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n",
612 mips64_cp0_reg_names[i*2], i*2,
613 mips64_cp0_get_reg(mcpu,i*2),
614 mips64_cp0_reg_names[(i*2)+1], (i*2)+1,
615 mips64_cp0_get_reg(mcpu,(i*2)+1));
616 }
617
618 printf("\n IRQ count: %llu, IRQ false positives: %llu, "
619 "IRQ Pending: %u\n",
620 mcpu->irq_count,mcpu->irq_fp_count,mcpu->irq_pending);
621
622 printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
623 mcpu->timer_irq_count,mcpu->timer_irq_pending,mcpu->timer_drift);
624
625 printf("\n");
626 }
627
628 /* Dump a memory block */
629 void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count)
630 {
631 void *haddr;
632 u_int i;
633
634 for(i=0;i<count;i++,vaddr+=4)
635 {
636 if ((i & 3) == 0)
637 printf("\n 0x%16.16llx: ",vaddr);
638
639 haddr = cpu->mem_op_lookup(cpu,vaddr);
640
641 if (haddr)
642 printf("0x%8.8x ",htovm32(*(m_uint32_t *)haddr));
643 else
644 printf("XXXXXXXXXX ");
645 }
646
647 printf("\n\n");
648 }
649
650 /* Dump the stack */
651 void mips64_dump_stack(cpu_mips_t *cpu,u_int count)
652 {
653 printf("MIPS Stack Dump at 0x%16.16llx:",cpu->gpr[MIPS_GPR_SP]);
654 mips64_dump_memory(cpu,cpu->gpr[MIPS_GPR_SP],count);
655 }
656
657 /* Save the CPU state into a file */
658 int mips64_save_state(cpu_mips_t *cpu,char *filename)
659 {
660 FILE *fd;
661 int i;
662
663 if (!(fd = fopen(filename,"w"))) {
664 perror("mips64_save_state: fopen");
665 return(-1);
666 }
667
668 /* pc, lo and hi */
669 fprintf(fd,"pc: %16.16llx\n",cpu->pc);
670 fprintf(fd,"lo: %16.16llx\n",cpu->lo);
671 fprintf(fd,"hi: %16.16llx\n",cpu->hi);
672
673 /* general purpose registers */
674 for(i=0;i<MIPS64_GPR_NR;i++)
675 fprintf(fd,"%s: %16.16llx\n",
676 mips64_gpr_reg_names[i],cpu->gpr[i]);
677
678 printf("\n");
679
680 /* cp0 registers */
681 for(i=0;i<MIPS64_CP0_REG_NR;i++)
682 fprintf(fd,"%s: %16.16llx\n",
683 mips64_cp0_reg_names[i],cpu->cp0.reg[i]);
684
685 printf("\n");
686
687 /* cp1 registers */
688 for(i=0;i<MIPS64_CP1_REG_NR;i++)
689 fprintf(fd,"fpu%d: %16.16llx\n",i,cpu->fpu.reg[i]);
690
691 printf("\n");
692
693 /* tlb entries */
694 for(i=0;i<cpu->cp0.tlb_entries;i++) {
695 fprintf(fd,"tlb%d_mask: %16.16llx\n",i,cpu->cp0.tlb[i].mask);
696 fprintf(fd,"tlb%d_hi: %16.16llx\n",i,cpu->cp0.tlb[i].hi);
697 fprintf(fd,"tlb%d_lo0: %16.16llx\n",i,cpu->cp0.tlb[i].lo0);
698 fprintf(fd,"tlb%d_lo1: %16.16llx\n",i,cpu->cp0.tlb[i].lo1);
699 }
700
701 fclose(fd);
702 return(0);
703 }
704
705 /* Read a 64-bit unsigned integer */
706 static m_uint64_t mips64_hex_u64(char *str,int *err)
707 {
708 m_uint64_t res = 0;
709 u_char c;
710
711 /* remove leading spaces */
712 while((*str == ' ') || (*str == '\t'))
713 str++;
714
715 while(*str) {
716 c = *str;
717
718 if ((c >= '0') && (c <= '9'))
719 res = (res << 4) + (c - '0');
720
721 if ((c >= 'a') && (c <= 'f'))
722 res = (res << 4) + ((c - 'a') + 10);
723
724 if ((c >= 'A') && (c <= 'F'))
725 res = (res << 4) + ((c - 'A') + 10);
726
727 str++;
728 }
729
730 return(res);
731 }
732
733 /* Restore the CPU state from a file */
734 int mips64_restore_state(cpu_mips_t *cpu,char *filename)
735 {
736 char buffer[4096],*sep,*value,*ep,*field;
737 size_t len;
738 FILE *fd;
739 int index;
740
741 if (!(fd = fopen(filename,"r"))) {
742 perror("mips64_restore_state: fopen");
743 return(-1);
744 }
745
746 while(!feof(fd))
747 {
748 *buffer = 0;
749 fgets(buffer,sizeof(buffer),fd);
750 len = strlen(buffer);
751
752 if (buffer[len-1] == '\n')
753 buffer[len-1] = 0;
754
755 sep = strchr(buffer,':');
756 if (!sep) continue;
757
758 value = sep + 1;
759 *sep = 0;
760
761 /* gpr ? */
762 if ((index = mips64_get_reg_index(buffer)) != -1) {
763 cpu->gpr[index] = mips64_hex_u64(value,NULL);
764 continue;
765 }
766
767 /* cp0 register ? */
768 if ((index = mips64_cp0_get_reg_index(buffer)) != -1) {
769 cpu->cp0.reg[index] = mips64_hex_u64(value,NULL);
770 continue;
771 }
772
773 /* cp1 register ? */
774 if ((len > 3) && (!strncmp(buffer,"fpu",3))) {
775 index = atoi(buffer+3);
776 cpu->fpu.reg[index] = mips64_hex_u64(value,NULL);
777 }
778
779 /* tlb entry ? */
780 if ((len > 3) && (!strncmp(buffer,"tlb",3))) {
781 ep = strchr(buffer,'_');
782
783 if (ep) {
784 index = atoi(buffer+3);
785 field = ep + 1;
786
787 if (!strcmp(field,"mask")) {
788 cpu->cp0.tlb[index].mask = mips64_hex_u64(value,NULL);
789 continue;
790 }
791
792 if (!strcmp(field,"hi")) {
793 cpu->cp0.tlb[index].hi = mips64_hex_u64(value,NULL);
794 continue;
795 }
796
797 if (!strcmp(field,"lo0")) {
798 cpu->cp0.tlb[index].lo0 = mips64_hex_u64(value,NULL);
799 continue;
800 }
801
802 if (!strcmp(field,"lo1")) {
803 cpu->cp0.tlb[index].lo1 = mips64_hex_u64(value,NULL);
804 continue;
805 }
806 }
807 }
808
809 /* pc, lo, hi ? */
810 if (!strcmp(buffer,"pc")) {
811 cpu->pc = mips64_hex_u64(value,NULL);
812 continue;
813 }
814
815 if (!strcmp(buffer,"lo")) {
816 cpu->lo = mips64_hex_u64(value,NULL);
817 continue;
818 }
819
820 if (!strcmp(buffer,"hi")) {
821 cpu->hi = mips64_hex_u64(value,NULL);
822 continue;
823 }
824 }
825
826 mips64_cp0_map_all_tlb_to_mts(cpu);
827
828 mips64_dump_regs(cpu->gen);
829 mips64_tlb_dump(cpu->gen);
830
831 fclose(fd);
832 return(0);
833 }
834
835 /* Load a raw image into the simulated memory */
836 int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr)
837 {
838 struct stat file_info;
839 size_t len,clen;
840 m_uint32_t remain;
841 void *haddr;
842 FILE *bfd;
843
844 if (!(bfd = fopen(filename,"r"))) {
845 perror("fopen");
846 return(-1);
847 }
848
849 if (fstat(fileno(bfd),&file_info) == -1) {
850 perror("stat");
851 return(-1);
852 }
853
854 len = file_info.st_size;
855
856 printf("Loading RAW file '%s' at virtual address 0x%llx (size=%lu)\n",
857 filename,vaddr,(u_long)len);
858
859 while(len > 0)
860 {
861 haddr = cpu->mem_op_lookup(cpu,vaddr);
862
863 if (!haddr) {
864 fprintf(stderr,"load_raw_image: invalid load address 0x%llx\n",
865 vaddr);
866 return(-1);
867 }
868
869 if (len > MIPS_MIN_PAGE_SIZE)
870 clen = MIPS_MIN_PAGE_SIZE;
871 else
872 clen = len;
873
874 remain = MIPS_MIN_PAGE_SIZE;
875 remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_MASK));
876
877 clen = m_min(clen,remain);
878
879 if (fread((u_char *)haddr,clen,1,bfd) != 1)
880 break;
881
882 vaddr += clen;
883 len -= clen;
884 }
885
886 fclose(bfd);
887 return(0);
888 }
889
890 /* Load an ELF image into the simulated memory */
891 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
892 m_uint32_t *entry_point)
893 {
894 m_uint64_t vaddr;
895 m_uint32_t remain;
896 void *haddr;
897 Elf32_Ehdr *ehdr;
898 Elf32_Shdr *shdr;
899 Elf_Scn *scn;
900 Elf *img_elf;
901 size_t len,clen;
902 char *name;
903 int i,fd;
904 FILE *bfd;
905
906 if (!filename)
907 return(-1);
908
909 #ifdef __CYGWIN__
910 fd = open(filename,O_RDONLY|O_BINARY);
911 #else
912 fd = open(filename,O_RDONLY);
913 #endif
914
915 if (fd == -1) {
916 perror("load_elf_image: open");
917 return(-1);
918 }
919
920 if (elf_version(EV_CURRENT) == EV_NONE) {
921 fprintf(stderr,"load_elf_image: library out of date\n");
922 return(-1);
923 }
924
925 if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) {
926 fprintf(stderr,"load_elf_image: elf_begin: %s\n",
927 elf_errmsg(elf_errno()));
928 return(-1);
929 }
930
931 if (!(ehdr = elf32_getehdr(img_elf))) {
932 fprintf(stderr,"load_elf_image: invalid ELF file\n");
933 return(-1);
934 }
935
936 printf("Loading ELF file '%s'...\n",filename);
937 bfd = fdopen(fd,"rb");
938
939 if (!bfd) {
940 perror("load_elf_image: fdopen");
941 return(-1);
942 }
943
944 if (!skip_load) {
945 for(i=0;i<ehdr->e_shnum;i++) {
946 scn = elf_getscn(img_elf,i);
947
948 shdr = elf32_getshdr(scn);
949 name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
950 len = shdr->sh_size;
951
952 if (!(shdr->sh_flags & SHF_ALLOC) || !len)
953 continue;
954
955 fseek(bfd,shdr->sh_offset,SEEK_SET);
956 vaddr = sign_extend(shdr->sh_addr,32);
957
958 if (cpu->vm->debug_level > 0) {
959 printf(" * Adding section at virtual address 0x%8.8llx "
960 "(len=0x%8.8lx)\n",vaddr & 0xFFFFFFFF,(u_long)len);
961 }
962
963 while(len > 0)
964 {
965 haddr = cpu->mem_op_lookup(cpu,vaddr);
966
967 if (!haddr) {
968 fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
969 vaddr);
970 return(-1);
971 }
972
973 if (len > MIPS_MIN_PAGE_SIZE)
974 clen = MIPS_MIN_PAGE_SIZE;
975 else
976 clen = len;
977
978 remain = PPC32_MIN_PAGE_SIZE;
979 remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK));
980
981 clen = m_min(clen,remain);
982
983 if (fread((u_char *)haddr,clen,1,bfd) < 1)
984 break;
985
986 vaddr += clen;
987 len -= clen;
988 }
989 }
990 } else {
991 printf("ELF loading skipped, using a ghost RAM file.\n");
992 }
993
994 printf("ELF entry point: 0x%x\n",ehdr->e_entry);
995
996 if (entry_point)
997 *entry_point = ehdr->e_entry;
998
999 elf_end(img_elf);
1000 fclose(bfd);
1001 return(0);
1002 }
1003
1004 /* Symbol lookup */
1005 struct symbol *mips64_sym_lookup(cpu_mips_t *cpu,m_uint64_t addr)
1006 {
1007 return(rbtree_lookup(cpu->sym_tree,&addr));
1008 }
1009
1010 /* Insert a new symbol */
1011 struct symbol *mips64_sym_insert(cpu_mips_t *cpu,char *name,m_uint64_t addr)
1012 {
1013 struct symbol *sym;
1014 size_t len;
1015
1016 if (!cpu->sym_tree)
1017 return NULL;
1018
1019 len = strlen(name);
1020
1021 if (!(sym = malloc(len+1+sizeof(*sym))))
1022 return NULL;
1023
1024 memcpy(sym->name,name,len+1);
1025 sym->addr = addr;
1026
1027 if (rbtree_insert(cpu->sym_tree,sym,sym) == -1) {
1028 free(sym);
1029 return NULL;
1030 }
1031
1032 return sym;
1033 }
1034
1035 /* Symbol comparison function */
1036 static int mips64_sym_compare(m_uint64_t *a1,struct symbol *sym)
1037 {
1038 if (*a1 > sym->addr)
1039 return(1);
1040
1041 if (*a1 < sym->addr)
1042 return(-1);
1043
1044 return(0);
1045 }
1046
1047 /* Create the symbol tree */
1048 int mips64_sym_create_tree(cpu_mips_t *cpu)
1049 {
1050 cpu->sym_tree = rbtree_create((tree_fcompare)mips64_sym_compare,NULL);
1051 return(cpu->sym_tree ? 0 : -1);
1052 }
1053
1054 /* Load a symbol file */
1055 int mips64_sym_load_file(cpu_mips_t *cpu,char *filename)
1056 {
1057 char buffer[4096],func_name[128];
1058 m_uint64_t addr;
1059 char sym_type;
1060 FILE *fd;
1061
1062 if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) {
1063 fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->gen->id);
1064 return(-1);
1065 }
1066
1067 if (!(fd = fopen(filename,"r"))) {
1068 perror("load_sym_file: fopen");
1069 return(-1);
1070 }
1071
1072 while(!feof(fd)) {
1073 fgets(buffer,sizeof(buffer),fd);
1074
1075 if (sscanf(buffer,"%llx %c %s",&addr,&sym_type,func_name) == 3) {
1076 mips64_sym_insert(cpu,func_name,addr);
1077 }
1078 }
1079
1080 fclose(fd);
1081 return(0);
1082 }

  ViewVC Help
Powered by ViewVC 1.1.26