/[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 12 - (show annotations)
Sat Oct 6 16:45:40 2007 UTC (11 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 27182 byte(s)
make working copy

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,32/*64*/); /* zzz */
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 /* 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) */
101 pthread_mutex_init(&cpu->irq_lock,NULL);
102
103 /* Idle loop mutex and condition */
104 pthread_mutex_init(&cpu->gen->idle_mutex,NULL);
105 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 */
118 mips64_reset(cpu);
119 return(0);
120 }
121
122 /* Delete a MIPS64 processor */
123 void mips64_delete(cpu_mips_t *cpu)
124 {
125 if (cpu) {
126 mips64_mem_shutdown(cpu);
127 mips64_jit_shutdown(cpu);
128 }
129 }
130
131 /* Set the CPU PRID register */
132 void mips64_set_prid(cpu_mips_t *cpu,m_uint32_t prid)
133 {
134 cpu->cp0.reg[MIPS_CP0_PRID] = prid;
135
136 if ((prid == MIPS_PRID_R7000) || (prid == MIPS_PRID_BCM1250))
137 cpu->cp0.tlb_entries = MIPS64_TLB_MAX_ENTRIES;
138 }
139
140 /* Set idle PC value */
141 void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr)
142 {
143 CPU_MIPS64(cpu)->idle_pc = addr;
144 }
145
146 /* Timer IRQ */
147 void *mips64_timer_irq_run(cpu_mips_t *cpu)
148 {
149 pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER;
150 pthread_cond_t ucond = PTHREAD_COND_INITIALIZER;
151 struct timespec t_spc;
152 m_tmcnt_t expire;
153 u_int interval;
154 u_int threshold;
155
156 interval = 1000000 / cpu->timer_irq_freq;
157 threshold = cpu->timer_irq_freq * 10;
158 expire = m_gettime_usec() + interval;
159
160 while(cpu->gen->state != CPU_STATE_HALTED) {
161 pthread_mutex_lock(&umutex);
162 t_spc.tv_sec = expire / 1000000;
163 t_spc.tv_nsec = (expire % 1000000) * 1000;
164 pthread_cond_timedwait(&ucond,&umutex,&t_spc);
165 pthread_mutex_unlock(&umutex);
166
167 if (likely(!cpu->irq_disable) &&
168 likely(cpu->gen->state == CPU_STATE_RUNNING))
169 {
170 cpu->timer_irq_pending++;
171
172 if (unlikely(cpu->timer_irq_pending > threshold)) {
173 cpu->timer_irq_pending = 0;
174 cpu->timer_drift++;
175 #if 0
176 printf("Timer IRQ not accurate (%u pending IRQ): "
177 "reduce the \"--timer-irq-check-itv\" parameter "
178 "(current value: %u)\n",
179 cpu->timer_irq_pending,cpu->timer_irq_check_itv);
180 #endif
181 }
182 }
183
184 expire += interval;
185 }
186
187 return NULL;
188 }
189
190 #define IDLE_HASH_SIZE 8192
191
192 /* Idle PC hash item */
193 struct mips64_idle_pc_hash {
194 m_uint64_t pc;
195 u_int count;
196 struct mips64_idle_pc_hash *next;
197 };
198
199 /* Determine an "idling" PC */
200 int mips64_get_idling_pc(cpu_gen_t *cpu)
201 {
202 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
203 struct mips64_idle_pc_hash **pc_hash,*p;
204 struct cpu_idle_pc *res;
205 u_int h_index,res_count;
206 m_uint64_t cur_pc;
207 int i;
208
209 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 "
213 "incorrect results.\n");
214 return(-1);
215 }
216
217 printf("\nPlease wait while gathering statistics...\n");
218
219 pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *));
220
221 /* Disable IRQ */
222 mcpu->irq_disable = TRUE;
223
224 /* Take 1000 measures, each mesure every 10ms */
225 for(i=0;i<1000;i++) {
226 cur_pc = mcpu->pc;
227 h_index = (cur_pc >> 2) & (IDLE_HASH_SIZE-1);
228
229 for(p=pc_hash[h_index];p;p=p->next)
230 if (p->pc == cur_pc) {
231 p->count++;
232 break;
233 }
234
235 if (!p) {
236 if ((p = malloc(sizeof(*p)))) {
237 p->pc = cur_pc;
238 p->count = 1;
239 p->next = pc_hash[h_index];
240 pc_hash[h_index] = p;
241 }
242 }
243
244 usleep(10000);
245 }
246
247 /* Select PCs */
248 for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) {
249 for(p=pc_hash[i];p;p=p->next)
250 if ((p->count >= 20) && (p->count <= 80)) {
251 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
252
253 res->pc = p->pc;
254 res->count = p->count;
255
256 if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)
257 goto done;
258 }
259 }
260
261 done:
262 /* Set idle PC */
263 if (cpu->idle_pc_prop_count) {
264 printf("Done. Suggested idling PC:\n");
265
266 for(i=0;i<cpu->idle_pc_prop_count;i++) {
267 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",
273 cpu->idle_pc_prop[0].pc);
274 } else {
275 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 */
293 mcpu->irq_disable = FALSE;
294 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) */
325 static forced_inline int mips64_update_irq_flag_fast(cpu_mips_t *cpu)
326 {
327 mips_cp0_t *cp0 = &cpu->cp0;
328 m_uint32_t imask,sreg_mask;
329 m_uint32_t cause;
330
331 cpu->irq_pending = FALSE;
332
333 cause = cp0->reg[MIPS_CP0_CAUSE] & ~MIPS_CP0_CAUSE_IMASK;
334 cp0->reg[MIPS_CP0_CAUSE] = cause | cpu->irq_cause;
335
336 sreg_mask = MIPS_CP0_STATUS_IE|MIPS_CP0_STATUS_EXL|MIPS_CP0_STATUS_ERL;
337
338 if ((cp0->reg[MIPS_CP0_STATUS] & sreg_mask) == MIPS_CP0_STATUS_IE) {
339 imask = cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_IMASK;
340 if (unlikely(cp0->reg[MIPS_CP0_CAUSE] & imask)) {
341 cpu->irq_pending = TRUE;
342 return(TRUE);
343 }
344 }
345
346 return(FALSE);
347 }
348
349 /* Update the IRQ flag */
350 void mips64_update_irq_flag(cpu_mips_t *cpu)
351 {
352 mips64_update_irq_flag_fast(cpu);
353 }
354
355 /* Generate an exception */
356 void mips64_trigger_exception(cpu_mips_t *cpu,u_int exc_code,int bd_slot)
357 {
358 mips_cp0_t *cp0 = &cpu->cp0;
359 m_uint64_t cause,vector;
360
361 /* we don't set EPC if EXL is set */
362 if (!(cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_EXL))
363 {
364 cp0->reg[MIPS_CP0_EPC] = cpu->pc;
365
366 /* keep IM, set exception code and bd slot */
367 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
368
369 if (bd_slot)
370 cause |= MIPS_CP0_CAUSE_BD_SLOT;
371 else
372 cause &= ~MIPS_CP0_CAUSE_BD_SLOT;
373
374 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
375 cp0->reg[MIPS_CP0_CAUSE] = cause;
376
377 /* XXX properly set vector */
378 vector = 0x180ULL;
379 }
380 else
381 {
382 /* keep IM and set exception code */
383 cause = cp0->reg[MIPS_CP0_CAUSE] & MIPS_CP0_CAUSE_IMASK;
384 cause |= (exc_code << MIPS_CP0_CAUSE_SHIFT);
385 cp0->reg[MIPS_CP0_CAUSE] = cause;
386
387 /* set vector */
388 vector = 0x180ULL;
389 }
390
391 /* Set EXL bit in status register */
392 cp0->reg[MIPS_CP0_STATUS] |= MIPS_CP0_STATUS_EXL;
393
394 /* Use bootstrap vectors ? */
395 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_BEV)
396 cpu->pc = 0xffffffffbfc00200ULL + vector;
397 else
398 cpu->pc = 0xffffffff80000000ULL + vector;
399
400 /* Clear the pending IRQ flag */
401 cpu->irq_pending = 0;
402 }
403
404 /*
405 * Increment count register and trigger the timer IRQ if value in compare
406 * register is the same.
407 */
408 fastcall void mips64_exec_inc_cp0_cnt(cpu_mips_t *cpu)
409 {
410 cpu->cp0_virt_cnt_reg++;
411
412 #if 0 /* TIMER_IRQ */
413 mips_cp0_t *cp0 = &cpu->cp0;
414
415 if (unlikely((cpu->cp0_virt_cnt_reg == cpu->cp0_virt_cmp_reg))) {
416 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
417 mips64_set_irq(cpu,7);
418 mips64_update_irq_flag_fast(cpu);
419 }
420 #endif
421 }
422
423 /* Trigger the Timer IRQ */
424 fastcall void mips64_trigger_timer_irq(cpu_mips_t *cpu)
425 {
426 mips_cp0_t *cp0 = &cpu->cp0;
427
428 cpu->timer_irq_count++;
429
430 cp0->reg[MIPS_CP0_COUNT] = (m_uint32_t)cp0->reg[MIPS_CP0_COMPARE];
431 mips64_set_irq(cpu,7);
432 mips64_update_irq_flag_fast(cpu);
433 }
434
435 /* Execute ERET instruction */
436 fastcall void mips64_exec_eret(cpu_mips_t *cpu)
437 {
438 mips_cp0_t *cp0 = &cpu->cp0;
439
440 if (cp0->reg[MIPS_CP0_STATUS] & MIPS_CP0_STATUS_ERL) {
441 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_ERL;
442 cpu->pc = cp0->reg[MIPS_CP0_ERR_EPC];
443 } else {
444 cp0->reg[MIPS_CP0_STATUS] &= ~MIPS_CP0_STATUS_EXL;
445 cpu->pc = cp0->reg[MIPS_CP0_EPC];
446 }
447
448 /* We have to clear the LLbit */
449 cpu->ll_bit = 0;
450
451 /* Update the pending IRQ flag */
452 mips64_update_irq_flag_fast(cpu);
453 }
454
455 /* Execute SYSCALL instruction */
456 fastcall void mips64_exec_syscall(cpu_mips_t *cpu)
457 {
458 #if DEBUG_SYSCALL
459 printf("MIPS64: SYSCALL at PC=0x%llx (RA=0x%llx)\n"
460 " a0=0x%llx, a1=0x%llx, a2=0x%llx, a3=0x%llx\n",
461 cpu->pc, cpu->gpr[MIPS_GPR_RA],
462 cpu->gpr[MIPS_GPR_A0], cpu->gpr[MIPS_GPR_A1],
463 cpu->gpr[MIPS_GPR_A2], cpu->gpr[MIPS_GPR_A3]);
464 #endif
465
466 /* XXX TODO: Branch Delay slot */
467 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_SYSCALL,0);
468 }
469
470 /* Execute BREAK instruction */
471 fastcall void mips64_exec_break(cpu_mips_t *cpu,u_int code)
472 {
473 printf("MIPS64: BREAK instruction (code=%u)\n",code);
474 mips64_dump_regs(cpu->gen);
475
476 /* XXX TODO: Branch Delay slot */
477 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_BP,0);
478 }
479
480 /* Trigger a Trap Exception */
481 fastcall void mips64_trigger_trap_exception(cpu_mips_t *cpu)
482 {
483 /* XXX TODO: Branch Delay slot */
484 printf("MIPS64: TRAP exception, CPU=%p\n",cpu);
485 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_TRAP,0);
486 }
487
488 /* Trigger IRQs */
489 fastcall void mips64_trigger_irq(cpu_mips_t *cpu)
490 {
491 if (unlikely(cpu->irq_disable)) {
492 cpu->irq_pending = 0;
493 return;
494 }
495
496 cpu->irq_count++;
497 if (mips64_update_irq_flag_fast(cpu))
498 mips64_trigger_exception(cpu,MIPS_CP0_CAUSE_INTERRUPT,0);
499 else
500 cpu->irq_fp_count++;
501 }
502
503 /* DMFC1 */
504 fastcall void mips64_exec_dmfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
505 {
506 cpu->gpr[gp_reg] = cpu->fpu.reg[cp1_reg];
507 }
508
509 /* DMTC1 */
510 fastcall void mips64_exec_dmtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
511 {
512 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg];
513 }
514
515 /* MFC1 */
516 fastcall void mips64_exec_mfc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
517 {
518 m_int64_t val;
519
520 val = cpu->fpu.reg[cp1_reg] & 0xffffffff;
521 cpu->gpr[gp_reg] = sign_extend(val,32);
522 }
523
524 /* MTC1 */
525 fastcall void mips64_exec_mtc1(cpu_mips_t *cpu,u_int gp_reg,u_int cp1_reg)
526 {
527 cpu->fpu.reg[cp1_reg] = cpu->gpr[gp_reg] & 0xffffffff;
528 }
529
530 /* Virtual breakpoint */
531 fastcall void mips64_run_breakpoint(cpu_mips_t *cpu)
532 {
533 cpu_log(cpu->gen,"BREAKPOINT",
534 "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);
535
536 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
537 cpu->pc,cpu->gpr[MIPS_GPR_RA]);
538
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 */
584 fastcall void mips64_debug_jr0(cpu_mips_t *cpu)
585 {
586 printf("MIPS64: cpu %p jumping to address 0...\n",cpu);
587 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 */
598 void mips64_dump_regs(cpu_gen_t *cpu)
599 {
600 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
601 mips_insn_t *ptr,insn;
602 char buffer[80];
603 int i;
604
605 printf("MIPS64 Registers:\n");
606
607 for(i=0;i<MIPS64_GPR_NR/2;i++) {
608 printf(" %s ($%2d) = 0x%16.16llx %s ($%2d) = 0x%16.16llx\n",
609 mips64_gpr_reg_names[i*2], i*2, mcpu->gpr[i*2],
610 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", mcpu->lo, mcpu->hi);
614 printf(" pc = 0x%16.16llx, ll_bit = %u\n", mcpu->pc, mcpu->ll_bit);
615
616 /* Fetch the current instruction */
617 ptr = mcpu->mem_op_lookup(mcpu,mcpu->pc);
618 if (ptr) {
619 insn = vmtoh32(*ptr);
620
621 if (mips64_dump_insn(buffer,sizeof(buffer),1,mcpu->pc,insn) != -1)
622 printf(" Instruction: %s\n",buffer);
623 }
624
625 printf("\nCP0 Registers:\n");
626
627 for(i=0;i<MIPS64_CP0_REG_NR/2;i++) {
628 printf(" %-10s ($%2d) = 0x%16.16llx %-10s ($%2d) = 0x%16.16llx\n",
629 mips64_cp0_reg_names[i*2], i*2,
630 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, "
636 "IRQ Pending: %u\n",
637 mcpu->irq_count,mcpu->irq_fp_count,mcpu->irq_pending);
638
639 printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
640 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");
644 }
645
646 /* Dump a memory block */
647 void mips64_dump_memory(cpu_mips_t *cpu,m_uint64_t vaddr,u_int count)
648 {
649 void *haddr;
650 u_int i;
651
652 for(i=0;i<count;i++,vaddr+=4)
653 {
654 if ((i & 3) == 0)
655 printf("\n 0x%16.16llx: ",vaddr);
656
657 haddr = cpu->mem_op_lookup(cpu,vaddr);
658
659 if (haddr)
660 printf("0x%8.8x ",htovm32(*(m_uint32_t *)haddr));
661 else
662 printf("XXXXXXXXXX ");
663 }
664
665 printf("\n\n");
666 }
667
668 /* Dump the stack */
669 void mips64_dump_stack(cpu_mips_t *cpu,u_int count)
670 {
671 printf("MIPS Stack Dump at 0x%16.16llx:",cpu->gpr[MIPS_GPR_SP]);
672 mips64_dump_memory(cpu,cpu->gpr[MIPS_GPR_SP],count);
673 }
674
675 /* Save the CPU state into a file */
676 int mips64_save_state(cpu_mips_t *cpu,char *filename)
677 {
678 FILE *fd;
679 int i;
680
681 if (!(fd = fopen(filename,"w"))) {
682 perror("mips64_save_state: fopen");
683 return(-1);
684 }
685
686 /* pc, lo and hi */
687 fprintf(fd,"pc: %16.16llx\n",cpu->pc);
688 fprintf(fd,"lo: %16.16llx\n",cpu->lo);
689 fprintf(fd,"hi: %16.16llx\n",cpu->hi);
690
691 /* general purpose registers */
692 for(i=0;i<MIPS64_GPR_NR;i++)
693 fprintf(fd,"%s: %16.16llx\n",
694 mips64_gpr_reg_names[i],cpu->gpr[i]);
695
696 printf("\n");
697
698 /* cp0 registers */
699 for(i=0;i<MIPS64_CP0_REG_NR;i++)
700 fprintf(fd,"%s: %16.16llx\n",
701 mips64_cp0_reg_names[i],cpu->cp0.reg[i]);
702
703 printf("\n");
704
705 /* cp1 registers */
706 for(i=0;i<MIPS64_CP1_REG_NR;i++)
707 fprintf(fd,"fpu%d: %16.16llx\n",i,cpu->fpu.reg[i]);
708
709 printf("\n");
710
711 /* tlb entries */
712 for(i=0;i<cpu->cp0.tlb_entries;i++) {
713 fprintf(fd,"tlb%d_mask: %16.16llx\n",i,cpu->cp0.tlb[i].mask);
714 fprintf(fd,"tlb%d_hi: %16.16llx\n",i,cpu->cp0.tlb[i].hi);
715 fprintf(fd,"tlb%d_lo0: %16.16llx\n",i,cpu->cp0.tlb[i].lo0);
716 fprintf(fd,"tlb%d_lo1: %16.16llx\n",i,cpu->cp0.tlb[i].lo1);
717 }
718
719 fclose(fd);
720 return(0);
721 }
722
723 /* Read a 64-bit unsigned integer */
724 static m_uint64_t mips64_hex_u64(char *str,int *err)
725 {
726 m_uint64_t res = 0;
727 u_char c;
728
729 /* remove leading spaces */
730 while((*str == ' ') || (*str == '\t'))
731 str++;
732
733 while(*str) {
734 c = *str;
735
736 if ((c >= '0') && (c <= '9'))
737 res = (res << 4) + (c - '0');
738
739 if ((c >= 'a') && (c <= 'f'))
740 res = (res << 4) + ((c - 'a') + 10);
741
742 if ((c >= 'A') && (c <= 'F'))
743 res = (res << 4) + ((c - 'A') + 10);
744
745 str++;
746 }
747
748 return(res);
749 }
750
751 /* Restore the CPU state from a file */
752 int mips64_restore_state(cpu_mips_t *cpu,char *filename)
753 {
754 char buffer[4096],*sep,*value,*ep,*field;
755 size_t len;
756 FILE *fd;
757 int index;
758
759 if (!(fd = fopen(filename,"r"))) {
760 perror("mips64_restore_state: fopen");
761 return(-1);
762 }
763
764 while(!feof(fd))
765 {
766 *buffer = 0;
767 fgets(buffer,sizeof(buffer),fd);
768 len = strlen(buffer);
769
770 if (buffer[len-1] == '\n')
771 buffer[len-1] = 0;
772
773 sep = strchr(buffer,':');
774 if (!sep) continue;
775
776 value = sep + 1;
777 *sep = 0;
778
779 /* gpr ? */
780 if ((index = mips64_get_reg_index(buffer)) != -1) {
781 cpu->gpr[index] = mips64_hex_u64(value,NULL);
782 continue;
783 }
784
785 /* cp0 register ? */
786 if ((index = mips64_cp0_get_reg_index(buffer)) != -1) {
787 cpu->cp0.reg[index] = mips64_hex_u64(value,NULL);
788 continue;
789 }
790
791 /* cp1 register ? */
792 if ((len > 3) && (!strncmp(buffer,"fpu",3))) {
793 index = atoi(buffer+3);
794 cpu->fpu.reg[index] = mips64_hex_u64(value,NULL);
795 }
796
797 /* tlb entry ? */
798 if ((len > 3) && (!strncmp(buffer,"tlb",3))) {
799 ep = strchr(buffer,'_');
800
801 if (ep) {
802 index = atoi(buffer+3);
803 field = ep + 1;
804
805 if (!strcmp(field,"mask")) {
806 cpu->cp0.tlb[index].mask = mips64_hex_u64(value,NULL);
807 continue;
808 }
809
810 if (!strcmp(field,"hi")) {
811 cpu->cp0.tlb[index].hi = mips64_hex_u64(value,NULL);
812 continue;
813 }
814
815 if (!strcmp(field,"lo0")) {
816 cpu->cp0.tlb[index].lo0 = mips64_hex_u64(value,NULL);
817 continue;
818 }
819
820 if (!strcmp(field,"lo1")) {
821 cpu->cp0.tlb[index].lo1 = mips64_hex_u64(value,NULL);
822 continue;
823 }
824 }
825 }
826
827 /* pc, lo, hi ? */
828 if (!strcmp(buffer,"pc")) {
829 cpu->pc = mips64_hex_u64(value,NULL);
830 continue;
831 }
832
833 if (!strcmp(buffer,"lo")) {
834 cpu->lo = mips64_hex_u64(value,NULL);
835 continue;
836 }
837
838 if (!strcmp(buffer,"hi")) {
839 cpu->hi = mips64_hex_u64(value,NULL);
840 continue;
841 }
842 }
843
844 mips64_cp0_map_all_tlb_to_mts(cpu);
845
846 mips64_dump_regs(cpu->gen);
847 mips64_tlb_dump(cpu->gen);
848
849 fclose(fd);
850 return(0);
851 }
852
853 /* Load a raw image into the simulated memory */
854 int mips64_load_raw_image(cpu_mips_t *cpu,char *filename,m_uint64_t vaddr)
855 {
856 struct stat file_info;
857 size_t len,clen;
858 m_uint32_t remain;
859 void *haddr;
860 FILE *bfd;
861
862 if (!(bfd = fopen(filename,"r"))) {
863 perror("fopen");
864 return(-1);
865 }
866
867 if (fstat(fileno(bfd),&file_info) == -1) {
868 perror("stat");
869 return(-1);
870 }
871
872 len = file_info.st_size;
873
874 printf("Loading RAW file '%s' at virtual address 0x%llx (size=%lu)\n",
875 filename,vaddr,(u_long)len);
876
877 while(len > 0)
878 {
879 haddr = cpu->mem_op_lookup(cpu,vaddr);
880
881 if (!haddr) {
882 fprintf(stderr,"load_raw_image: invalid load address 0x%llx\n",
883 vaddr);
884 return(-1);
885 }
886
887 if (len > MIPS_MIN_PAGE_SIZE)
888 clen = MIPS_MIN_PAGE_SIZE;
889 else
890 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)
898 break;
899
900 vaddr += clen;
901 len -= clen;
902 }
903
904 fclose(bfd);
905 return(0);
906 }
907
908 /* Load an ELF image into the simulated memory */
909 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
910 m_uint32_t *entry_point)
911 {
912 m_uint64_t vaddr;
913 m_uint32_t remain;
914 void *haddr;
915 Elf32_Ehdr *ehdr;
916 Elf32_Shdr *shdr;
917 Elf_Scn *scn;
918 Elf *img_elf;
919 size_t len,clen;
920 char *name;
921 int i,fd;
922 FILE *bfd;
923
924 if (!filename)
925 return(-1);
926
927 #ifdef __CYGWIN__
928 fd = open(filename,O_RDONLY|O_BINARY);
929 #else
930 fd = open(filename,O_RDONLY);
931 #endif
932
933 if (fd == -1) {
934 perror("load_elf_image: open");
935 return(-1);
936 }
937
938 if (elf_version(EV_CURRENT) == EV_NONE) {
939 fprintf(stderr,"load_elf_image: library out of date\n");
940 return(-1);
941 }
942
943 if (!(img_elf = elf_begin(fd,ELF_C_READ,NULL))) {
944 fprintf(stderr,"load_elf_image: elf_begin: %s\n",
945 elf_errmsg(elf_errno()));
946 return(-1);
947 }
948
949 if (!(ehdr = elf32_getehdr(img_elf))) {
950 fprintf(stderr,"load_elf_image: invalid ELF file\n");
951 return(-1);
952 }
953
954 printf("Loading ELF file '%s'...\n",filename);
955 bfd = fdopen(fd,"rb");
956
957 if (!bfd) {
958 perror("load_elf_image: fdopen");
959 return(-1);
960 }
961
962 if (!skip_load) {
963 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 if (len > MIPS_MIN_PAGE_SIZE)
992 clen = MIPS_MIN_PAGE_SIZE;
993 else
994 clen = len;
995
996 remain = PPC32_MIN_PAGE_SIZE;
997 remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK));
998
999 clen = m_min(clen,remain);
1000
1001 if (fread((u_char *)haddr,clen,1,bfd) < 1)
1002 break;
1003
1004 vaddr += clen;
1005 len -= clen;
1006 }
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);
1013
1014 if (entry_point)
1015 *entry_point = ehdr->e_entry;
1016
1017 elf_end(img_elf);
1018 fclose(bfd);
1019 return(0);
1020 }
1021
1022 /* Symbol lookup */
1023 struct symbol *mips64_sym_lookup(cpu_mips_t *cpu,m_uint64_t addr)
1024 {
1025 return(rbtree_lookup(cpu->sym_tree,&addr));
1026 }
1027
1028 /* Insert a new symbol */
1029 struct symbol *mips64_sym_insert(cpu_mips_t *cpu,char *name,m_uint64_t addr)
1030 {
1031 struct symbol *sym;
1032 size_t len;
1033
1034 if (!cpu->sym_tree)
1035 return NULL;
1036
1037 len = strlen(name);
1038
1039 if (!(sym = malloc(len+1+sizeof(*sym))))
1040 return NULL;
1041
1042 memcpy(sym->name,name,len+1);
1043 sym->addr = addr;
1044
1045 if (rbtree_insert(cpu->sym_tree,sym,sym) == -1) {
1046 free(sym);
1047 return NULL;
1048 }
1049
1050 return sym;
1051 }
1052
1053 /* Symbol comparison function */
1054 static int mips64_sym_compare(m_uint64_t *a1,struct symbol *sym)
1055 {
1056 if (*a1 > sym->addr)
1057 return(1);
1058
1059 if (*a1 < sym->addr)
1060 return(-1);
1061
1062 return(0);
1063 }
1064
1065 /* Create the symbol tree */
1066 int mips64_sym_create_tree(cpu_mips_t *cpu)
1067 {
1068 cpu->sym_tree = rbtree_create((tree_fcompare)mips64_sym_compare,NULL);
1069 return(cpu->sym_tree ? 0 : -1);
1070 }
1071
1072 /* Load a symbol file */
1073 int mips64_sym_load_file(cpu_mips_t *cpu,char *filename)
1074 {
1075 char buffer[4096],func_name[128];
1076 m_uint64_t addr;
1077 char sym_type;
1078 FILE *fd;
1079
1080 if (!cpu->sym_tree && (mips64_sym_create_tree(cpu) == -1)) {
1081 fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->gen->id);
1082 return(-1);
1083 }
1084
1085 if (!(fd = fopen(filename,"r"))) {
1086 perror("load_sym_file: fopen");
1087 return(-1);
1088 }
1089
1090 while(!feof(fd)) {
1091 fgets(buffer,sizeof(buffer),fd);
1092
1093 if (sscanf(buffer,"%llx %c %s",&addr,&sym_type,func_name) == 3) {
1094 mips64_sym_insert(cpu,func_name,addr);
1095 }
1096 }
1097
1098 fclose(fd);
1099 return(0);
1100 }

  ViewVC Help
Powered by ViewVC 1.1.26