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

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 8 mips64_set_addr_mode(cpu,32/*64*/); /* zzz */
72 dpavlin 7 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 dpavlin 8 /* Enable/Disable direct block jump */
98     cpu->exec_blk_direct_jump = cpu->vm->exec_blk_direct_jump;
99    
100 dpavlin 1 /* Create the IRQ lock (for non-jit architectures) */
101     pthread_mutex_init(&cpu->irq_lock,NULL);
102    
103     /* Idle loop mutex and condition */
104 dpavlin 7 pthread_mutex_init(&cpu->gen->idle_mutex,NULL);
105     pthread_cond_init(&cpu->gen->idle_cond,NULL);
106 dpavlin 1
107 dpavlin 7 /* 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 dpavlin 1 /* 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 dpavlin 7 mips64_mem_shutdown(cpu);
127 dpavlin 1 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 dpavlin 7 /* Set idle PC value */
141     void mips64_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr)
142 dpavlin 1 {
143 dpavlin 7 CPU_MIPS64(cpu)->idle_pc = addr;
144 dpavlin 1 }
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 dpavlin 7 while(cpu->gen->state != CPU_STATE_HALTED) {
161 dpavlin 1 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 dpavlin 7 likely(cpu->gen->state == CPU_STATE_RUNNING))
169 dpavlin 1 {
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 dpavlin 3 #define IDLE_HASH_SIZE 8192
191    
192 dpavlin 1 /* Idle PC hash item */
193 dpavlin 3 struct mips64_idle_pc_hash {
194 dpavlin 1 m_uint64_t pc;
195     u_int count;
196 dpavlin 3 struct mips64_idle_pc_hash *next;
197 dpavlin 1 };
198    
199     /* Determine an "idling" PC */
200 dpavlin 7 int mips64_get_idling_pc(cpu_gen_t *cpu)
201 dpavlin 1 {
202 dpavlin 7 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
203 dpavlin 3 struct mips64_idle_pc_hash **pc_hash,*p;
204 dpavlin 7 struct cpu_idle_pc *res;
205 dpavlin 1 u_int h_index,res_count;
206     m_uint64_t cur_pc;
207     int i;
208    
209 dpavlin 3 cpu->idle_pc_prop_count = 0;
210    
211 dpavlin 7 if (mcpu->idle_pc != 0) {
212 dpavlin 1 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 dpavlin 7 pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct mips64_idle_pc_hash *));
220 dpavlin 1
221     /* Disable IRQ */
222 dpavlin 7 mcpu->irq_disable = TRUE;
223 dpavlin 1
224     /* Take 1000 measures, each mesure every 10ms */
225     for(i=0;i<1000;i++) {
226 dpavlin 7 cur_pc = mcpu->pc;
227 dpavlin 1 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 dpavlin 3 res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++];
252 dpavlin 1
253 dpavlin 3 res->pc = p->pc;
254     res->count = p->count;
255    
256 dpavlin 7 if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES)
257 dpavlin 1 goto done;
258     }
259     }
260    
261     done:
262     /* Set idle PC */
263 dpavlin 3 if (cpu->idle_pc_prop_count) {
264 dpavlin 1 printf("Done. Suggested idling PC:\n");
265    
266 dpavlin 3 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 dpavlin 1 printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n",
273 dpavlin 3 cpu->idle_pc_prop[0].pc);
274 dpavlin 1 } else {
275     printf("Done. No suggestion for idling PC\n");
276 dpavlin 8
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 dpavlin 1 }
291    
292     /* Re-enable IRQ */
293 dpavlin 7 mcpu->irq_disable = FALSE;
294 dpavlin 1 return(0);
295     }
296    
297 dpavlin 7 /* 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 dpavlin 1 /* 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 dpavlin 11
466 dpavlin 1 /* 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 dpavlin 7 mips64_dump_regs(cpu->gen);
475 dpavlin 1
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 dpavlin 7 cpu_log(cpu->gen,"BREAKPOINT",
534 dpavlin 1 "Virtual breakpoint reached at PC=0x%llx\n",cpu->pc);
535    
536 dpavlin 2 printf("[[[ Virtual Breakpoint reached at PC=0x%llx RA=0x%llx]]]\n",
537     cpu->pc,cpu->gpr[MIPS_GPR_RA]);
538    
539 dpavlin 7 mips64_dump_regs(cpu->gen);
540     memlog_dump(cpu->gen);
541 dpavlin 1 }
542    
543 dpavlin 2 /* Add a virtual breakpoint */
544 dpavlin 7 int mips64_add_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
545 dpavlin 2 {
546 dpavlin 7 cpu_mips_t *mcpu = CPU_MIPS64(cpu);
547 dpavlin 2 int i;
548    
549     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
550 dpavlin 7 if (!mcpu->breakpoints[i])
551 dpavlin 2 break;
552    
553     if (i == MIPS64_MAX_BREAKPOINTS)
554     return(-1);
555    
556 dpavlin 7 mcpu->breakpoints[i] = pc;
557     mcpu->breakpoints_enabled = TRUE;
558 dpavlin 2 return(0);
559     }
560    
561     /* Remove a virtual breakpoint */
562 dpavlin 7 void mips64_remove_breakpoint(cpu_gen_t *cpu,m_uint64_t pc)
563     {
564     cpu_mips_t *mcpu = CPU_MIPS64(cpu);
565 dpavlin 2 int i,j;
566    
567     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
568 dpavlin 7 if (mcpu->breakpoints[i] == pc)
569 dpavlin 2 {
570     for(j=i;j<MIPS64_MAX_BREAKPOINTS-1;j++)
571 dpavlin 7 mcpu->breakpoints[j] = mcpu->breakpoints[j+1];
572 dpavlin 2
573 dpavlin 7 mcpu->breakpoints[MIPS64_MAX_BREAKPOINTS-1] = 0;
574 dpavlin 2 }
575    
576     for(i=0;i<MIPS64_MAX_BREAKPOINTS;i++)
577 dpavlin 7 if (mcpu->breakpoints[i] != 0)
578 dpavlin 2 return;
579    
580 dpavlin 7 mcpu->breakpoints_enabled = FALSE;
581 dpavlin 2 }
582    
583 dpavlin 1 /* 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 dpavlin 7 mips64_dump_regs(cpu->gen);
588 dpavlin 1 }
589    
590 dpavlin 7 /* 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 dpavlin 1 /* Dump registers of a MIPS64 processor */
598 dpavlin 7 void mips64_dump_regs(cpu_gen_t *cpu)
599     {
600     cpu_mips_t *mcpu = CPU_MIPS64(cpu);
601 dpavlin 1 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 dpavlin 7 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 dpavlin 1 }
612    
613 dpavlin 7 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 dpavlin 1
616     /* Fetch the current instruction */
617 dpavlin 7 ptr = mcpu->mem_op_lookup(mcpu,mcpu->pc);
618 dpavlin 1 if (ptr) {
619     insn = vmtoh32(*ptr);
620    
621 dpavlin 7 if (mips64_dump_insn(buffer,sizeof(buffer),1,mcpu->pc,insn) != -1)
622 dpavlin 1 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 dpavlin 7 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 dpavlin 1 }
634    
635     printf("\n IRQ count: %llu, IRQ false positives: %llu, "
636     "IRQ Pending: %u\n",
637 dpavlin 7 mcpu->irq_count,mcpu->irq_fp_count,mcpu->irq_pending);
638 dpavlin 1
639     printf(" Timer IRQ count: %llu, pending: %u, timer drift: %u\n\n",
640 dpavlin 7 mcpu->timer_irq_count,mcpu->timer_irq_pending,mcpu->timer_drift);
641 dpavlin 1
642 dpavlin 8 printf(" Device access count: %llu\n",cpu->dev_access_counter);
643 dpavlin 1 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 dpavlin 7 if ((index = mips64_cp0_get_reg_index(buffer)) != -1) {
787 dpavlin 1 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 dpavlin 7 mips64_cp0_map_all_tlb_to_mts(cpu);
845 dpavlin 1
846 dpavlin 7 mips64_dump_regs(cpu->gen);
847     mips64_tlb_dump(cpu->gen);
848 dpavlin 1
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 dpavlin 7 m_uint32_t remain;
859 dpavlin 1 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 dpavlin 7 remain = MIPS_MIN_PAGE_SIZE;
893     remain -= (vaddr - (vaddr & MIPS_MIN_PAGE_MASK));
894    
895     clen = m_min(clen,remain);
896    
897 dpavlin 1 if (fread((u_char *)haddr,clen,1,bfd) != 1)
898     break;
899    
900 dpavlin 7 vaddr += clen;
901 dpavlin 1 len -= clen;
902     }
903    
904     fclose(bfd);
905     return(0);
906     }
907    
908     /* Load an ELF image into the simulated memory */
909 dpavlin 4 int mips64_load_elf_image(cpu_mips_t *cpu,char *filename,int skip_load,
910 dpavlin 1 m_uint32_t *entry_point)
911     {
912     m_uint64_t vaddr;
913 dpavlin 7 m_uint32_t remain;
914 dpavlin 1 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 dpavlin 4 if (!skip_load) {
963     for(i=0;i<ehdr->e_shnum;i++) {
964     scn = elf_getscn(img_elf,i);
965 dpavlin 1
966 dpavlin 4 shdr = elf32_getshdr(scn);
967     name = elf_strptr(img_elf, ehdr->e_shstrndx, (size_t)shdr->sh_name);
968     len = shdr->sh_size;
969 dpavlin 1
970 dpavlin 4 if (!(shdr->sh_flags & SHF_ALLOC) || !len)
971     continue;
972 dpavlin 1
973 dpavlin 4 fseek(bfd,shdr->sh_offset,SEEK_SET);
974     vaddr = sign_extend(shdr->sh_addr,32);
975 dpavlin 1
976 dpavlin 4 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 dpavlin 1
985 dpavlin 4 if (!haddr) {
986     fprintf(stderr,"load_elf_image: invalid load address 0x%llx\n",
987     vaddr);
988     return(-1);
989     }
990 dpavlin 1
991 dpavlin 4 if (len > MIPS_MIN_PAGE_SIZE)
992     clen = MIPS_MIN_PAGE_SIZE;
993     else
994     clen = len;
995 dpavlin 1
996 dpavlin 7 remain = PPC32_MIN_PAGE_SIZE;
997     remain -= (vaddr - (vaddr & PPC32_MIN_PAGE_MASK));
998 dpavlin 1
999 dpavlin 7 clen = m_min(clen,remain);
1000    
1001     if (fread((u_char *)haddr,clen,1,bfd) < 1)
1002 dpavlin 4 break;
1003 dpavlin 1
1004 dpavlin 7 vaddr += clen;
1005 dpavlin 4 len -= clen;
1006     }
1007 dpavlin 1 }
1008 dpavlin 4 } else {
1009     printf("ELF loading skipped, using a ghost RAM file.\n");
1010 dpavlin 1 }
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 dpavlin 7 fprintf(stderr,"CPU%u: Unable to create symbol tree.\n",cpu->gen->id);
1082 dpavlin 1 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