📄 ppc32_exec.c
字号:
/* * Cisco router simulation platform. * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr) * * PowerPC (32-bit) step-by-step execution. */#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 "cpu.h"#include "vm.h"#include "ppc32_exec.h"#include "ppc32_mem.h"#include "memory.h"#include "insn_lookup.h"#include "dynamips.h"/* Forward declaration of instruction array */static struct ppc32_insn_exec_tag ppc32_exec_tags[];static insn_lookup_t *ilt = NULL;/* ILT */static forced_inline void *ppc32_exec_get_insn(int index){ return(&ppc32_exec_tags[index]);}static int ppc32_exec_chk_lo(struct ppc32_insn_exec_tag *tag,int value){ return((value & tag->mask) == (tag->value & 0xFFFF));}static int ppc32_exec_chk_hi(struct ppc32_insn_exec_tag *tag,int value){ return((value & (tag->mask >> 16)) == (tag->value >> 16));}/* Initialize instruction lookup table */void ppc32_exec_create_ilt(void){ int i,count; for(i=0,count=0;ppc32_exec_tags[i].exec;i++) count++; ilt = ilt_create("ppc32e",count, (ilt_get_insn_cbk_t)ppc32_exec_get_insn, (ilt_check_cbk_t)ppc32_exec_chk_lo, (ilt_check_cbk_t)ppc32_exec_chk_hi);}/* Dump statistics */void ppc32_dump_stats(cpu_ppc_t *cpu){ int i;#if NJM_STATS_ENABLE printf("\n"); for(i=0;ppc32_exec_tags[i].exec;i++) printf(" * %-10s : %10llu\n", ppc32_exec_tags[i].name,ppc32_exec_tags[i].count); printf("%llu instructions executed since startup.\n",cpu->insn_exec_count);#else printf("Statistics support is not compiled in.\n");#endif}/* Execute a memory operation */static forced_inline void ppc32_exec_memop(cpu_ppc_t *cpu,int memop, m_uint32_t vaddr,u_int dst_reg){ fastcall ppc_memop_fn fn; fn = cpu->mem_op_fn[memop]; fn(cpu,vaddr,dst_reg);}/* Fetch an instruction */static forced_inline int ppc32_exec_fetch(cpu_ppc_t *cpu,m_uint32_t ia, ppc_insn_t *insn){ m_uint32_t exec_page,offset; exec_page = ia & ~PPC32_MIN_PAGE_IMASK; if (unlikely(exec_page != cpu->njm_exec_page)) { cpu->njm_exec_page = exec_page; cpu->njm_exec_ptr = cpu->mem_op_lookup(cpu,exec_page,PPC32_MTS_ICACHE); } offset = (ia & PPC32_MIN_PAGE_IMASK) >> 2; *insn = vmtoh32(cpu->njm_exec_ptr[offset]); return(0);}/* Unknown opcode */static fastcall int ppc32_exec_unknown(cpu_ppc_t *cpu,ppc_insn_t insn){ printf("PPC32: unknown opcode 0x%8.8x at ia = 0x%x\n",insn,cpu->ia); ppc32_dump_regs(cpu->gen); return(0);}/* Execute a single instruction */static forced_inline int ppc32_exec_single_instruction(cpu_ppc_t *cpu,ppc_insn_t instruction){ register fastcall int (*exec)(cpu_ppc_t *,ppc_insn_t) = NULL; struct ppc32_insn_exec_tag *tag; int index; #if DEBUG_INSN_PERF_CNT cpu->perf_counter++;#endif /* Lookup for instruction */ index = ilt_lookup(ilt,instruction); tag = ppc32_exec_get_insn(index); exec = tag->exec;#if NJM_STATS_ENABLE cpu->insn_exec_count++; ppc32_exec_tags[index].count++;#endif return(exec(cpu,instruction));}/* Execute a single instruction (external) */fastcall int ppc32_exec_single_insn_ext(cpu_ppc_t *cpu,ppc_insn_t insn){ int res; res = ppc32_exec_single_instruction(cpu,insn); if (likely(!res)) cpu->ia += sizeof(ppc_insn_t); return(res);}/* Execute a page */fastcall int ppc32_exec_page(cpu_ppc_t *cpu){ m_uint32_t exec_page,offset; ppc_insn_t insn; int res; exec_page = cpu->ia & ~PPC32_MIN_PAGE_IMASK; cpu->njm_exec_page = exec_page; cpu->njm_exec_ptr = cpu->mem_op_lookup(cpu,exec_page,PPC32_MTS_ICACHE); do { offset = (cpu->ia & PPC32_MIN_PAGE_IMASK) >> 2; insn = vmtoh32(cpu->njm_exec_ptr[offset]); res = ppc32_exec_single_instruction(cpu,insn); if (likely(!res)) cpu->ia += sizeof(ppc_insn_t); }while((cpu->ia & ~PPC32_MIN_PAGE_IMASK) == exec_page); return(0);}/* Run PowerPC code in step-by-step mode */void *ppc32_exec_run_cpu(cpu_gen_t *gen){ cpu_ppc_t *cpu = CPU_PPC32(gen); pthread_t timer_irq_thread; int timer_irq_check = 0; ppc_insn_t insn; int res; if (pthread_create(&timer_irq_thread,NULL, (void *)ppc32_timer_irq_run,cpu)) { fprintf(stderr,"VM '%s': unable to create Timer IRQ thread for CPU%u.\n", cpu->vm->name,gen->id); cpu_stop(gen); return NULL; } gen->cpu_thread_running = TRUE; cpu_exec_loop_set(gen); start_cpu: for(;;) { if (unlikely(gen->state != CPU_STATE_RUNNING)) break; /* Check IRQ */ if (unlikely(cpu->irq_check)) ppc32_trigger_irq(cpu); /* Handle virtual idle loop */ if (unlikely(cpu->ia == cpu->idle_pc)) { if (++gen->idle_count == gen->idle_max) { cpu_idle_loop(gen); gen->idle_count = 0; } } /* Handle the virtual CPU clock */ if (++timer_irq_check == cpu->timer_irq_check_itv) { timer_irq_check = 0; if (cpu->timer_irq_pending && !cpu->irq_disable && (cpu->msr & PPC32_MSR_EE)) { cpu->timer_irq_armed = 0; cpu->timer_irq_pending--; vm_set_irq(cpu->vm,0); //ppc32_trigger_timer_irq(cpu); } } /* Increment the time base */ cpu->tb += 100; /* Fetch and execute the instruction */ ppc32_exec_fetch(cpu,cpu->ia,&insn); res = ppc32_exec_single_instruction(cpu,insn); /* Normal flow ? */ if (likely(!res)) cpu->ia += sizeof(ppc_insn_t); } /* Check regularly if the CPU has been restarted */ while(gen->cpu_thread_running) { gen->seq_state++; switch(gen->state) { case CPU_STATE_RUNNING: gen->state = CPU_STATE_RUNNING; goto start_cpu; case CPU_STATE_HALTED: gen->cpu_thread_running = FALSE; pthread_join(timer_irq_thread,NULL); break; } /* CPU is paused */ usleep(200000); } return NULL;}/* ========================================================================= *//* Update CR0 */static forced_inline void ppc32_exec_update_cr0(cpu_ppc_t *cpu,m_uint32_t val){ m_uint32_t res; if (val & 0x80000000) res = 1 << PPC32_CR_LT_BIT; else { if (val > 0) res = 1 << PPC32_CR_GT_BIT; else res = 1 << PPC32_CR_EQ_BIT; } if (cpu->xer & PPC32_XER_SO) res |= 1 << PPC32_CR_SO_BIT; cpu->cr_fields[0] = res;}/* * Update Overflow bit from a sum result (r = a + b) * * (a > 0) && (b > 0) => r > 0, otherwise overflow * (a < 0) && (a < 0) => r < 0, otherwise overflow. */static forced_inline void ppc32_exec_ov_sum(cpu_ppc_t *cpu,m_uint32_t r, m_uint32_t a,m_uint32_t b){ register m_uint32_t sc; sc = (~(a ^ b) & (a ^ r) & 0x80000000); if (unlikely(sc)) cpu->xer |= PPC32_XER_SO | PPC32_XER_OV; else cpu->xer &= ~PPC32_XER_OV;}/* * Update Overflow bit from a substraction result (r = a - b) * * (a > 0) && (b < 0) => r > 0, otherwise overflow * (a < 0) && (a > 0) => r < 0, otherwise overflow. */static forced_inline void ppc32_exec_ov_sub(cpu_ppc_t *cpu,m_uint32_t r, m_uint32_t a,m_uint32_t b){ register m_uint32_t sc; sc = ((a ^ b) & (a ^ r) & 0x80000000); if (unlikely(sc)) cpu->xer |= PPC32_XER_SO | PPC32_XER_OV; else cpu->xer &= ~PPC32_XER_OV;}/* * Update CA bit from a sum result (r = a + b) */static forced_inline void ppc32_exec_ca_sum(cpu_ppc_t *cpu,m_uint32_t r, m_uint32_t a,m_uint32_t b){ cpu->xer_ca = (r < a) ? 1 : 0;}/* * Update CA bit from a substraction result (r = a - b) */static forced_inline void ppc32_exec_ca_sub(cpu_ppc_t *cpu,m_uint32_t r, m_uint32_t a,m_uint32_t b){ cpu->xer_ca = (b > a) ? 1 : 0;}/* Check condition code */static forced_inline int ppc32_check_cond(cpu_ppc_t *cpu,m_uint32_t bo, m_uint32_t bi){ u_int ctr_ok = TRUE; u_int cond_ok; u_int cr_bit; if (!(bo & 0x04)) { cpu->ctr--; ctr_ok = (cpu->ctr != 0) ^ ((bo >> 1) & 0x1); } cr_bit = ppc32_read_cr_bit(cpu,bi); cond_ok = (bo >> 4) | ((cr_bit ^ (~bo >> 3)) & 0x1); return(ctr_ok & cond_ok);}/* MFLR - Move From Link Register */static fastcall int ppc32_exec_MFLR(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); cpu->gpr[rd] = cpu->lr; return(0);}/* MTLR - Move To Link Register */static fastcall int ppc32_exec_MTLR(cpu_ppc_t *cpu,ppc_insn_t insn){ int rs = bits(insn,21,25); cpu->lr = cpu->gpr[rs]; return(0);}/* MFCTR - Move From Counter Register */static fastcall int ppc32_exec_MFCTR(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); cpu->gpr[rd] = cpu->ctr; return(0);}/* MTCTR - Move To Counter Register */static fastcall int ppc32_exec_MTCTR(cpu_ppc_t *cpu,ppc_insn_t insn){ int rs = bits(insn,21,25); cpu->ctr = cpu->gpr[rs]; return(0);}/* ADD */static fastcall int ppc32_exec_ADD(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); cpu->gpr[rd] = cpu->gpr[ra] + cpu->gpr[rb]; return(0);}/* ADD. */static fastcall int ppc32_exec_ADD_dot(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t tmp; tmp = cpu->gpr[ra] + cpu->gpr[rb]; ppc32_exec_update_cr0(cpu,tmp); cpu->gpr[rd] = tmp; return(0);}/* ADDO - Add with Overflow */static fastcall int ppc32_exec_ADDO(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ov_sum(cpu,d,a,b); cpu->gpr[rd] = d; return(0);}/* ADDO. */static fastcall int ppc32_exec_ADDO_dot(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ov_sum(cpu,d,a,b); ppc32_exec_update_cr0(cpu,d); cpu->gpr[rd] = d; return(0);}/* ADDC - Add Carrying */static fastcall int ppc32_exec_ADDC(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ca_sum(cpu,d,a,b); cpu->gpr[rd] = d; return(0);}/* ADDC. */static fastcall int ppc32_exec_ADDC_dot(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ca_sum(cpu,d,a,b); ppc32_exec_update_cr0(cpu,d); cpu->gpr[rd] = d; return(0);}/* ADDCO - Add Carrying with Overflow */static fastcall int ppc32_exec_ADDCO(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ca_sum(cpu,d,a,b); ppc32_exec_ov_sum(cpu,d,a,b); cpu->gpr[rd] = d; return(0);}/* ADDCO. */static fastcall int ppc32_exec_ADDCO_dot(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b; ppc32_exec_ca_sum(cpu,d,a,b); ppc32_exec_ov_sum(cpu,d,a,b); ppc32_exec_update_cr0(cpu,d); cpu->gpr[rd] = d; return(0);}/* ADDE - Add Extended */static fastcall int ppc32_exec_ADDE(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; m_uint32_t carry; carry = cpu->xer_ca; cpu->xer_ca = 0; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b + carry; if (((b + carry) < b) || (d < a)) cpu->xer_ca = 1; cpu->gpr[rd] = d; return(0);}/* ADDE. */static fastcall int ppc32_exec_ADDE_dot(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; m_uint32_t carry; carry = cpu->xer_ca; cpu->xer_ca = 0; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b + carry; if (((b + carry) < b) || (d < a)) cpu->xer_ca = 1; ppc32_exec_update_cr0(cpu,d); cpu->gpr[rd] = d; return(0);}/* ADDEO - Add Extended with Overflow */static fastcall int ppc32_exec_ADDEO(cpu_ppc_t *cpu,ppc_insn_t insn){ int rd = bits(insn,21,25); int ra = bits(insn,16,20); int rb = bits(insn,11,15); register m_uint32_t a,b,d; m_uint32_t carry; carry = cpu->xer_ca; cpu->xer_ca = 0; a = cpu->gpr[ra]; b = cpu->gpr[rb]; d = a + b + carry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -