void CodeGen::gen_x_cmp(JavaByteCodes op, jtype jt) { if (is_f(jt)) { char *helper; if (jt == dbl64) { assert(op == OPCODE_DCMPG || op == OPCODE_DCMPL); helper = op == OPCODE_DCMPG ? (char*)&rt_h_dcmp_g : (char*)&rt_h_dcmp_l; } else { assert(op == OPCODE_FCMPG || op == OPCODE_FCMPL); helper = op == OPCODE_FCMPG ? (char*)&rt_h_fcmp_g : (char*)&rt_h_fcmp_l; } const CallSig cs(CCONV_STDCALL, i32, jt, jt); unsigned stackFix = gen_stack_to_args(true, cs, 0); gen_call_novm(cs, helper, 2); if (stackFix != 0) { alu(alu_sub, sp, stackFix); } runlock(cs); gen_save_ret(cs); return; } assert(op == OPCODE_LCMP); char *helper = (char *)rt_h_lcmp; SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i32, i64, i64)); unsigned stackFix = gen_stack_to_args(true, cs, 0); gen_call_novm(cs, helper, 2); if (stackFix != 0) { alu(alu_sub, sp, stackFix); } runlock(cs); gen_save_ret(cs); }
/** * Generates monitor exit. * The code should not contain safepoints. * * @param[in] ss buffer to put the assembly code to * @param[in] input_param1 register should point to the lockword in object header. * If input_param1 == ecx it reduce one register mov. * The code use and do not restore eax, ecx registers. * @return 0 if success in eax register */ char* gen_monitor_exit_helper(char *ss, const R_Opnd & input_param1) { if (&input_param1 != &ecx_opnd) { ss = mov(ss, ecx_opnd, input_param1); } #ifdef ASM_MONITOR_HELPER ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 0)); // mov eax,dword[ecx] ss = test(ss, eax_opnd, Imm_Opnd(0x80000000), size_32); // test eax,0x80000000 ss = branch8(ss, Condition_NZ, Imm_Opnd(size_8, 0)); // jnz fat char *fat = ((char *)ss) - 1; ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8); // mov al, byte[ecx+1] ss = alu(ss, sub_opc, eax_opnd, Imm_Opnd(size_8,0x8),size_8); // sub al, 0x8 ss = branch8(ss, Condition_C, Imm_Opnd(size_8, 0)); // jc zero_rec char *zero_rec = ((char *)ss) - 1; ss = mov(ss, M_Base_Opnd(ecx_reg, 1), eax_opnd, size_8); // mov byte[ecx+1],al ss = ret(ss, Imm_Opnd(4)); // ret 4 signed offset = (signed)ss - (signed)zero_rec - 1; //zero_rec: *zero_rec = (char)offset; ss = mov(ss, M_Base_Opnd(ecx_reg, 2), Imm_Opnd(size_16, 0), size_16);// mov word[ecx+2],0 ss = ret(ss, Imm_Opnd(4)); // ret 4 offset = (signed)ss - (signed)fat - 1; //fat: *fat = (char)offset; #endif ss = push(ss, ecx_opnd); ss = call(ss, (char *)hythread_thin_monitor_exit); ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); // pop parameters return ss; }
char * m2n_gen_pop_m2n(char * buf, bool handles, unsigned num_callee_saves, I_32 bytes_to_m2n_bottom, unsigned num_preserve_ret) { assert (num_preserve_ret <= 2); assert(LcgEM64TContext::GR_SIZE == 8); if (num_preserve_ret > 0) { // Save return value // NOTE: don't break stack allignment by pushing only one register. buf = push(buf, rax_opnd, size_64); buf = push(buf, rdx_opnd, size_64); } if (handles) { // There are handles located on the stack buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)m2n_pop_local_handles), size_64); } else { buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)m2n_free_local_handles), size_64); } // NOTE: the following should be true before the call ($rsp % 8 == 0 && $rsp % 16 != 0)! // Call m2n_pop_local_handles or m2n_free_local_handles #ifdef _WIN64 buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(-SHADOW)); #endif buf = call(buf, rax_opnd, size_64); #ifdef _WIN64 buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(SHADOW)); #endif if (num_preserve_ret > 0) { // Restore return value buf = pop(buf, rdx_opnd, size_64); buf = pop(buf, rax_opnd, size_64); } // pop prev_m2nf buf = mov(buf, r10_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; // pop p_lm2nf buf = mov(buf, r11_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(r11_reg, 0), r10_opnd, size_64); // skip local_object_handles, method, current_frame_type, pop_regs bytes_to_m2n_bottom += 4 * LcgEM64TContext::GR_SIZE; // restore part of callee-saves registers for (int i = LcgEM64TContext::MAX_GR_LOCALS - 1; i >= (int)num_callee_saves; i--) { buf = mov(buf, LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_LOCALS_OFFSET + i), M_Base_Opnd(rsp_reg, bytes_to_m2n_bottom), size_64); bytes_to_m2n_bottom += LcgEM64TContext::GR_SIZE; } return buf; }//m2n_gen_pop_m2n
/* take string cmd_line, parse the line and call the alu function corresponding to alu-opcodes.h */ void alu_parse_line(char *cmd_line){ char opcode[100]; char operand1[100]; char operand2[100]; int nargs = 0; nargs = sscanf (cmd_line, "%s %s %s", opcode, operand1, operand2); switch(nargs){ case 3: ldhex2register(operand1, rega); ldhex2register(operand2, regb); if(!strcmp(opcode,"add")){ alu(ALU_OP_ADD, rega, regb, accumulator, flags); } if(!strcmp(opcode,"adc")){ alu(ALU_OP_ADD_WITH_CARRY, rega, regb, accumulator, flags); } if(!strcmp(opcode,"sub")) alu(ALU_OP_SUB, rega, regb, accumulator, flags); if(!strcmp(opcode,"and")) alu(ALU_OP_AND, rega, regb, accumulator, flags); if(!strcmp(opcode,"or")) alu(ALU_OP_OR, rega, regb, accumulator, flags); if(!strcmp(opcode,"xor")) alu(ALU_OP_XOR, rega, regb, accumulator, flags); printf("%s %s %s\n", opcode, operand1, operand2); break; case 2: if(!strcmp(opcode,"neg_a")){ ldhex2register(operand1, rega); alu(ALU_OP_NEG_A, rega, regb, accumulator, flags); } if(!strcmp(opcode,"neg_b")){ ldhex2register(operand1, regb); alu(ALU_OP_NEG_B, rega, regb, accumulator, flags); } if(!strcmp(opcode,"not_a")){ ldhex2register(operand1, rega); alu(ALU_OP_NOT_A, rega, regb, accumulator, flags); } if(!strcmp(opcode,"not_b")){ ldhex2register(operand1, regb); alu(ALU_OP_NOT_B, rega, regb, accumulator, flags); } printf("%s %s\n", opcode, operand1); break; case 1: if(!strcmp(opcode,"reset")){ alu_main_reset(rega, regb, accumulator, flags); printf("%s\n", opcode); break; } break; } }
/** * Provides fine-tuned implementation for IDIV/IREM operations on IA32-compatible platforms, * in replacement of common arithmetic helper (see arith_rt.h). */ bool CodeGen::gen_a_platf(JavaByteCodes op, jtype jt) { if (jt != i32) return false; if (op != OPCODE_IDIV && op != OPCODE_IREM) { return false; } // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // vpark(eax.reg()); vpark(edx.reg()); rlock(eax); rlock(edx); Val& v1 = vstack(1, vis_imm(1)); Val& v2 = vstack(0, true); alu(alu_cmp, v2.as_opnd(), Opnd(-1)); unsigned br_normal = br(ne, 0, 0); alu(alu_cmp, v1.as_opnd(), Opnd(INT_MIN)); unsigned br_exit = NOTHING; if (op == OPCODE_IREM) { do_mov(edx, Opnd(0)); // prepare exit value for the corner case br_exit = br(eq, 0, 0); } else { do_mov(eax, v1); br_exit = br(eq, 0, 0); } patch(br_normal, ip()); do_mov(eax, v1); // // The method is supposed to be platform-depended, and may not have // Encoder support - leaving as-is, without implementing general // support in Encoder // //CDQ EncoderBase::Operands args0(RegName_EDX, RegName_EAX); ip(EncoderBase::encode(ip(), Mnemonic_CDQ, args0)); //IDIV EncoderBase::Operands args(RegName_EDX, RegName_EAX, devirt(v2.reg(), i32)); ip(EncoderBase::encode(ip(), Mnemonic_IDIV, args)); patch(br_exit, ip()); vpop(); vpop(); vpush(op == OPCODE_IREM ? edx : eax); runlock(eax); runlock(edx); return true; }
// inputs should be preserved outside if required since we do a call // num_std_need_to_save registers will be preserved char * m2n_gen_push_m2n(char * buf, Method_Handle method, frame_type current_frame_type, bool handles, unsigned num_callee_saves, unsigned num_std_need_to_save, I_32 bytes_to_m2n_top) { // skip callee-saves registers bytes_to_m2n_top -= num_callee_saves * LcgEM64TContext::GR_SIZE; // TODO: check if it makes sense to save all callee-saves registers here //store rest of callee-saves registers for (unsigned i = num_callee_saves; i < LcgEM64TContext::MAX_GR_LOCALS; i++) { bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), LcgEM64TContext::get_reg_from_map(LcgEM64TContext::GR_LOCALS_OFFSET + i), size_64); } // init pop_regs to null bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), Imm_Opnd(size_32, 0), size_64); // store current_frame_type bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; assert(fit32(current_frame_type)); buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), Imm_Opnd(size_32, current_frame_type), size_64); // store a method associated with the current m2n frame bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; if (fit32((int64)method)) { buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), Imm_Opnd(size_32, (int64)method), size_64); } else { buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (int64)method), size_64); buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), rax_opnd); } // store local object handles bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), Imm_Opnd(size_64, (int64)0), size_64); // move pointer to the current VM_Thread structure to rax buf = m2n_gen_ts_to_register(buf, &rax_opnd, num_callee_saves, LcgEM64TContext::MAX_GR_LOCALS, num_std_need_to_save, 0); // shift to the last_m2n_frame field I_32 last_m2n_frame_offset = (I_32)(int64)&((VM_thread*)0)->last_m2n_frame; buf = alu(buf, add_opc, rax_opnd, Imm_Opnd(size_32, last_m2n_frame_offset), size_64); // store pointer to pointer to last m2n frame bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), rax_opnd, size_64); // save pointer to the previous m2n frame bytes_to_m2n_top -= LcgEM64TContext::GR_SIZE; buf = mov(buf, r9_opnd, M_Base_Opnd(rax_reg, 0)); buf = mov(buf, M_Base_Opnd(rsp_reg, bytes_to_m2n_top), r9_opnd, size_64); // update last m2n frame of the current thread buf = lea(buf, r9_opnd, M_Base_Opnd(rsp_reg, bytes_to_m2n_top)); buf = mov(buf, M_Base_Opnd(rax_reg, 0), r9_opnd, size_64); return buf; }
static void* getaddress__pop_java_to_native_frame() { static void *addr = 0; if (addr) { return addr; } const int stub_size = 32 + m2n_pop_m2n_size(false, 1, 0); char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_MAX/2, CAA_Allocate); #ifdef _DEBUG memset(stub, 0xcc /*int 3*/, stub_size); #endif char *ss = stub; ss = mov(ss, r12_opnd, rax_opnd); ss = m2n_gen_pop_m2n(ss, false, 1, 8, 0); ss = mov(ss, rax_opnd, r12_opnd); ss = mov(ss, r11_opnd, M_Base_Opnd(rsp_reg, 0)); ss = mov(ss, r12_opnd, M_Base_Opnd(rsp_reg, m2n_sizeof_m2n_frame - 8)); ss = mov(ss, M_Base_Opnd(rsp_reg, m2n_sizeof_m2n_frame - 8), r11_opnd); ss = alu(ss, add_opc, rsp_opnd, Imm_Opnd(m2n_sizeof_m2n_frame - 8)); ss = ret(ss); assert((ss - stub) <= stub_size); addr = stub; compile_add_dynamic_generated_code_chunk("pop_java_to_native_frame", false, stub, stub_size); // Put TI support here. DUMP_STUB(stub, "getaddress__pop_java_to_native_frame", ss - stub); return addr; } //getaddress__pop_java_to_native_frame
/** * Generates slow path of monitor exit. * This code could block on monitor and contains safepoint. * The appropriate m2n frame should be generated and * * @param[in] ss buffer to put the assembly code to * @param[in] input_param1 register should point to the jobject(handle) * If input_param1 == eax it reduces one register mov. * the code use and do not restore ecx, edx, eax registers * @return 0 if success in eax register */ char* gen_monitorexit_slow_path_helper(char *ss, const R_Opnd & input_param1) { if (&input_param1 != &eax_opnd) { ss = mov(ss, eax_opnd, input_param1); } ss = push(ss, eax_opnd); // push the address of the handle ss = call(ss, (char *)jthread_monitor_exit); ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); // pop parameters return ss; }
void Compiler::gen_if(JavaByteCodes opcod, unsigned target) { if (target <= m_pc) { // have back branch here gen_prof_be(); gen_gc_safe_point(); } jtype jt = i32; if (opcod == OPCODE_IFNULL) { opcod = OPCODE_IFEQ; jt = jobj; } else if (opcod == OPCODE_IFNONNULL) { opcod = OPCODE_IFNE; jt = jobj; } OpndKind kind = m_jframe->dip(0).kind(); bool forceReg = (kind == opnd_imm) || (jt == jobj && g_refs_squeeze); Opnd op1 = vstack(0, forceReg).as_opnd(); vpop(); rlock(op1); COND cond = to_cond(opcod); static const Opnd zero((int)0); if (jt == jobj && g_refs_squeeze) { AR ar = valloc(jobj); movp(ar, NULL_REF); alu(alu_cmp, Opnd(jobj, ar), op1); } else if (opcod == OPCODE_IFEQ || opcod == OPCODE_IFNE) { if (op1.is_reg()) { alu(alu_test, op1, op1); } else { alu(alu_cmp, op1, zero); } } else { alu(alu_cmp, op1, zero); } runlock(op1); gen_bb_leave(target); br(cond, target, m_bbinfo->start); }
void Compiler::gen_if_icmp(JavaByteCodes opcod, unsigned target) { if (target <= m_pc) { // have back branch here gen_prof_be(); gen_gc_safe_point(); } if (opcod == OPCODE_IF_ACMPEQ) { opcod = OPCODE_IF_ICMPEQ; } else if (opcod == OPCODE_IF_ACMPNE) { opcod = OPCODE_IF_ICMPNE; } Opnd op2 = vstack(0).as_opnd(); vpop(); rlock(op2); OpndKind kind = m_jframe->dip(0).kind(); // 'Bad' combinations are 'm,m' and 'imm,<any, but imm>' - have to force // an item into a register bool forceReg = (op2.is_mem() && kind == opnd_mem) || (op2.is_imm() && kind == opnd_imm); Opnd op1 = vstack(0, forceReg).as_opnd(); vpop(); rlock(op1); COND cond = to_cond(opcod); if ( (op1.is_mem() && op2.is_reg()) || op1.is_imm()) { // here we have 'mem, reg' or 'imm, mem-or-reg' - swap them so it // become 'reg, mem' (more efficient) or 'mem-or-reg, imm' (existent) // operations. change the branch condition appropriately. alu(alu_cmp, op2, op1); cond = flip(cond); } else { alu(alu_cmp, op1, op2); } runlock(op1); runlock(op2); gen_bb_leave(target); br(cond, target, m_bbinfo->start); }
void ARMCore::thumbDataLo(uint4 opcode, uint3 ird, uint3 irm) { auto &rd = r[ird], rm = r[irm]; r[15] += 2; if(opcode == 2) { SOut r = lsl(rd, rm); bitf(true, rd = r, r); } // lsls else if(opcode == 3) { SOut r = lsr(rd, rm); bitf(true, rd = r, r); } // lsrs else if(opcode == 4) { SOut r = asr(rd, rm); bitf(true, rd = r, r); } // asrs else if(opcode == 7) { SOut r = ror(rd, rm); bitf(true, rd = r, r); } // rors else if(opcode == 9) sumf(true, rd = -rm, 0, ~rm); // negs else if(opcode == 13) bitf(true, rd = rm * rd, {rm*rd, Cf}); // muls else alu(2*opcode+1, rd, rd, {rm,Cf}); // others are same as ARM }
static void* getaddress__setup_java_to_native_frame() { static void *addr = 0; if (addr) { return addr; } const int stub_size = 32 + m2n_push_m2n_size(1, 0); char *stub = (char *)malloc_fixed_code_for_jit(stub_size, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_MAX/2, CAA_Allocate); #ifdef _DEBUG memset(stub, 0xcc /*int 3*/, stub_size); #endif char *ss = stub; // Stack changes // prev new // // ... ... // -------- -------- ------------ // ret ret // -------- -------- // ret r12 // -------- -------- m2n frame // // ... // // -------- ------------ // ret // -------- ss = alu(ss, sub_opc, rsp_opnd, Imm_Opnd(m2n_sizeof_m2n_frame - 8)); ss = mov(ss, r11_opnd, M_Base_Opnd(rsp_reg, m2n_sizeof_m2n_frame - 8)); ss = mov(ss, M_Base_Opnd(rsp_reg, m2n_sizeof_m2n_frame - 8), r12_opnd); ss = mov(ss, M_Base_Opnd(rsp_reg, 0), r11_opnd); ss = mov(ss, r12_opnd, rdi_opnd); ss = m2n_gen_push_m2n(ss, NULL, FRAME_UNKNOWN, false, 1, 0, m2n_sizeof_m2n_frame); ss = mov(ss, rdi_opnd, r12_opnd); ss = ret(ss); assert((ss - stub) <= stub_size); addr = stub; compile_add_dynamic_generated_code_chunk("setup_java_to_native_frame", false, stub, stub_size); // Put TI support here. DUMP_STUB(stub, "getaddress__setup_java_to_native_frame", ss - stub); return addr; } //getaddress__setup_java_to_native_frame
void CodeGen::gen_cnv(jtype from, jtype to) { if (from<i32 && to==i32) { // no op return; } char *helper = (char *) cnv_matrix_impls[from][to]; const CallSig cs(CCONV_STDCALL, to, from); unsigned stackFix = gen_stack_to_args(true, cs, 0); gen_call_novm(cs, helper, 1); if (stackFix != 0) { alu(alu_sub, sp, stackFix); } runlock(cs); gen_save_ret(cs); }
int interp_ex() { ex_mem.mem_read = id_ex.mem_read; ex_mem.mem_write = id_ex.mem_write; ex_mem.reg_write = id_ex.reg_write; ex_mem.branch = id_ex.branch; ex_mem.beq = id_ex.beq; ex_mem.rt = id_ex.rt; ex_mem.rt_value = id_ex.rt_value; ex_mem.mem_to_reg = id_ex.mem_to_reg; ex_mem.reg_dst = id_ex.reg_dst; ex_mem.branch_target = id_ex.next_pc + (id_ex.sign_ext_imm << 2); int retAlu = alu(); if (retAlu != SAW_SYSCALL && retAlu != 0) { printf("ERROR: alu() failed\n"); } return retAlu; }
int sc_main(int argc, char* argv[]) { sc_trace_file *ar = sc_create_vcd_trace_file("Wave"); sc_trace(ar, ain, "ain"); sc_trace(ar, bin, "bin"); sc_trace(ar, sum, "sum"); sc_trace(ar, operation,"operation"); sc_trace(ar, owf , "owf-flag"); sc_trace(ar, zero , "zero-flag"); sc_trace(ar, lessFlag, "less-than-flag"); ain.write("0b0000000000001000"); bin.write("0b0000000000000111"); alu alu("alu"); alu.ain(ain); alu.bin(bin); alu.sum(sum); alu.owf(owf); alu.zero(zero); alu.less(lessFlag); alu.operation(operation); /*Write dummy value*/ operation.write(10); sc_start(100,SC_NS); /*Start ALU 6 times*/ for(int i =0;i<7;i++){ operation.write(i); sc_start(100,SC_NS); print(); //print the result } sc_close_vcd_trace_file(ar); }
bool CodeGen::gen_a_generic(JavaByteCodes op, jtype jt) { if (op == OPCODE_INEG) { return false; // later } if (jt == i32) { bool v2_imm = vis_imm(0); if (v2_imm && (op == OPCODE_ISHL || op == OPCODE_ISHL || op == OPCODE_IUSHR)) { // accept it } /*else if (v2_imm && (op == OPCODE_IMUL || op == OPCODE_IDIV)) { // accept it } else if (op == OPCODE_IMUL) { // accept it }*/ else if (op == OPCODE_IADD || op == OPCODE_ISUB) { // accept it } else if (op == OPCODE_IOR || op == OPCODE_IAND || op == OPCODE_IXOR) { // accept it } else if (vis_imm(0) && m_jframe->size()>1 && vis_imm(1)) { // accept it } else { return false; } } else if (is_f(jt)) { if (op != OPCODE_IADD && op != OPCODE_ISUB && op != OPCODE_IMUL && op != OPCODE_IDIV) { return false; } } else { return false; } bool is_dbl = jt == dbl64; unsigned v1_depth = is_dbl?2:1; if (vis_imm(v1_depth) && vis_imm(0)) { const Val& v1 = m_jframe->dip(v1_depth); const Val& v2 = m_jframe->dip(0); Val res; if (jt==dbl64) { double d = rt_h_dbl_a(v1.dval(), v2.dval(), op); res = Val(d); } else if (jt==flt32) { float f = rt_h_flt_a(v1.fval(), v2.fval(), op); res = Val(f); } else { assert(jt==i32); int i = rt_h_i32_a(v1.ival(), v2.ival(), op); res = Val(i); } vpop(); vpop(); vpush(res); return true; } // if v1.is_imm() && v2.is_imm() const Val& v1 = vstack(v1_depth, true); Opnd res = v1.as_opnd(); if (rrefs(v1.reg()) > 1) { rlock(v1); AR ar = valloc(jt); runlock(v1); Opnd reg(jt, ar); mov(reg, v1.as_opnd()); res = reg; } rlock(res); rlock(v1); const Val& v2 = m_jframe->dip(0); /* if (false )v2. #ifdef _IA32_ // on IA32 can use address in a displacement alu(to_alu(op), v1, ar_x, (int)v2.addr()); #else AR addr = valloc(jobj); rlock(addr); movp(addr, v2.addr()); alu_mem(jt, to_alu(op), r1, addr); runlock(addr); #endif } else */ if(v2.is_mem()) { // Everyone can do 'reg, mem' operation alu(to_alu(op), res, v2.as_opnd()); } else if(v2.is_imm() && jt==i32) { // 'reg, imm' is only for i32 operations alu(to_alu(op), res, v2.ival()); } else { Opnd v2 = vstack(0, true).as_opnd(); alu(to_alu(op), res, v2); } vpop(); vpop(); runlock(v1); runlock(res); vpush(res); return true; }
static transfer_control_stub_type gen_transfer_control_stub() { static transfer_control_stub_type addr = NULL; if (addr) { return addr; } const int STUB_SIZE = 255; char * stub = (char *)malloc_fixed_code_for_jit(STUB_SIZE, DEFAULT_CODE_ALIGNMENT, CODE_BLOCK_HEAT_COLD, CAA_Allocate); char * ss = stub; #ifndef NDEBUG memset(stub, 0xcc /*int 3*/, STUB_SIZE); #endif // // ************* LOW LEVEL DEPENDENCY! *************** // This code sequence must be atomic. The "atomicity" effect is achieved by // changing the rsp at the very end of the sequence. // rdx holds the pointer to the stack iterator #if defined (PLATFORM_POSIX) // RDI holds 1st parameter on Linux ss = mov(ss, rdx_opnd, rdi_opnd); #else // RCX holds 1st parameter on Windows ss = mov(ss, rdx_opnd, rcx_opnd); #endif // Restore general registers ss = get_reg(ss, rbp_opnd, rdx_reg, CONTEXT_OFFSET(p_rbp), false); ss = get_reg(ss, rbx_opnd, rdx_reg, CONTEXT_OFFSET(p_rbx), true); ss = get_reg(ss, r12_opnd, rdx_reg, CONTEXT_OFFSET(p_r12), true); ss = get_reg(ss, r13_opnd, rdx_reg, CONTEXT_OFFSET(p_r13), true); ss = get_reg(ss, r14_opnd, rdx_reg, CONTEXT_OFFSET(p_r14), true); ss = get_reg(ss, r15_opnd, rdx_reg, CONTEXT_OFFSET(p_r15), true); ss = get_reg(ss, rsi_opnd, rdx_reg, CONTEXT_OFFSET(p_rsi), true); ss = get_reg(ss, rdi_opnd, rdx_reg, CONTEXT_OFFSET(p_rdi), true); ss = get_reg(ss, r8_opnd, rdx_reg, CONTEXT_OFFSET(p_r8), true); ss = get_reg(ss, r9_opnd, rdx_reg, CONTEXT_OFFSET(p_r9), true); ss = get_reg(ss, r10_opnd, rdx_reg, CONTEXT_OFFSET(p_r10), true); ss = get_reg(ss, r11_opnd, rdx_reg, CONTEXT_OFFSET(p_r11), true); // Get the new RSP M_Base_Opnd saved_rsp(rdx_reg, CONTEXT_OFFSET(rsp)); ss = mov(ss, rax_opnd, saved_rsp); // Store it over return address for future use ss = mov(ss, M_Base_Opnd(rsp_reg, 0), rax_opnd); // Get the new RIP ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rip), false); // Store RIP to [<new RSP> - 136] to preserve 128 bytes under RSP // which are 'reserved' on Linux ss = mov(ss, M_Base_Opnd(rax_reg, -136), rcx_opnd); ss = get_reg(ss, rax_opnd, rdx_reg, CONTEXT_OFFSET(p_rax), true); // Restore processor flags ss = movzx(ss, rcx_opnd, M_Base_Opnd(rdx_reg, CONTEXT_OFFSET(eflags)), size_16); ss = test(ss, rcx_opnd, rcx_opnd); ss = branch8(ss, Condition_Z, Imm_Opnd(size_8, 0)); char* patch_offset = ((char*)ss) - 1; // Store location for jump patch *ss++ = (char)0x9C; // PUSHFQ M_Base_Opnd sflags(rsp_reg, 0); ss = alu(ss, and_opc, sflags, Imm_Opnd(size_32,FLG_CLEAR_MASK), size_32); ss = alu(ss, and_opc, rcx_opnd, Imm_Opnd(size_32,FLG_SET_MASK), size_32); ss = alu(ss, or_opc, sflags, rcx_opnd, size_32); *ss++ = (char)0x9D; // POPFQ // Patch conditional jump POINTER_SIZE_SINT offset = (POINTER_SIZE_SINT)ss - (POINTER_SIZE_SINT)patch_offset - 1; *patch_offset = (char)offset; ss = get_reg(ss, rcx_opnd, rdx_reg, CONTEXT_OFFSET(p_rcx), true, true); ss = get_reg(ss, rdx_opnd, rdx_reg, CONTEXT_OFFSET(p_rdx), true, true); // Setup stack pointer to previously saved value ss = mov(ss, rsp_opnd, M_Base_Opnd(rsp_reg, 0)); // Jump to address stored to [<new RSP> - 136] ss = jump(ss, M_Base_Opnd(rsp_reg, -136)); addr = (transfer_control_stub_type)stub; assert(ss-stub <= STUB_SIZE); /* The following code will be generated: mov rdx,rcx mov rbp,qword ptr [rdx+10h] mov rbp,qword ptr [rbp] mov rbx,qword ptr [rdx+20h] test rbx,rbx je __label1__ mov rbx,qword ptr [rbx] __label1__ ; .... The same for r12,r13,r14,r15,rsi,rdi,r8,r9,r10 mov r11,qword ptr [rdx+88h] test r11,r11 je __label11__ mov r11,qword ptr [r11] __label11__ mov rax,qword ptr [rdx+8] mov qword ptr [rsp],rax mov rcx,qword ptr [rdx+18h] mov rcx,qword ptr [rcx] mov qword ptr [rax-88h],rcx mov rax,qword ptr [rdx+48h] test rax,rax je __label12__ mov rax,qword ptr [rax] __label12__ movzx rcx,word ptr [rdx+90h] test rcx,rcx je __label13__ pushfq and dword ptr [rsp], 0x003F7202 and ecx, 0x00000CD5 or dword ptr [esp], ecx popfq __label13__ mov rcx,qword ptr [rdx+50h] pushfq test rcx,rcx je __label14__ mov rcx,qword ptr [rcx] __label14__ popfq mov rdx,qword ptr [rdx+58h] pushfq test rdx,rdx je __label15__ mov rdx,qword ptr [rdx] __label15__ popfq mov rsp,qword ptr [rsp] jmp qword ptr [rsp-88h] */ DUMP_STUB(stub, "getaddress__transfer_control", ss-stub); return addr; }
unsigned short start() { return alu(3); }
void execute(char instruction, char data) { char dataBus = 0; switch ((unsigned char) instruction) { case LDAD: ACC = dataMemory->access(0, data); break; case LDAI: ACC = data; break; case STA : dataMemory->access(1, data, ACC); break; case ADDD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 0, ACC, dataBus, 0, 2, 0); break; case ADDI: ACC = alu(SR, 0, ACC, data, 0, 2, 0); break; case ADCD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 0, ACC, dataBus, 0, 0, 0); break; case ADCI: ACC = alu(SR, 0, ACC, data, 0, 0, 0); break; case SUBD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 0, ACC, dataBus, 1, 2, 0); break; case SUBI: ACC = alu(SR, 0, ACC, data, 1, 2, 0); break; case SBCD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 0, ACC, dataBus, 1, 0, 0); break; case SBCI: ACC = alu(SR, 0, ACC, data, 1, 0, 0); break; case INC : ACC = alu(SR, 0, ACC, '1', 0, 2, 0); break; case DEC : ACC = alu(SR, 0, ACC, '1', 1, 2, 0); break; case ANDD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 1, ACC, dataBus, 0, 0, 0); break; case ANDI: ACC = alu(SR, 1, ACC, data, 0, 0, 0); break; case ORD : dataBus = dataMemory->access(0, data); ACC = alu(SR, 1, ACC, dataBus, 0, 0, 1); break; case ORI : ACC = alu(SR, 1, ACC, data, 0, 0, 1); break; case INV : ACC = alu(SR, 1, ACC, data, 0, 0, 2); break; case XORD: dataBus = dataMemory->access(0, data); ACC = alu(SR, 1, ACC, dataBus, 0, 0, 3); break; case XORI: ACC = alu(SR, 1, ACC, data, 0, 0, 3); break; case CLRA: ACC = '0'; break; case CLRC: SR.setc(0); break; case CSET: SR.setc(1); break; case CMPD: dataBus = dataMemory->access(0, data); alu(SR, 0, ACC, dataBus, 1, 2, 0); break; case CMPI: alu(SR, 0, ACC, data, 1, 2, 0); break; default: char destinationQuestionMark; //JUMP(instruction, &destinationQuestionMark, SR, &programCounter); break; } }
/** * Generates fast path of monitor enter * the code should not contains safepoint. * * @param[in] ss buffer to put the assembly code to * @param[in] input_param1 register which should point to the object lockword. * If input_param1 == ecx it reduces one register mov. * the code use and do not restore ecx, edx, eax registers * * @return 0 if success in eax register */ char* gen_monitorenter_fast_path_helper(char *ss, const R_Opnd & input_param1) { if (&input_param1 != &ecx_opnd) { ss = mov(ss, ecx_opnd, input_param1); } #ifdef ASM_MONITOR_HELPER //get self_id ss = gen_hythread_self_helper(ss); ss = mov(ss, edx_opnd, M_Base_Opnd(eax_reg, hythread_get_thread_id_offset())); // mov edx,dword [eax+off] ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 2), size_16); // mov ax,word[ecx+2] ss = alu(ss, cmp_opc, edx_opnd, eax_opnd, size_16); // cmp dx,ax ss = branch8(ss, Condition_NZ, Imm_Opnd(size_8, 0)); // jnz check_zero char *check_zero = ((char *)ss) - 1; //; ax==dx it's safe to do inc ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8); // mov al, byte[ecx+1] //rec_inc: ss = alu(ss, add_opc, eax_opnd, Imm_Opnd(size_8, 0x8), size_8); // add al,0x8 ss = branch8(ss, Condition_C, Imm_Opnd(size_8, 0)); // jc failed char *failed1 = ((char *)ss) - 1; ss = mov(ss, M_Base_Opnd(ecx_reg, 1), eax_opnd, size_8); // mov byte[ecx+1],al ss = ret(ss, Imm_Opnd(4)); // ret 4 signed offset = (signed)ss - (signed)check_zero - 1; *check_zero = (char)offset; //check_zero: ss = test(ss, eax_opnd, eax_opnd, size_16); // test ax,ax ss = branch8(ss, Condition_NZ, Imm_Opnd(size_8, 0)); // jnz failed char *failed2 = ((char *)ss) - 1; ss = prefix(ss, lock_prefix); //; here ax==0. ss = cmpxchg(ss, M_Base_Opnd(ecx_reg, 2), edx_opnd, size_16); // lock cmpxchg16 [ecx+2],dx ss = branch8(ss, Condition_NZ, Imm_Opnd(size_8, 0)); // jnz failed char *failed3 = ((char *)ss) - 1; #ifdef LOCK_RESERVATION ss = mov(ss, eax_opnd, M_Base_Opnd(ecx_reg, 1), size_8); // mov al, byte[ecx+1] ss = test(ss, eax_opnd, Imm_Opnd(size_8, 0x4), size_8); // test al,0x4 ss = branch8(ss, Condition_NZ, Imm_Opnd(size_8, 0)); // jnz finish char *finish = ((char *)ss) - 1; ss = alu(ss, add_opc, eax_opnd, Imm_Opnd(size_8, 0x8), size_8); // add al,0x8 ss = mov(ss, M_Base_Opnd(ecx_reg, 1), eax_opnd, size_8); // mov byte[ecx+1],al offset = (signed)ss - (signed)finish - 1; *finish = (char)offset; //finish: #endif ss = ret(ss, Imm_Opnd(4)); // ret 4 offset = (signed)ss - (signed)failed1 - 1; *failed1 = (char)offset; //failed: offset = (signed)ss - (signed)failed2 - 1; *failed2 = (char)offset; offset = (signed)ss - (signed)failed3 - 1; *failed3 = (char)offset; #endif //ASM_MONITOR_HELPER // the second attempt to lock monitor ss = push(ss, ecx_opnd); ss = call(ss, (char *)hythread_thin_monitor_try_enter); ss = alu(ss, add_opc, esp_opnd, Imm_Opnd(4)); // pop parameters return ss; }
void Compiler::gen_switch(const JInst & jinst) { assert(jinst.opcode == OPCODE_LOOKUPSWITCH || jinst.opcode == OPCODE_TABLESWITCH); Opnd val = vstack(0, true).as_opnd(); vpop(); rlock(val); gen_bb_leave(NOTHING); if (jinst.opcode == OPCODE_LOOKUPSWITCH) { unsigned n = jinst.get_num_targets(); for (unsigned i = 0; i < n; i++) { Opnd key(jinst.key(i)); unsigned pc = jinst.get_target(i); alu(alu_cmp, val, key); br(eq, pc, m_bbinfo->start); } runlock(val); br(cond_none, jinst.get_def_target(), m_bbinfo->start); return; } // // TABLESWITCH // alu(alu_cmp, val, jinst.high()); br(gt, jinst.get_def_target(), m_bbinfo->start); alu(alu_cmp, val, jinst.low()); br(lt, jinst.get_def_target(), m_bbinfo->start); AR gr_tabl = valloc(jobj); movp(gr_tabl, DATA_SWITCH_TABLE | m_curr_inst->pc, m_bbinfo->start); #ifdef _EM64T_ // On EM64T, we operate with I_32 value in a register, but the // register will be used as 64 bit in address form - have to extend sx(Opnd(i64, val.reg()), Opnd(i32, val.reg())); #endif // Here, we need to extract 'index-=low()' - can pack this into // complex address form: // [table + index*sizeof(void*) - low()*sizeof(void*)], // but only if low()*sizeof(void*) does fit into displacement ... int tmp = -jinst.low(); const int LO_BOUND = INT_MIN/(int)sizeof(void*); const int UP_BOUND = INT_MAX/(int)sizeof(void*); if (LO_BOUND<=tmp && tmp<=UP_BOUND) { ld(jobj, gr_tabl, gr_tabl, -jinst.low()*sizeof(void*), val.reg(), sizeof(void*)); } else { // ... otherwise subtract explicitly, but only if the register // is not used anywhere else if (rrefs(val.reg()) !=0) { Opnd vtmp(i32, valloc(i32)); mov(vtmp, val); // make a copy of val runlock(val); val = vtmp; rlock(val); } alu(alu_sub, val, jinst.low()); ld(jobj, gr_tabl, gr_tabl, 0, val.reg(), sizeof(void*)); } runlock(val); br(gr_tabl); }
int sc_main(int argc, char* argv[]) { sc_report_handler:: set_actions("/IEEE_Std_1666/deprecated", SC_DO_NOTHING); char stbuf[256]; // SIGNALS // Data signals sc_signal< sc_bv<DWORD> > bus_mux1; sc_signal< sc_bv<DWORD> > bus_mux2; sc_signal< sc_bv<DWORD> > bus_mux3; sc_signal< sc_bv<AWORDREG> > bus_mux4; sc_signal< sc_bv<6> > bus_decoder_instr_31_26; sc_signal< sc_bv<AWORDREG> > bus_decoder_instr_25_21; sc_signal< sc_bv<AWORDREG> > bus_decoder_instr_20_16; sc_signal< sc_bv<AWORDREG> > bus_decoder_instr_15_11; sc_signal< sc_bv<SIGNEXTENDBIT> > bus_decoder_instr_15_0; sc_signal< sc_bv<6> > bus_decoder_instr_5_0; sc_signal< sc_bv<DWORD> > bus_pc; sc_signal< sc_bv<DWORD> > bus_add1; sc_signal< sc_bv<DWORD> > bus_add2; sc_signal< sc_bv<DWORD> > bus_shiftleft; sc_signal< sc_bv<DWORD> > bus_signextend; sc_signal< sc_bv<DWORD> > bus_imem_1; sc_signal< sc_bv<DWORD> > bus_dmem_1; sc_signal< sc_bv<DWORD> > bus_alu_result; sc_signal< sc_bv<1> > bus_alu_zero; sc_signal< sc_bv<DWORD> > bus_registers_1; sc_signal< sc_bv<DWORD> > bus_registers_2; // Control signals sc_signal< sc_bv<1> > bus_ctrl_regdst; sc_signal< sc_bv<1> > bus_ctrl_branch; sc_signal< sc_bv<1> > bus_ctrl_memread; sc_signal< sc_bv<1> > bus_ctrl_memtoreg; sc_signal< sc_bv<2> > bus_ctrl_aluop; sc_signal< sc_bv<1> > bus_ctrl_memwrite; sc_signal< sc_bv<1> > bus_ctrl_alusrc; sc_signal< sc_bv<1> > bus_ctrl_regwrite; sc_signal< sc_bv<DWORD> > bus_ctrl_c4; sc_signal< sc_bv<3> > bus_aluctrl; sc_signal< sc_bv<1> > bus_and1; // MODULES REGISTER pc("pc"); ADD add1("add1"); ADD add2("add2"); AND and1("and1"); ROM imem("instruction_memory"); // Instruction memory RAM dmem("data_memory"); // Data memory REGFILE registers("registers"); // Registerfile ALU alu("alu"); ALUCTRL aluctrl("aluctrl"); SIGNEXTEND signextend("signextend"); SHIFTLEFT shiftleft("shiftleft"); CTRL ctrl("ctrl"); DECODER decoder("decoder"); MUX mux1("mux1"); MUX mux2("mux2"); MUX mux3("mux3"); MUX2_AWORDREG mux4("mux4"); sc_clock clk("clock", 20); // Clock // CONNECTIONS // Program counter pc.in(bus_mux1); pc.out(bus_pc); pc.w(clk); pc.clk(clk); // Add 1 (PC + 4) add1.a(bus_pc); add1.b(bus_ctrl_c4); add1.r(bus_add1); // Add 2 (add1 + shiftleft) add2.a(bus_add1); add2.b(bus_shiftleft); add2.r(bus_add2); // Mux 1 (add1 or add2) mux1.in0(bus_add1); mux1.in1(bus_add2); mux1.sel(bus_and1); mux1.out(bus_mux1); // Shift left 2 shiftleft.in(bus_signextend); shiftleft.out(bus_shiftleft); // Sign extend signextend.in(bus_decoder_instr_15_0); signextend.out(bus_signextend); // Decoder (Select correct part of instruction for registerfile) decoder.instr(bus_imem_1); decoder.instr_31_26(bus_decoder_instr_31_26); decoder.instr_25_21(bus_decoder_instr_25_21); decoder.instr_20_16(bus_decoder_instr_20_16); decoder.instr_15_11(bus_decoder_instr_15_11); decoder.instr_15_0(bus_decoder_instr_15_0); decoder.instr_5_0(bus_decoder_instr_5_0); // Mux 4 (Select address for write to registerfile) mux4.in0(bus_decoder_instr_20_16); mux4.in1(bus_decoder_instr_15_11); mux4.sel(bus_ctrl_regdst); mux4.out(bus_mux4); // ALU alu.a(bus_registers_1); alu.b(bus_mux2); alu.r(bus_alu_result); alu.z(bus_alu_zero); alu.ctrl(bus_aluctrl); // Mux 2 (Registerfile or signextend) mux2.in0(bus_registers_2); mux2.in1(bus_signextend); mux2.sel(bus_ctrl_alusrc); mux2.out(bus_mux2); // ALU ctrl aluctrl.ALUop(bus_ctrl_aluop); aluctrl.functionCode(bus_decoder_instr_5_0); aluctrl.ALUctrl(bus_aluctrl); // Mux 3 (ALU result or memory result to register) mux3.in0(bus_alu_result); mux3.in1(bus_dmem_1); mux3.sel(bus_ctrl_memtoreg); mux3.out(bus_mux3); // AND and1.a(bus_alu_zero); and1.b(bus_ctrl_branch); and1.r(bus_and1); // Registerfile registers.r_addr_reg1(bus_decoder_instr_25_21); registers.r_addr_reg2(bus_decoder_instr_20_16); registers.w_addr_reg(bus_mux4); registers.r_data_reg1(bus_registers_1); registers.r_data_reg2(bus_registers_2); registers.w_data_reg(bus_mux3); registers.w(bus_ctrl_regwrite); registers.clk(clk); // Data memory dmem.a_read(bus_alu_result); dmem.d_read(bus_dmem_1); dmem.r(bus_ctrl_memread); dmem.a_write(bus_alu_result); dmem.d_write(bus_registers_2); dmem.w(bus_ctrl_memwrite); dmem.clk(clk); // Instruction Memory imem.a_read(bus_pc); imem.d_read(bus_imem_1); imem.clk(clk); // Controller ctrl.Opcode(bus_decoder_instr_31_26); ctrl.RegDst(bus_ctrl_regdst); ctrl.Branch(bus_ctrl_branch); ctrl.MemRead(bus_ctrl_memread); ctrl.MemtoReg(bus_ctrl_memtoreg); ctrl.ALUop(bus_ctrl_aluop); ctrl.MemWrite(bus_ctrl_memwrite); ctrl.ALUSrc(bus_ctrl_alusrc); ctrl.RegWrite(bus_ctrl_regwrite); ctrl.c4(bus_ctrl_c4); // INITIALIZATION imem.rom_init("mips.rom"); dmem.ram_init("mips.ram"); // TRACING sc_trace_file* tf; tf = sc_create_vcd_trace_file("mips"); // Signals sc_trace(tf, clk, "clock"); sc_trace(tf, bus_mux1, "bus_mux1"); sc_trace(tf, bus_mux2, "bus_mux2"); sc_trace(tf, bus_mux3, "bus_mux3"); sc_trace(tf, bus_mux4, "bus_mux4"); sc_trace(tf, bus_pc, "bus_pc"); sc_trace(tf, bus_add1, "bus_add1"); sc_trace(tf, bus_add2, "bus_add2"); sc_trace(tf, bus_shiftleft, "bus_shiftleft"); sc_trace(tf, bus_signextend, "bus_signextend"); sc_trace(tf, bus_imem_1, "bus_imem_1"); sc_trace(tf, bus_dmem_1, "bus_dmem_1"); sc_trace(tf, bus_alu_result, "bus_alu_result"); sc_trace(tf, bus_alu_zero, "bus_alu_zero"); sc_trace(tf, bus_registers_1, "bus_registers_1"); sc_trace(tf, bus_registers_2, "bus_registers_2"); sc_trace(tf, bus_ctrl_regdst, "bus_ctrl_regdst"); sc_trace(tf, bus_ctrl_branch, "bus_ctrl_branch"); sc_trace(tf, bus_ctrl_memread, "bus_ctrl_memread"); sc_trace(tf, bus_ctrl_memtoreg, "bus_ctrl_memtoreg"); sc_trace(tf, bus_ctrl_aluop, "bus_ctrl_aluop"); sc_trace(tf, bus_ctrl_memwrite, "bus_ctrl_memwrite"); sc_trace(tf, bus_ctrl_alusrc, "bus_ctrl_alusrc"); sc_trace(tf, bus_ctrl_regwrite, "bus_ctrl_regwrite"); sc_trace(tf, bus_ctrl_c4, "bus_ctrl_c4"); sc_trace(tf, bus_aluctrl, "bus_aluctrl"); sc_trace(tf, bus_and1, "bus_and1"); sc_trace(tf, bus_decoder_instr_31_26, "bus_decoder_instr_31_26"); sc_trace(tf, bus_decoder_instr_25_21, "bus_decoder_instr_25_21"); sc_trace(tf, bus_decoder_instr_20_16, "bus_decoder_instr_20_16"); sc_trace(tf, bus_decoder_instr_15_11, "bus_decoder_instr_15_11"); sc_trace(tf, bus_decoder_instr_15_0, "bus_decoder_instr_15_0"); sc_trace(tf, bus_decoder_instr_5_0, "bus_decoder_instr_5_0"); for (int i = 0; i < REGSIZE; i++) { sprintf(stbuf, "registers.reg(%d)", i); sc_trace(tf, registers.rfile[i], stbuf); } for (int i = 0; i < RAMSIZE; i++) { sprintf(stbuf, "memory.dmem(%d)", i); sc_trace(tf, dmem.ramfile[i], stbuf); } for (int i = 0; i < ROMSIZE; i++) { sprintf(stbuf, "memory.imem(%d)", i); sc_trace(tf, imem.romfile[i], stbuf); } // SIMULATION int sim_time = 500; if (argc == 2) sim_time = atoi(argv[1]); sc_start(sim_time, SC_NS); sc_close_vcd_trace_file(tf); dmem.ram_dump("mips_ram.dump"); return 0; }
void execute(uint64_t ir){ int op = decodeOp(ir); alu(op,getReg(AC),getReg(MBR),getReg(MQ)); }
// rsp should point to the bottom of the activation frame since push may occur // inputs should be preserved outside if required since we do a call // num_std_need_to_save registers will be preserved char * m2n_gen_ts_to_register(char * buf, const R_Opnd * reg, unsigned num_callee_saves_used, unsigned num_callee_saves_max, unsigned num_std_need_to_save, unsigned num_ret_need_to_save) { // we can't preserve rax and return value on it at the same time assert (num_ret_need_to_save == 0 || reg != &rax_opnd); //#ifdef PLATFORM_POSIX // preserve std places unsigned i; unsigned num_std_saved = 0; // use calle-saves registers first while (num_std_saved < num_std_need_to_save && (i = num_callee_saves_used + num_std_saved) < num_callee_saves_max) { buf = mov(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i), LcgEM64TContext::get_reg_from_map( LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); ++num_std_saved; } // if we still have not preserved std places save them on the stack while (num_std_saved < num_std_need_to_save) { buf = push(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); ++num_std_saved; } assert(num_std_saved == num_std_need_to_save); // preserve returns unsigned num_ret_saved = 0; while (num_ret_saved < num_ret_need_to_save && (i = num_callee_saves_used + num_std_saved + num_ret_saved) < num_callee_saves_max) { buf = mov(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i), LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), size_64); ++num_ret_saved; } // if we still have not preserved returns save them on the stack while (num_ret_saved < num_ret_need_to_save) { buf = push(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_RETURNS_OFFSET + num_std_saved), size_64); ++num_ret_saved; } assert(num_ret_saved == num_ret_need_to_save); // TODO: FIXME: only absolute addressing mode is supported now buf = mov(buf, rax_opnd, Imm_Opnd(size_64, (uint64)get_thread_ptr), size_64); #ifdef _WIN64 buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(-SHADOW)); #endif buf = call(buf, rax_opnd, size_64); #ifdef _WIN64 buf = alu(buf, add_opc, rsp_opnd, Imm_Opnd(SHADOW)); #endif if (reg != &rax_opnd) { buf = mov(buf, *reg, rax_opnd, size_64); } // restore returns from the stack i = num_callee_saves_used + num_std_saved; while (num_ret_saved > 0 && i + num_ret_saved > num_callee_saves_max) { --num_ret_saved; buf = pop(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), size_64); } // restore std places from the stack while (num_std_saved > 0 && num_callee_saves_used + num_std_saved > num_callee_saves_max) { --num_std_saved; buf = pop(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), size_64); } // restore returns from callee-saves registers i = num_callee_saves_used + num_std_saved; while (num_ret_saved > 0) { --num_ret_saved; buf = mov(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_RETURNS_OFFSET + num_ret_saved), LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + i + num_ret_saved), size_64); } // restore std places from callee-saves registers while (num_std_saved > 0) { --num_std_saved; buf = mov(buf, LcgEM64TContext::get_reg_from_map( LcgEM64TContext::STD_PLACES_OFFSET + num_std_saved), LcgEM64TContext::get_reg_from_map( LcgEM64TContext::GR_LOCALS_OFFSET + num_callee_saves_used + num_std_saved), size_64); } //#else //!PLATFORM_POSIX // buf = prefix(buf, prefix_fs); // buf = mov(buf, *reg, M_Opnd(0x14), size_64); //#endif //!PLATFORM_POSIX return buf; }
static char* gen_invoke_common_managed_func(char* stub) { // Defines stack alignment on managed function enter. const I_32 STACK_ALIGNMENT = MANAGED_STACK_ALIGNMENT; const I_32 STACK_ALIGNMENT_MASK = ~(STACK_ALIGNMENT - 1); const char * LOOP_BEGIN = "loop_begin"; const char * LOOP_END = "loop_end"; // [ebp + 8] - args // [ebp + 12] - size // [ebp + 16] - func const I_32 STACK_ARGS_OFFSET = 8; const I_32 STACK_NARGS_OFFSET = 12; const I_32 STACK_FUNC_OFFSET = 16; const I_32 STACK_CALLEE_SAVED_OFFSET = -12; tl::MemoryPool pool; LilCguLabelAddresses labels(&pool, stub); // Initialize ebp-based stack frame. stub = push(stub, ebp_opnd); stub = mov(stub, ebp_opnd, esp_opnd); // Preserve callee-saved registers. stub = push(stub, ebx_opnd); stub = push(stub, esi_opnd); stub = push(stub, edi_opnd); // Load an array of arguments ('args') and its size from the stack. stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_ARGS_OFFSET)); stub = mov(stub, ecx_opnd, M_Base_Opnd(ebp_reg, STACK_NARGS_OFFSET)); // Align memory stack. stub = lea(stub, ebx_opnd, M_Index_Opnd(n_reg, ecx_reg, 4, 4)); stub = mov(stub, esi_opnd, ebx_opnd); stub = neg(stub, esi_opnd); stub = alu(stub, add_opc, esi_opnd, esp_opnd); stub = alu(stub, and_opc, esi_opnd, Imm_Opnd(size_32, STACK_ALIGNMENT_MASK)); stub = alu(stub, add_opc, ebx_opnd, esi_opnd); stub = mov(stub, esp_opnd, ebx_opnd); // Load a pointer to the last argument of 'args' array. stub = lea(stub, eax_opnd, M_Index_Opnd(eax_reg, ecx_reg, -4, 4)); stub = alu(stub, sub_opc, eax_opnd, esp_opnd); stub = alu(stub, or_opc, ecx_opnd, ecx_opnd); stub = branch8(stub, Condition_Z, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(LOOP_END, stub - 1, LPT_Rel8); // LOOP_BEGIN: // Push inputs on the stack. labels.define_label(LOOP_BEGIN, stub, false); stub = push(stub, M_Index_Opnd(esp_reg, eax_reg, 0, 1)); stub = loop(stub, Imm_Opnd(size_8, 0)); labels.add_patch_to_label(LOOP_BEGIN, stub - 1, LPT_Rel8); // LOOP_END: labels.define_label(LOOP_END, stub, false); // Call target function. stub = mov(stub, eax_opnd, M_Base_Opnd(ebp_reg, STACK_FUNC_OFFSET)); stub = call(stub, eax_opnd); // Restore callee-saved registers from the stack. stub = lea(stub, esp_opnd, M_Base_Opnd(ebp_reg, STACK_CALLEE_SAVED_OFFSET)); stub = pop(stub, edi_opnd); stub = pop(stub, esi_opnd); stub = pop(stub, ebx_opnd); // Leave current frame. stub = pop(stub, ebp_opnd); return stub; }
void CodeGen::gen_a(JavaByteCodes op, jtype jt) { if (gen_a_platf(op, jt)) { return; } if (gen_a_generic(op, jt)) { return; } if (is_f(jt) && gen_a_f(op, jt)) { return; } if (jt == i32 && gen_a_i32(op)) { return; } unsigned stackFix = 0; bool shft = op == OPCODE_ISHL || op == OPCODE_ISHR || op == OPCODE_IUSHR; const CallSig* rcs = NULL; if (is_f(jt)) { assert(jt == dbl64 || jt == flt32); char * helper = NULL; bool is_dbl = jt == dbl64; if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs_dbl(CCONV_STDCALL, dbl64, dbl64)); SYNC_FIRST(static const CallSig cs_flt(CCONV_STDCALL, flt32, flt32)); rcs = is_dbl? &cs_dbl : &cs_flt; stackFix = gen_stack_to_args(true, *rcs, 0, 1); helper = is_dbl ? (char*)&rt_h_neg_dbl64 : (char*)&rt_h_neg_flt32; gen_call_novm(*rcs, helper, 1); runlock(*rcs); } else { //if (m_jframe->dip(1).stype == st_imm && ) SYNC_FIRST(static const CallSig cs_dbl(CCONV_STDCALL, dbl64, dbl64, dbl64, i32)); SYNC_FIRST(static const CallSig cs_flt(CCONV_STDCALL, flt32, flt32, flt32, i32)); rcs = is_dbl? &cs_dbl : &cs_flt; stackFix = gen_stack_to_args(true, *rcs, 0, 2); helper = is_dbl ? (char*)&rt_h_dbl_a : (char*)&rt_h_flt_a; gen_call_novm(*rcs, helper, 2, op); runlock(*rcs); } } else if (jt==i64) { if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 1); gen_call_novm(*rcs, (void*)&rt_h_neg_i64, 1); runlock(*rcs); } else if (shft) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i64_shift, 2, op); runlock(*rcs); } else { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i64, i64, i64, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i64_a, 2, op); runlock(*rcs); } } else { assert(jt==i32); if (op == OPCODE_INEG) { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 1); gen_call_novm(*rcs, (void*)&rt_h_neg_i32, 1); runlock(*rcs); } else if (op == OPCODE_IADD || op == OPCODE_ISUB) { const Val& op2 = vstack(0); vpop(); rlock(op2); const Val& op1 = vstack(0); vpop(); rlock(op1); AR ar = valloc(i32); Opnd reg(i32, ar); //TODO: may eliminate additional register allocation mov(reg, op1.as_opnd()); alu(op == OPCODE_IADD ? alu_add : alu_sub, reg, op2.as_opnd()); runlock(op1); runlock(op2); vpush(Val(i32, ar)); return; } else { SYNC_FIRST(static const CallSig cs(CCONV_STDCALL, i32, i32, i32, i32)); rcs = &cs; stackFix = gen_stack_to_args(true, *rcs, 0, 2); gen_call_novm(*rcs, (void*)&rt_h_i32_a, 2, op); runlock(*rcs); } } assert(rcs != NULL); gen_save_ret(*rcs); if (stackFix != 0) { alu(alu_sub, sp, stackFix); } }