/[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

Annotation of /trunk/mips64.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 6 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 dpavlin 1 /*
2 dpavlin 7 * Cisco router simulation platform.
3 dpavlin 1 * 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 dpavlin 7 #include "cpu.h"
20     #include "mips64_mem.h"
21     #include "mips64_exec.h"
22     #include "mips64_jit.h"
23 dpavlin 1 #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 dpavlin 7 mips64_set_addr_mode(cpu,64);
72     cpu->gen->mts_rebuild(cpu->gen);
73 dpavlin 1
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 dpavlin 7 cpu->gen->idle_max = 1500;
88     cpu->gen->idle_sleep_time = 30000;
89 dpavlin 1
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 dpavlin 7 pthread_mutex_init(&cpu->gen->idle_mutex,NULL);
102     pthread_cond_init(&cpu->gen->idle_cond,NULL);
103 dpavlin 1
104 dpavlin 7 /* 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 dpavlin 1 /* 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 dpavlin 7 mips64_mem_shutdown(cpu);
124 dpavlin 1 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 dpavlin 7 /* Set idle PC value */
138     void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr)
139 dpavlin 1 {
140 dpavlin 7 CPU_MIPS64(cpu)->idle_pc = addr;
141 dpavlin 1 }
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 dpavlin 7 while(cpu->gen->state != CPU_STATE_HALTED) {
158 dpavlin 1 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 dpavlin 7 likely(cpu->gen->state == CPU_STATE_RUNNING))
166 dpavlin 1 {
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 dpavlin 3 #define IDLE_HASH_SIZE 8192
188    
189 dpavlin 1 /* Idle PC hash item */
190 dpavlin 3 struct mips64_idle_pc_hash {
191 dpavlin 1 m_uint64_t pc;
192     u_int count;
193 dpavlin 3 struct mips64_idle_pc_hash *next;
194 dpavlin 1 };
195    
196     /* Determine an "idling" PC */
197 dpavlin 7 int mips64_get_idling_pc(cpu_gen_t *cpu)
198 dpavlin 1 {
199 dpavlin 7 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
200 dpavlin 3 struct mips64_idle_pc_hash **pc_hash,*p;
201 dpavlin 7 struct cpu_idle_pc *res;
202 dpavlin 1 u_int h_index,res_count;
203     m_uint64_t cur_pc;
204     int i;
205    
206 dpavlin 3 cpu->idle_pc_prop_count = 0;
207    
208 dpavlin 7 if (mcpu->idle_pc != 0) {
209 dpavlin 1 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 dpavlin 7 pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *));
217 dpavlin 1
218     /* Disable IRQ */
219 dpavlin 7 mcpu->irq_disable = TRUE;
220 dpavlin 1
221     /* Take 1000 measures, each mesure every 10ms */
222     for(i=0;i<1000;i++) {
223 dpavlin 7 cur_pc = mcpu->pc;
224 dpavlin 1 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 dpavlin 3 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
249 dpavlin 1
250 dpavlin 3 res->pc = p->pc;
251     res->count = p->count;
252    
253 dpavlin 7 if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)
254 dpavlin 1 goto done;
255     }
256     }
257    
258     done:
259     /* Set idle PC */
260 dpavlin 3 if (cpu->idle_pc_prop_count) {
261 dpavlin 1 printf("Done. Suggested idling PC:\n");
262    
263 dpavlin 3 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 dpavlin 1 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
270 dpavlin 3 cpu->idle_pc_prop[0].pc);
271 dpavlin 1 } else {
272     printf("Done. No suggestion for idling PC\n");
273     }
274    
275     /* Re-enable IRQ */
276 dpavlin 7 mcpu->irq_disable = FALSE;
277 dpavlin 1 return(0);
278     }
279    
280 dpavlin 7 /* 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 dpavlin 1 /* 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 dpavlin 7 mips64_dump_regs(cpu->gen);
458 dpavlin 1
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 dpavlin 7 cpu_log(cpu->gen,"BREAKPOINT",
517 dpavlin 1 "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);
518    
519 dpavlin 2 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
520     cpu->pc,cpu->gpr[MIPS_GPR_RA]);
521    
522 dpavlin 7 mips64_dump_regs(cpu->gen);
523     memlog_dump(cpu->gen);
524 dpavlin 1 }
525    
526 dpavlin 2 /* Add a virtual breakpoint */
527 dpavlin 7 int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
528 dpavlin 2 {
529 dpavlin 7 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
530 dpavlin 2 int i;
531    
532     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
533 dpavlin 7 if (!mcpu->breakpoints[i])
534 dpavlin 2 break;
535    
536     if (i == MIPS64_MAX_BREAKPOINTS)
537     return(-1);
538    
539 dpavlin 7 mcpu->breakpoints[i] = pc;
540     mcpu->breakpoints_enabled = TRUE;
541 dpavlin 2 return(0);
542     }
543    
544     /* Remove a virtual breakpoint */
545 dpavlin 7 void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
546     {
547     cpu_mips_t *mcpu = CPU_MIPS64(cpu);
548 dpavlin 2 int i,j;
549    
550     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
551 dpavlin 7 if (mcpu->breakpoints[i] == pc)
552 dpavlin 2 {
553     for(j=i;j<MIPS64_MAX_BREAKPOINTS-1;j++)
554 dpavlin 7 mcpu->breakpoints[j] = mcpu->breakpoints[j+1];
555 dpavlin 2
556 dpavlin 7 mcpu->breakpoints[MIPS64_MAX_BREAKPOINTS-1] = 0;
557 dpavlin 2 }
558    
559     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
560 dpavlin 7 if (mcpu->breakpoints[i] != 0)
561 dpavlin 2 return;
562    
563 dpavlin 7 mcpu->breakpoints_enabled = FALSE;
564 dpavlin 2 }
565    
566 dpavlin 1 /* 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 dpavlin 7 mips64_dump_regs(cpu->gen);
571 dpavlin 1 }
572    
573 dpavlin 7 /* 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 dpavlin 1 /* Dump registers of a MIPS64 processor */
581 dpavlin 7 void mips64_dump_regs(cpu_gen_t *cpu)
582     {
583     cpu_mips_t *mcpu = CPU_MIPS64(cpu);
584 dpavlin 1 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 dpavlin 7 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 dpavlin 1 }
595    
596 dpavlin 7 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 dpavlin 1
599     /* Fetch the current instruction */
600 dpavlin 7 ptr = mcpu->mem_op_lookup(mcpu,mcpu->pc);
601 dpavlin 1 if (ptr) {
602     insn = vmtoh32(*ptr);
603    
604 dpavlin 7 if (mips64_dump_insn(buffer,sizeof(buffer),1,mcpu->pc,insn) != -1)
605 dpavlin 1 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 dpavlin 7 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 dpavlin 1 }
617    
618     printf("\n IRQ count: %llu, IRQ false positives: %llu, "
619     "IRQ Pending: %u\n",
620 dpavlin 7 mcpu->irq_count,mcpu->irq_fp_count,mcpu->irq_pending);
621 dpavlin 1
622     printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
623 dpavlin 7 mcpu->timer_irq_count,mcpu->timer_irq_pending,mcpu->timer_drift);
624 dpavlin 1
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 dpavlin 7 if ((index = mips64_cp0_get_reg_index(buffer)) != -1) {
769 dpavlin 1 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 dpavlin 7 mips64_cp0_map_all_tlb_to_mts(cpu);
827 dpavlin 1
828 dpavlin 7 mips64_dump_regs(cpu->gen);
829     mips64_tlb_dump(cpu->gen);
830 dpavlin 1
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 dpavlin 7 m_uint32_t remain;
841 dpavlin 1 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 dpavlin 7 remain = MIPS_MIN_PAGE_SIZE;
875     remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_MASK));
876    
877     clen = m_min(clen,remain);
878    
879 dpavlin 1 if (fread((u_char *)haddr,clen,1,bfd) != 1)
880     break;
881    
882 dpavlin 7 vaddr += clen;
883 dpavlin 1 len -= clen;
884     }
885    
886     fclose(bfd);
887     return(0);
888     }
889    
890     /* Load an ELF image into the simulated memory */
891 dpavlin 4 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
892 dpavlin 1 m_uint32_t *entry_point)
893     {
894     m_uint64_t vaddr;
895 dpavlin 7 m_uint32_t remain;
896 dpavlin 1 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 dpavlin 4 if (!skip_load) {
945     for(i=0;i<ehdr->e_shnum;i++) {
946     scn = elf_getscn(img_elf,i);
947 dpavlin 1
948 dpavlin 4 shdr = elf32_getshdr(scn);
949     name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
950     len = shdr->sh_size;
951 dpavlin 1
952 dpavlin 4 if (!(shdr->sh_flags & SHF_ALLOC) || !len)
953     continue;
954 dpavlin 1
955 dpavlin 4 fseek(bfd,shdr->sh_offset,SEEK_SET);
956     vaddr = sign_extend(shdr->sh_addr,32);
957 dpavlin 1
958 dpavlin 4 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 dpavlin 1
967 dpavlin 4 if (!haddr) {
968     fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
969     vaddr);
970     return(-1);
971     }
972 dpavlin 1
973 dpavlin 4 if (len > MIPS_MIN_PAGE_SIZE)
974     clen = MIPS_MIN_PAGE_SIZE;
975     else
976     clen = len;
977 dpavlin 1
978 dpavlin 7 remain = PPC32_MIN_PAGE_SIZE;
979     remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK));
980 dpavlin 1
981 dpavlin 7 clen = m_min(clen,remain);
982    
983     if (fread((u_char *)haddr,clen,1,bfd) < 1)
984 dpavlin 4 break;
985 dpavlin 1
986 dpavlin 7 vaddr += clen;
987 dpavlin 4 len -= clen;
988     }
989 dpavlin 1 }
990 dpavlin 4 } else {
991     printf("ELF loading skipped, using a ghost RAM file.\n");
992 dpavlin 1 }
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 dpavlin 7 fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->gen->id);
1064 dpavlin 1 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