📄 ppc32.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * PowerPC (32-bit) generic routines. */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#include <assert.h>#include "rbtree.h"#include "cpu.h"#include "dynamips.h"#include "memory.h"#include "device.h"#include "ppc32_mem.h"#include "ppc32_exec.h"#include "ppc32_jit.h"/* Reset a PowerPC CPU */int ppc32_reset(cpu_ppc_t *cpu){ cpu->ia = PPC32_ROM_START; cpu->gpr[1] = PPC32_ROM_SP; cpu->msr = PPC32_MSR_IP; /* Restart the MTS subsystem */ ppc32_mem_restart(cpu); /* Flush JIT structures */ ppc32_jit_flush(cpu,0); return(0);}/* Initialize a PowerPC processor */int ppc32_init(cpu_ppc_t *cpu){ /* Initialize JIT operations */ jit_op_init_cpu(cpu->gen); /* Initialize idle timer */ cpu->gen->idle_max = 1500; cpu->gen->idle_sleep_time = 30000; /* Timer IRQ parameters (default frequency: 250 Hz <=> 4ms period) */ cpu->timer_irq_check_itv = 1000; cpu->timer_irq_freq = 250; /* Enable/disable direct block jump */ cpu->exec_blk_direct_jump = cpu->vm->exec_blk_direct_jump; /* Idle loop mutex and condition */ pthread_mutex_init(&cpu->gen->idle_mutex,NULL); pthread_cond_init(&cpu->gen->idle_cond,NULL); /* Set the CPU methods */ cpu->gen->reg_set = (void *)ppc32_reg_set; cpu->gen->reg_dump = (void *)ppc32_dump_regs; cpu->gen->mmu_dump = (void *)ppc32_dump_mmu; cpu->gen->mmu_raw_dump = (void *)ppc32_dump_mmu; cpu->gen->add_breakpoint = (void *)ppc32_add_breakpoint; cpu->gen->remove_breakpoint = (void *)ppc32_remove_breakpoint; cpu->gen->set_idle_pc = (void *)ppc32_set_idle_pc; cpu->gen->get_idling_pc = (void *)ppc32_get_idling_pc; /* zzz */ memset(cpu->vtlb,0xFF,sizeof(cpu->vtlb)); /* Set the startup parameters */ ppc32_reset(cpu); return(0);}/* Delete a PowerPC processor */void ppc32_delete(cpu_ppc_t *cpu){ if (cpu) { ppc32_mem_shutdown(cpu); ppc32_jit_shutdown(cpu); }}/* Set the processor version register (PVR) */void ppc32_set_pvr(cpu_ppc_t *cpu,m_uint32_t pvr){ cpu->pvr = pvr; ppc32_mem_restart(cpu);}/* Set idle PC value */void ppc32_set_idle_pc(cpu_gen_t *cpu,m_uint64_t addr){ CPU_PPC32(cpu)->idle_pc = (m_uint32_t)addr;}/* Timer IRQ */void *ppc32_timer_irq_run(cpu_ppc_t *cpu){ pthread_mutex_t umutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t ucond = PTHREAD_COND_INITIALIZER; struct timespec t_spc; m_tmcnt_t expire; u_int interval; u_int threshold;#if 0 while(!cpu->timer_irq_armed) sleep(1);#endif interval = 1000000 / cpu->timer_irq_freq; threshold = cpu->timer_irq_freq * 10; expire = m_gettime_usec() + interval; while(cpu->gen->state != CPU_STATE_HALTED) { pthread_mutex_lock(&umutex); t_spc.tv_sec = expire / 1000000; t_spc.tv_nsec = (expire % 1000000) * 1000; pthread_cond_timedwait(&ucond,&umutex,&t_spc); pthread_mutex_unlock(&umutex); if (likely(!cpu->irq_disable) && likely(cpu->gen->state == CPU_STATE_RUNNING) && likely(cpu->msr & PPC32_MSR_EE)) { cpu->timer_irq_pending++; if (unlikely(cpu->timer_irq_pending > threshold)) { cpu->timer_irq_pending = 0; cpu->timer_drift++;#if 0 printf("Timer IRQ not accurate (%u pending IRQ): " "reduce the \"--timer-irq-check-itv\" parameter " "(current value: %u)\n", cpu->timer_irq_pending,cpu->timer_irq_check_itv);#endif } } expire += interval; } return NULL;}#define IDLE_HASH_SIZE 8192/* Idle PC hash item */struct ppc32_idle_pc_hash { m_uint32_t ia; u_int count; struct ppc32_idle_pc_hash *next;};/* Determine an "idling" PC */int ppc32_get_idling_pc(cpu_gen_t *cpu){ cpu_ppc_t *pcpu = CPU_PPC32(cpu); struct ppc32_idle_pc_hash **pc_hash,*p; struct cpu_idle_pc *res; u_int h_index,res_count; m_uint32_t cur_ia; int i; cpu->idle_pc_prop_count = 0; if (pcpu->idle_pc != 0) { printf("\nYou already use an idle PC, using the calibration would give " "incorrect results.\n"); return(-1); } printf("\nPlease wait while gathering statistics...\n"); pc_hash = calloc(IDLE_HASH_SIZE,sizeof(struct ppc32_idle_pc_hash *)); /* Disable IRQ */ pcpu->irq_disable = TRUE; /* Take 1000 measures, each mesure every 10ms */ for(i=0;i<1000;i++) { cur_ia = pcpu->ia; h_index = (cur_ia >> 2) & (IDLE_HASH_SIZE-1); for(p=pc_hash[h_index];p;p=p->next) if (p->ia == cur_ia) { p->count++; break; } if (!p) { if ((p = malloc(sizeof(*p)))) { p->ia = cur_ia; p->count = 1; p->next = pc_hash[h_index]; pc_hash[h_index] = p; } } usleep(10000); } /* Select PCs */ for(i=0,res_count=0;i<IDLE_HASH_SIZE;i++) { for(p=pc_hash[i];p;p=p->next) if ((p->count >= 20) && (p->count <= 80)) { res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++]; res->pc = p->ia; res->count = p->count; if (cpu->idle_pc_prop_count >= CPU_IDLE_PC_MAX_RES) goto done; } } done: /* Set idle PC */ if (cpu->idle_pc_prop_count) { printf("Done. Suggested idling PC:\n"); for(i=0;i<cpu->idle_pc_prop_count;i++) { printf(" 0x%llx (count=%u)\n", cpu->idle_pc_prop[i].pc, cpu->idle_pc_prop[i].count); } printf("Restart the emulator with \"--idle-pc=0x%llx\" (for example)\n", cpu->idle_pc_prop[0].pc); } else { printf("Done. No suggestion for idling PC, dumping the full table:\n"); for(i=0;i<IDLE_HASH_SIZE;i++) for(p=pc_hash[i];p;p=p->next) { printf(" 0x%8.8x (%3u)\n",p->ia,p->count); if (cpu->idle_pc_prop_count < CPU_IDLE_PC_MAX_RES) { res = &cpu->idle_pc_prop[cpu->idle_pc_prop_count++]; res->pc = p->ia; res->count = p->count; } } printf("\n"); } /* Re-enable IRQ */ pcpu->irq_disable = FALSE; return(0);}#if 0/* Set an IRQ (VM IRQ standard routing) */void ppc32_vm_set_irq(vm_instance_t *vm,u_int irq){ cpu_ppc_t *boot_cpu; boot_cpu = CPU_PPC32(vm->boot_cpu); if (boot_cpu->irq_disable) { boot_cpu->irq_pending = 0; return; } ppc32_set_irq(boot_cpu,irq); if (boot_cpu->irq_idle_preempt[irq]) cpu_idle_break_wait(vm->boot_cpu);}/* Clear an IRQ (VM IRQ standard routing) */void ppc32_vm_clear_irq(vm_instance_t *vm,u_int irq){ cpu_ppc_t *boot_cpu; boot_cpu = CPU_PPC32(vm->boot_cpu); ppc32_clear_irq(boot_cpu,irq);}#endif/* Generate an exception */void ppc32_trigger_exception(cpu_ppc_t *cpu,u_int exc_vector){ //printf("TRIGGER_EXCEPTION: saving cpu->ia=0x%8.8x, msr=0x%8.8x\n", // cpu->ia,cpu->msr); /* Save the return instruction address */ cpu->srr0 = cpu->ia; if (exc_vector == PPC32_EXC_SYSCALL) cpu->srr0 += sizeof(ppc_insn_t); //printf("SRR0 = 0x%8.8x\n",cpu->srr0); /* Save Machine State Register (MSR) */ cpu->srr1 = cpu->msr & PPC32_EXC_SRR1_MASK; //printf("SRR1 = 0x%8.8x\n",cpu->srr1); /* Set the new SRR value */ cpu->msr &= ~PPC32_EXC_MSR_MASK; cpu->irq_check = FALSE; //printf("MSR = 0x%8.8x\n",cpu->msr); /* Use bootstrap vectors ? */ if (cpu->msr & PPC32_MSR_IP) cpu->ia = 0xFFF00000 + exc_vector; else cpu->ia = exc_vector;}/* Trigger IRQs */fastcall void ppc32_trigger_irq(cpu_ppc_t *cpu){ if (unlikely(cpu->irq_disable)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -