void dec_DynamicSet(u32 regbase,u32 offs=0) { if (offs==0) Emit(shop_jdyn,reg_pc_dyn,mk_reg((Sh4RegType)regbase)); else Emit(shop_jdyn,reg_pc_dyn,mk_reg((Sh4RegType)regbase),mk_imm(offs)); }
/* * Generate code to pop a register from the stack. */ static void g_pop P2 (REG, reg, DEEP, depth) { ADDRESS *ap; /* check on stack underflow */ if (stack_depth-- == EMPTY) { FATAL ((__FILE__, "g_pop", "register stack empty")); } /* check if the desired register really is on stack */ if (reg_stack[stack_depth].depth != depth) { FATAL ( (__FILE__, "g_pop", "register order (%d,%d)", (int) depth, (int) reg_stack[stack_depth].depth)); } /* check if the register which is restored is really void */ if (reg_in_use[reg] != UNUSED) { FATAL ((__FILE__, "g_pop", "register %d in use", (int) reg)); } reg_in_use[reg] = depth; sync_stack (); ap = mk_reg (reg); switch (reg) { case D0: case D1: case D2: case D3: case D4: case D5: case D6: case D7: case A0: case A1: case A2: case A3: case A4: case A5: case A6: case A7: g_move (IL4, &apop, ap); break; #ifdef FLOAT_IEEE case FP0: case FP1: case FP2: case FP3: case FP4: case FP5: case FP6: case FP7: g_fcode (op_fmove, IL12, &apop, ap); break; #endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); } /* clear the push_flag */ reg_alloc[depth].pushed = FALSE; }
static Exp *translate_get_reg_32( int offset ) { assert(offset >= 0); Temp *reg = mk_reg(reg_offset_to_name(offset), REG_32); return reg; }
/* * Allocate a temporary floating point register and return it's * addressing mode. */ ADDRESS *float_register P0 (void) { ADDRESS *ap = mk_reg (next_float); next_float = allocate_register (next_float, F_REG); ap->deep = reg_in_use[ap->preg]; return ap; }
/* * Allocate a temporary addr register and return it's addressing mode. */ ADDRESS *address_register P0 (void) { ADDRESS *ap = mk_reg (next_addr); next_addr = allocate_register (next_addr, A_REG); ap->deep = reg_in_use[ap->preg]; return ap; }
/* * Allocate a temporary data register and return * it's addressing mode. */ ADDRESS *data_register P0 (void) { ADDRESS *ap = mk_reg (next_data); next_data = allocate_register (next_data, D_REG); ap->deep = reg_in_use[ap->preg]; return ap; }
static Stmt *translate_put_reg_32( int offset, Exp *data, IRSB *irbb ) { assert(data); Temp *reg = mk_reg(reg_offset_to_name(offset), REG_32); return new Move( reg, data ); }
static BOOL is_exchangable P2 (ADDRESS **, apptr, REG, reg) { ADDRESS *ap = *apptr; switch (ap->mode) { case am_dreg: case am_freg: if ((ap->preg <= MAX_DATA) && (is_data_register (reg)) /* * to avoid endless exchanges do replaces only higher * registernumbers with lower registernumbers */ && (reg < ap->preg)) { /* * replace only if temporary */ *apptr = mk_reg (reg); (*apptr)->mode = ap->mode; DPRINTF ((DEBUG_FLOW, " and replaced\n")); return TRUE; } break; case am_ireg: case am_sreg: break; case am_areg: if (((!is_address_register (reg)) || (ap->preg <= MAX_ADDR)) /* * to avoid endless exchanges do replaces only higher * registernumbers with lower registernumbers */ && ((reg < ap->preg) || (is_index_register (reg)))) { *apptr = mk_reg (reg); DPRINTF ((DEBUG_FLOW, " and replaced\n")); return TRUE; } break; default: *apptr = mk_reg (reg); DPRINTF ((DEBUG_FLOW, " and replaced\n")); return TRUE; } DPRINTF ((DEBUG_FLOW, " but not changed\n")); return FALSE; }
/* make (or delete) an object in the filesystem */ gboolean mk_obj(FILE * in, char *p, struct rdup * e, GHashTable * uidhash, GHashTable * gidhash) { if (opt_verbose >= 1 && e->f_name) { if (S_ISLNK(e->f_mode) || e->f_lnk) fprintf(stderr, "%s -> %s\n", e->f_name, e->f_target); else fprintf(stderr, "%s\n", e->f_name); } if (opt_table) rdup_write_table(e, stdout); /* split here - or above - return when path is zero length * for links check that the f_size is zero */ switch (e->plusmin) { case MINUS: if (opt_dry || !e->f_name) return TRUE; return rm(e->f_name); case PLUS: /* opt_dry handled within the subfunctions */ /* only files, no hardlinks! */ if (S_ISREG(e->f_mode) && !e->f_lnk) return mk_reg(in, e, uidhash, gidhash); /* no name, we can exit here - for files this is handled * in mk_reg, because we may need to suck in data */ if (e->f_name == NULL) return TRUE; if (S_ISDIR(e->f_mode)) return mk_dir(e, uidhash, gidhash); /* First sym and hardlinks and then regular files */ if (S_ISLNK(e->f_mode) || e->f_lnk) return mk_link(e, p, uidhash, gidhash); if (S_ISBLK(e->f_mode) || S_ISCHR(e->f_mode)) return mk_dev(e, uidhash, gidhash); // There's no way to restore a named socket if (S_ISSOCK(e->f_mode)) return TRUE; if (S_ISFIFO(e->f_mode)) return mk_sock(e, uidhash, gidhash); } /* only reached during the heat death of the universe */ return TRUE; }
/* * This routine generates code to push a register onto the stack. */ static void g_push P2 (REG, reg, DEEP, depth) { ADDRESS *ap; sync_stack (); ap = mk_reg (reg); switch (reg) { case D0: case D1: case D2: case D3: case D4: case D5: case D6: case D7: case A0: case A1: case A2: case A3: case A4: case A5: case A6: case A7: g_move (IL4, ap, &apush); break; #ifdef FLOAT_IEEE case FP0: case FP1: case FP2: case FP3: case FP4: case FP5: case FP6: case FP7: g_fcode (op_fmove, IL12, ap, &apush); break; #endif /* FLOAT_IEEE */ default: CANNOT_REACH_HERE (); } reg_stack[stack_depth].reg = reg; reg_stack[stack_depth].depth = depth; if (reg_alloc[depth].pushed) { FATAL ((__FILE__, "g_push", "reg %d already pushed", (int) reg)); } reg_alloc[depth].pushed = TRUE; /* check on stack overflow */ if (++stack_depth > MAX_REG_STACK) { FATAL ((__FILE__, "g_push", "register stack overflow")); } }
/* * this routine generates code to push a register onto the stack */ static void g_push P2 (REG, reg, DEEP, number) { ADDRESS *ap; ap = mk_reg (reg); g_code (op_mov, cc_al, ap, NIL_ADDRESS, NIL_ADDRESS); reg_stack[reg_stack_ptr].reg = reg; reg_stack[reg_stack_ptr].depth = number; /* is already pushed */ if (reg_alloc[number].pushed) { FATAL ((__FILE__, "g_push", "1")); } reg_alloc[number].pushed = TRUE; /* check on stack overflow */ if (++reg_stack_ptr > MAX_REG_STACK) { FATAL ((__FILE__, "g_push", "2")); } }
void dec_End(u32 dst,BlockEndType flags,bool delay) { if (state.ngen.OnlyDynamicEnds && flags == BET_StaticJump) { Emit(shop_mov32,mk_reg(reg_nextpc),mk_imm(dst)); dec_DynamicSet(reg_nextpc); dec_End(0xFFFFFFFF,BET_DynamicJump,delay); return; } if (state.ngen.OnlyDynamicEnds) { verify(flags == BET_DynamicJump); } state.BlockType=flags; state.NextOp=delay?NDO_Delayslot:NDO_End; state.DelayOp=NDO_End; state.JumpAddr=dst; state.NextAddr=state.cpu.rpc+2+(delay?2:0); }
/* * generate code to pop a register from the stack. */ static void g_pop P2 (REG, reg, DEEP, number) { ADDRESS *ap; /* check on stack underflow */ if (reg_stack_ptr-- == EMPTY) { FATAL ((__FILE__, "g_pop", "1")); } /* check if the desired register really is on stack */ if (reg_stack[reg_stack_ptr].depth != number) { FATAL ((__FILE__, "g_pop", "2")); } /* check if the register which is restored is really void */ if (reg_in_use[reg] != UNUSED) { FATAL ((__FILE__, "g_pop", "3")); } reg_in_use[reg] = number; ap = mk_reg (reg); g_code (op_mov, cc_al, ap, NIL_ADDRESS, NIL_ADDRESS); /* clear the push_flag */ reg_alloc[number].pushed = FALSE; }
/* * allocate a register */ ADDRESS *data_register P0 (void) { ADDRESS *ap; /* * if the register is in use, push it to the stack */ if (reg_in_use[next_reg] != UNUSED) { g_push (next_reg, reg_in_use[next_reg]); } reg_in_use[next_reg] = reg_depth; ap = mk_reg (next_reg); ap->deep = reg_depth; reg_alloc[reg_depth].reg = next_reg; reg_alloc[reg_depth].pushed = FALSE; if (next_reg++ == max_reg) { next_reg = R0; /* wrap around */ } if (reg_depth++ == MAX_REG_STACK) { FATAL ((__FILE__, "data_register", "")); } return ap; }
void dec_param(DecParam p,shil_param& r1,shil_param& r2, u32 op) { switch(p) { //constants case PRM_PC_D8_x2: r1=mk_imm((state.cpu.rpc+4)+(GetImm8(op)<<1)); break; case PRM_PC_D8_x4: r1=mk_imm(((state.cpu.rpc+4)&0xFFFFFFFC)+(GetImm8(op)<<2)); break; case PRM_ZERO: r1= mk_imm(0); break; case PRM_ONE: r1= mk_imm(1); break; case PRM_TWO: r1= mk_imm(2); break; case PRM_TWO_INV: r1= mk_imm(~2); break; case PRM_ONE_F32: r1= mk_imm(0x3f800000); break; //imms case PRM_SIMM8: r1=mk_imm(GetSImm8(op)); break; case PRM_UIMM8: r1=mk_imm(GetImm8(op)); break; //direct registers case PRM_R0: r1=mk_reg(reg_r0); break; case PRM_RN: r1=mk_regi(reg_r0+GetN(op)); break; case PRM_RM: r1=mk_regi(reg_r0+GetM(op)); break; case PRM_FRN_SZ: if (state.cpu.FSZ64) { int rx=GetN(op)/2; if (GetN(op)&1) rx+=regv_xd_0; else rx+=regv_dr_0; r1=mk_regi(rx); break; } case PRM_FRN: r1=mk_regi(reg_fr_0+GetN(op)); break; case PRM_FRM_SZ: if (state.cpu.FSZ64) { int rx=GetM(op)/2; if (GetM(op)&1) rx+=regv_xd_0; else rx+=regv_dr_0; r1=mk_regi(rx); break; } case PRM_FRM: r1=mk_regi(reg_fr_0+GetM(op)); break; case PRM_FPUL: r1=mk_regi(reg_fpul); break; case PRM_FPN: //float pair, 3 bits r1=mk_regi(regv_dr_0+GetN(op)/2); break; case PRM_FVN: //float quad, 2 bits r1=mk_regi(regv_fv_0+GetN(op)/4); break; case PRM_FVM: //float quad, 2 bits r1=mk_regi(regv_fv_0+(GetN(op)&0x3)); break; case PRM_XMTRX: //float matrix, 0 bits r1=mk_regi(regv_xmtrx); break; case PRM_FRM_FR0: r1=mk_regi(reg_fr_0+GetM(op)); r2=mk_regi(reg_fr_0); break; case PRM_SR_T: r1=mk_regi(reg_sr_T); break; case PRM_SR_STATUS: r1=mk_regi(reg_sr_status); break; case PRM_SREG: //FPUL/FPSCR/MACH/MACL/PR/DBR/SGR r1=mk_regi(SREGS[GetM(op)]); break; case PRM_CREG: //SR/GBR/VBR/SSR/SPC/<RM_BANK> r1=mk_regi(CREGS[GetM(op)]); break; //reg/imm reg/reg case PRM_RN_D4_x1: case PRM_RN_D4_x2: case PRM_RN_D4_x4: { u32 shft=p-PRM_RN_D4_x1; r1=mk_regi(reg_r0+GetN(op)); r2=mk_imm(GetImm4(op)<<shft); } break; case PRM_RN_R0: r1=mk_regi(reg_r0+GetN(op)); r2=mk_regi(reg_r0); break; case PRM_RM_D4_x1: case PRM_RM_D4_x2: case PRM_RM_D4_x4: { u32 shft=p-PRM_RM_D4_x1; r1=mk_regi(reg_r0+GetM(op)); r2=mk_imm(GetImm4(op)<<shft); } break; case PRM_RM_R0: r1=mk_regi(reg_r0+GetM(op)); r2=mk_regi(reg_r0); break; case PRM_GBR_D8_x1: case PRM_GBR_D8_x2: case PRM_GBR_D8_x4: { u32 shft=p-PRM_GBR_D8_x1; r1=mk_regi(reg_gbr); r2=mk_imm(GetImm8(op)<<shft); } break; default: die("Non-supported parameter used"); } }
shil_param mk_regi(int reg) { return mk_reg((Sh4RegType)reg); }
void dec_write_sr(shil_param src) { Emit(shop_and,mk_reg(reg_sr_status),src,mk_imm(SR_STATUS_MASK)); Emit(shop_and,mk_reg(reg_sr_T),src,mk_imm(SR_T_MASK)); }
bool dec_generic(u32 op) { DecMode mode;DecParam d;DecParam s;shilop natop;u32 e; if (OpDesc[op]->decode==0) return false; u64 inf=OpDesc[op]->decode; e=(u32)(inf>>32); mode=(DecMode)((inf>>24)&0xFF); d=(DecParam)((inf>>16)&0xFF); s=(DecParam)((inf>>8)&0xFF); natop=(shilop)((inf>>0)&0xFF); /* if ((op&0xF00F)==0x300E) { return false; }*/ /* if (mode==DM_ADC) return false; */ bool transfer_64=false; if (op>=0xF000) { state.info.has_fpu=true; //return false;//FPU off for now if (state.cpu.FPR64 /*|| state.cpu.FSZ64*/) return false; if (state.cpu.FSZ64 && (d==PRM_FRN_SZ || d==PRM_FRM_SZ || s==PRM_FRN_SZ || s==PRM_FRM_SZ)) { transfer_64=true; } } shil_param rs1,rs2,rs3,rd; dec_param(s,rs2,rs3,op); dec_param(d,rs1,rs3,op); switch(mode) { case DM_ReadSRF: Emit(shop_mov32,rs1,reg_sr_status); Emit(shop_or,rs1,rs1,reg_sr_T); break; case DM_WriteTOp: Emit(natop,reg_sr_T,rs1,rs2); break; case DM_DT: verify(natop==shop_sub); Emit(natop,rs1,rs1,rs2); Emit(shop_seteq,mk_reg(reg_sr_T),rs1,mk_imm(0)); break; case DM_Shift: if (natop==shop_shl && e==1) Emit(shop_shr,mk_reg(reg_sr_T),rs1,mk_imm(31)); else if (e==1) Emit(shop_and,mk_reg(reg_sr_T),rs1,mk_imm(1)); Emit(natop,rs1,rs1,mk_imm(e)); break; case DM_Rot: if (!(((s32)e>=0?e:-e)&0x1000)) { if ((s32)e<0) { //left rotate Emit(shop_shr,mk_reg(reg_sr_T),rs2,mk_imm(31)); e=-e; } else { //right rotate Emit(shop_and,mk_reg(reg_sr_T),rs2,mk_imm(1)); } } e&=31; Emit(natop,rs1,rs2,mk_imm(e)); break; case DM_BinaryOp://d=d op s if (e&1) Emit(natop,rs1,rs1,rs2,0,rs3); else Emit(natop,shil_param(),rs1,rs2,0,rs3); break; case DM_UnaryOp: //d= op s if (transfer_64 && natop==shop_mov32) natop=shop_mov64; if (natop==shop_cvt_i2f_n && state.cpu.RoundToZero) natop=shop_cvt_i2f_z; if (e&1) Emit(natop,shil_param(),rs1); else Emit(natop,rs1,rs2); break; case DM_WriteM: //write(d,s) { //0 has no effect, so get rid of it if (rs3.is_imm() && rs3._imm==0) rs3=shil_param(); state.info.has_writem=true; if (transfer_64) e=(s32)e*2; bool update_after=false; if ((s32)e<0) { if (rs1._reg!=rs2._reg) //reg shouldn't be updated if its written { Emit(shop_sub,rs1,rs1,mk_imm(-e)); } else { verify(rs3.is_null()); rs3=mk_imm(e); update_after=true; } } Emit(shop_writem,shil_param(),rs1,rs2,(s32)e<0?-e:e,rs3); if (update_after) { Emit(shop_sub,rs1,rs1,mk_imm(-e)); } } break; case DM_ReadM: //0 has no effect, so get rid of it if (rs3.is_imm() && rs3._imm==0) rs3=shil_param(); state.info.has_readm=true; if (transfer_64) e=(s32)e*2; Emit(shop_readm,rs1,rs2,shil_param(),(s32)e<0?-e:e,rs3); if ((s32)e<0) { if (rs1._reg!=rs2._reg)//the reg shouldn't be updated if it was just read. Emit(shop_add,rs2,rs2,mk_imm(-e)); } break; case DM_fiprOp: { shil_param rdd=mk_regi(rs1._reg+3); Emit(natop,rdd,rs1,rs2); } break; case DM_EXTOP: { Emit(natop,rs1,rs2,mk_imm(e==1?0xFF:0xFFFF)); } break; case DM_MUL: { shilop op; shil_param rd=mk_reg(reg_macl); shil_param rd2=shil_param(); switch((s32)e) { case 16: op=shop_mul_u16; break; case -16: op=shop_mul_s16; break; case -32: op=shop_mul_i32; break; case 64: op=shop_mul_u64; rd2 = mk_reg(reg_mach); break; case -64: op=shop_mul_s64; rd2 = mk_reg(reg_mach); break; default: die("DM_MUL: Failed to classify opcode"); } Emit(op,rd,rs1,rs2,0,shil_param(),rd2); } break; case DM_DIV0: { if (e==1) { if (MatchDiv32u(op,state.cpu.rpc)) { verify(!state.cpu.is_delayslot); //div32u Emit(shop_div32u,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_reg(div_som_reg2),0,shil_param(),mk_reg(div_som_reg3)); Emit(shop_and,mk_reg(reg_sr_T),mk_reg(div_som_reg1),mk_imm(1)); Emit(shop_shr,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_imm(1)); Emit(shop_div32p2,mk_reg(div_som_reg3),mk_reg(div_som_reg3),mk_reg(div_som_reg2),0,shil_param(reg_sr_T)); //skip the aggregated opcodes state.cpu.rpc+=128; blk->guest_cycles+=CPU_RATIO*64; } else { //clear QM (bits 8,9) u32 qm=(1<<8)|(1<<9); Emit(shop_and,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_imm(~qm)); //clear T ! Emit(shop_mov32,mk_reg(reg_sr_T),mk_imm(0)); } } else { if (MatchDiv32s(op,state.cpu.rpc)) { verify(!state.cpu.is_delayslot); //div32s Emit(shop_div32s,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_reg(div_som_reg2),0,shil_param(),mk_reg(div_som_reg3)); Emit(shop_and,mk_reg(reg_sr_T),mk_reg(div_som_reg1),mk_imm(1)); Emit(shop_sar,mk_reg(div_som_reg1),mk_reg(div_som_reg1),mk_imm(1)); Emit(shop_div32p2,mk_reg(div_som_reg3),mk_reg(div_som_reg3),mk_reg(div_som_reg2),0,shil_param(reg_sr_T)); //skip the aggregated opcodes state.cpu.rpc+=128; blk->guest_cycles+=CPU_RATIO*64; } else { //sr.Q=r[n]>>31; //sr.M=r[m]>>31; //sr.T=sr.M^sr.Q; //This is nasty because there isn't a temp reg .. //VERY NASTY //Clear Q & M Emit(shop_and,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_imm(~((1<<8)|(1<<9)))); //sr.Q=r[n]>>31; Emit(shop_sar,mk_reg(reg_sr_T),rs1,mk_imm(31)); Emit(shop_and,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(1<<8)); Emit(shop_or,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_reg(reg_sr_T)); //sr.M=r[m]>>31; Emit(shop_sar,mk_reg(reg_sr_T),rs2,mk_imm(31)); Emit(shop_and,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(1<<9)); Emit(shop_or,mk_reg(reg_sr_status),mk_reg(reg_sr_status),mk_reg(reg_sr_T)); //sr.T=sr.M^sr.Q; Emit(shop_xor,mk_reg(reg_sr_T),rs1,rs2); Emit(shop_shr,mk_reg(reg_sr_T),mk_reg(reg_sr_T),mk_imm(31)); } } } break; case DM_ADC: { Emit(natop,rs1,rs1,rs2,0,mk_reg(reg_sr_T),mk_reg(reg_sr_T)); } break; default: verify(false); } return true; }