📄 ppc32_jit.c
字号:
case JIT_OP_BRANCH_TARGET: case JIT_OP_EOB: ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS); for(j=0;j<8;j++) last_cr_update[j] = NULL; break; /* Branch jump: clear "store" operation status */ case JIT_OP_BRANCH_JUMP: for(j=0;j<PPC32_GPR_NR;j++) ppc_map[j].last_store = NULL; for(j=0;j<8;j++) last_cr_update[j] = NULL; break; /* Alteration of a specific host register */ case JIT_OP_ALTER_HOST_REG: reg = op->param[0]; if (reg != JIT_OP_ALL_REGS) { if (host_map[reg] != JIT_OP_INV_REG) ppc32_clear_ppc_reg_map(ppc_map,host_map,host_map[reg]); } else { ppc32_clear_ppc_reg_map(ppc_map,host_map,JIT_OP_ALL_REGS); } break; /* Save reg mapping and last operation */ case JIT_OP_STORE_GPR: reg = op->param[0]; map = &ppc_map[op->param[1]]; /* clear old mapping */ if (reg != map->host_reg) { ppc32_clear_host_reg_map(ppc_map,host_map,reg); ppc32_clear_ppc_reg_map(ppc_map,host_map,op->param[1]); } /* cancel previous store op for this PPC register */ if (map->last_store) { map->last_store->param[0] = JIT_OP_INV_REG; map->last_store = NULL; } map->host_reg = reg; map->last_store = op; map->last_store_ia = cur_ia; host_map[reg] = op->param[1]; break; /* Load reg: check if can avoid it */ case JIT_OP_LOAD_GPR: reg = op->param[0]; map = &ppc_map[op->param[1]]; if (reg == map->host_reg) { /* Cancel this load */ op->param[0] = JIT_OP_INV_REG; } else { /* clear old mapping */ ppc32_clear_host_reg_map(ppc_map,host_map,reg); ppc32_clear_ppc_reg_map(ppc_map,host_map,op->param[1]); /* Save this reg mapping */ map->host_reg = op->param[0]; map->last_store = NULL; host_map[op->param[0]] = op->param[1]; } break; /* Trash flags */ case JIT_OP_TRASH_FLAGS: for(j=0;j<8;j++) last_cr_update[j] = NULL; break; /* Flags required */ case JIT_OP_REQUIRE_FLAGS: if (op->param[0] != JIT_OP_PPC_ALL_FLAGS) { last_cr_update[op->param[0]] = NULL; } else { for(j=0;j<8;j++) last_cr_update[j] = NULL; } break; /* Update flags */ case JIT_OP_UPDATE_FLAGS: opx = last_cr_update[op->param[0]]; if (opx != NULL) opx->param[0] = JIT_OP_INV_REG; last_cr_update[op->param[0]] = op; break; } } }}/* Generate the JIT code for the specified JIT op list */static void ppc32_op_gen_list(ppc32_jit_tcb_t *b,int ipos,jit_op_t *op_list, u_char *jit_start){ jit_op_t *op; for(op=op_list;op;op=op->next) { switch(op->opcode) { case JIT_OP_INSN_OUTPUT: ppc32_op_insn_output(b,op); break; case JIT_OP_LOAD_GPR: ppc32_op_load_gpr(b,op); break; case JIT_OP_STORE_GPR: ppc32_op_store_gpr(b,op); break; case JIT_OP_UPDATE_FLAGS: ppc32_op_update_flags(b,op); break; case JIT_OP_BRANCH_TARGET: b->jit_insn_ptr[ipos] = jit_start; break; case JIT_OP_MOVE_HOST_REG: ppc32_op_move_host_reg(b,op); break; case JIT_OP_SET_HOST_REG_IMM32: ppc32_op_set_host_reg_imm32(b,op); break; } }}/* Opcode emit start */static inline void ppc32_op_emit_start(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b){ cpu_gen_t *c = cpu->gen; jit_op_t *op; if (c->jit_op_array[b->ppc_trans_pos] == NULL) c->jit_op_current = &c->jit_op_array[b->ppc_trans_pos]; else { for(op=c->jit_op_array[b->ppc_trans_pos];op;op=op->next) c->jit_op_current = &op->next; }}/* Generate the JIT code for the current page, given an op list */static int ppc32_op_gen_page(cpu_ppc_t *cpu,ppc32_jit_tcb_t *b){ struct ppc32_insn_tag *tag; cpu_gen_t *gcpu = cpu->gen; jit_op_t *iop; m_uint32_t cur_ia; u_char *jit_ptr; int i; /* Generate JIT opcodes */ for(b->ppc_trans_pos=0; b->ppc_trans_pos<PPC32_INSN_PER_PAGE; b->ppc_trans_pos++) { ppc32_op_emit_start(cpu,b); cur_ia = b->start_ia + (b->ppc_trans_pos << 2); if (ppc32_jit_tcb_get_target_bit(b,cur_ia)) ppc32_op_emit_basic_opcode(cpu,JIT_OP_BRANCH_TARGET);#if DEBUG_INSN_PERF_CNT ppc32_inc_perf_counter(cpu);#endif#if BREAKPOINT_ENABLE if (cpu->breakpoints_enabled) insn_emit_breakpoint(cpu,b);#endif if (unlikely(!(tag = ppc32_jit_fetch_and_emit(cpu,b)))) { fprintf(stderr,"ppc32_op_gen_page: unable to fetch instruction.\n"); return(-1); } } /* * Mark the first instruction as a potential target, as well as the * current IA value. */ ppc32_op_emit_branch_target(cpu,b,b->start_ia); ppc32_op_emit_branch_target(cpu,b,cpu->ia); /* Optimize condition register and general registers */ ppc32_op_optimize(gcpu,b); /* Generate JIT code for each instruction in page */ for(i=0;i<PPC32_INSN_PER_PAGE;i++) { jit_ptr = b->jit_ptr; /* Generate output code */ ppc32_op_gen_list(b,i,gcpu->jit_op_array[i],jit_ptr); /* Adjust the JIT buffer if its size is not sufficient */ ppc32_jit_tcb_adjust_buffer(cpu,b); } /* Apply patches and free opcodes */ for(i=0;i<PPC32_INSN_PER_PAGE;i++) { for(iop=gcpu->jit_op_array[i];iop;iop=iop->next) if (iop->opcode == JIT_OP_INSN_OUTPUT) ppc32_jit_tcb_apply_patches(cpu,b,iop); jit_op_free_list(gcpu,gcpu->jit_op_array[i]); gcpu->jit_op_array[i] = NULL; } /* Add end of page (returns to caller) */ ppc32_set_page_jump(cpu,b); /* Free patch tables */ ppc32_jit_tcb_free_patches(b); return(0);}/* ======================================================================== *//* Compile a PowerPC instruction page */static inline ppc32_jit_tcb_t *ppc32_jit_tcb_compile(cpu_ppc_t *cpu,m_uint32_t vaddr){ ppc32_jit_tcb_t *block; m_uint32_t page_addr; page_addr = vaddr & ~PPC32_MIN_PAGE_IMASK; if (unlikely(!(block = ppc32_jit_tcb_create(cpu,page_addr)))) { fprintf(stderr,"insn_page_compile: unable to create JIT block.\n"); return NULL; } /* Allocate the array used to convert PPC code ptr to native code ptr */ if (!(block->jit_insn_ptr = calloc(PPC32_INSN_PER_PAGE,sizeof(u_char *)))) { fprintf(stderr,"insn_page_compile: unable to create JIT mappings.\n"); goto error; } /* Compile the page */ if (ppc32_op_gen_page(cpu,block) == -1) { fprintf(stderr,"insn_page_compile: unable to compile page.\n"); goto error; } /* Add the block to the linked list */ block->next = cpu->tcb_list; block->prev = NULL; if (cpu->tcb_list) cpu->tcb_list->prev = block; else cpu->tcb_last = block; cpu->tcb_list = block; /* Add the block to the physical mapping hash table */ block->phys_next = cpu->exec_phys_map[block->phys_hash]; block->phys_pprev = &cpu->exec_phys_map[block->phys_hash]; if (cpu->exec_phys_map[block->phys_hash] != NULL) cpu->exec_phys_map[block->phys_hash]->phys_pprev = &block->phys_next; cpu->exec_phys_map[block->phys_hash] = block; cpu->compiled_pages++; return block; error: ppc32_jit_tcb_free(cpu,block,FALSE); return NULL;}/* Recompile a page */int ppc32_jit_tcb_recompile(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block){#if 0 printf("PPC32-JIT: recompiling page 0x%8.8x\n",block->start_ia);#endif /* Free old code chunks */ ppc32_jit_tcb_free_code_chunks(cpu,block); /* Reset code ptr array */ memset(block->jit_insn_ptr,0,PPC32_INSN_PER_PAGE * sizeof(u_char *)); /* Allocate the first JIT buffer */ if (!(block->jit_buffer = exec_page_alloc(cpu))) return(-1); /* Recompile the page */ if (ppc32_op_gen_page(cpu,block) == -1) { fprintf(stderr,"insn_page_compile: unable to recompile page.\n"); return(-1); } block->target_undef_cnt = 0; return(0);}/* Run a compiled PowerPC instruction block */static forced_inlinevoid ppc32_jit_tcb_run(cpu_ppc_t *cpu,ppc32_jit_tcb_t *block){ if (unlikely(cpu->ia & 0x03)) { fprintf(stderr,"ppc32_jit_tcb_run: Invalid IA 0x%8.8x.\n",cpu->ia); ppc32_dump_regs(cpu->gen); ppc32_dump_mmu(cpu->gen); cpu_stop(cpu->gen); return; } /* Execute JIT compiled code */ ppc32_jit_tcb_exec(cpu,block);}/* Execute compiled PowerPC code */void *ppc32_jit_run_cpu(cpu_gen_t *gen){ cpu_ppc_t *cpu = CPU_PPC32(gen); pthread_t timer_irq_thread; ppc32_jit_tcb_t *block; m_uint32_t ia_hash; int timer_irq_check = 0; ppc32_jit_init_hreg_mapping(cpu); 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(cpu->gen); return NULL; } gen->cpu_thread_running = TRUE; cpu_exec_loop_set(gen); start_cpu: gen->idle_count = 0; for(;;) { if (unlikely(gen->state != CPU_STATE_RUNNING)) break;#if DEBUG_BLOCK_PERF_CNT cpu->perf_counter++;#endif /* 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); } } /* Check IRQs */ if (unlikely(cpu->irq_check)) ppc32_trigger_irq(cpu); /* Get the JIT block corresponding to IA register */ ia_hash = ppc32_jit_get_ia_hash(cpu->ia); block = cpu->exec_blk_map[ia_hash]; /* No block found, compile the page */ if (unlikely(!block) || unlikely(!ppc32_jit_tcb_match(cpu,block))) { if (block != NULL) { ppc32_jit_tcb_free(cpu,block,TRUE); cpu->exec_blk_map[ia_hash] = NULL; } block = ppc32_jit_tcb_compile(cpu,cpu->ia); if (unlikely(!block)) { fprintf(stderr, "VM '%s': unable to compile block for CPU%u IA=0x%8.8x\n", cpu->vm->name,gen->id,cpu->ia); cpu_stop(gen); break; } cpu->exec_blk_map[ia_hash] = block; }#if DEBUG_BLOCK_TIMESTAMP block->tm_last_use = jit_jiffies++;#endif block->acc_count++; ppc32_jit_tcb_run(cpu,block); } if (!cpu->ia) { cpu_stop(gen); cpu_log(gen,"JIT","IA=0, halting CPU.\n"); } /* 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -