#include "system.h" #include #include /* Interpreter for portable bytecode. See "pb.ss". */ typedef uint32_t instruction_t; #define INSTR_op(instr) ((instr) & 0xFF) #define INSTR_d_dest(instr) (((instr) >> 8) & 0xF) #define INSTR_dr_dest(instr) INSTR_d_dest(instr) #define INSTR_dr_reg(instr) (((instr) >> 16) & 0xF) #define INSTR_di_dest(instr) INSTR_d_dest(instr) #define INSTR_di_imm(instr) (((int32_t)(instr)) >> 16) #define INSTR_di_imm_unsigned(instr) ((instr) >> 16) #define INSTR_drr_dest(instr) INSTR_d_dest(instr) #define INSTR_drr_reg1(instr) (((instr) >> 12) & 0xF) #define INSTR_drr_reg2(instr) (((instr) >> 16) & 0xF) #define INSTR_dri_dest(instr) INSTR_d_dest(instr) #define INSTR_dri_reg(instr) (((instr) >> 12) & 0xF) #define INSTR_dri_imm(instr) (((int32_t)(instr)) >> 16) #define INSTR_i_imm(instr) (((int32_t)(instr)) >> 8) #define SHIFT_MASK(v) ((v) & (ptr_bits-1)) static uptr regs[16]; static double fpregs[8]; enum { Cretval = 9, Carg1 = 9, Carg2, Carg3, Carg4, Carg5, Carg6, Carg7 }; enum { Cfpretval = 1, Cfparg1 = 1, Cfparg2, Cfparg3, Cfparg4, Cfparg5, Cfparg6 }; void S_machine_init() {} #define SIGN_FLIP(r, a, b) ((~((a ^ b) | (r ^ ~b))) >> (ptr_bits-1)) #if __GNUC__ >= 5 # define USE_OVERFLOW_INTRINSICS 1 #else # define USE_OVERFLOW_INTRINSICS 0 #endif #if 0 # define TRACE(print, record) print #elif 0 # define TRACE(print, record) record static instruction_t *branch_from, *branch_to; static instruction_t *jump_from, *jump_to; static instruction_t *interp_from, *interp_to; static instruction_t *call_from; static void *call_to; #else # define TRACE(print, record) /* empty */ #endif void S_pb_interp(ptr tc, void *bytecode) { instruction_t *ip = (instruction_t *)bytecode, *next_ip, instr; int flag = 0; regs[0] = (uptr)tc; TRACE(printf("enter %p\n", ip), ); while (1) { instr = *ip; next_ip = ip + 1; switch(INSTR_op(instr)) { case pb_mov16_pb_zero_bits_pb_shift0: regs[INSTR_di_dest(instr)] = (uptr)INSTR_di_imm_unsigned(instr); break; case pb_mov16_pb_zero_bits_pb_shift1: regs[INSTR_di_dest(instr)] = (uptr)INSTR_di_imm_unsigned(instr) << 16; break; case pb_mov16_pb_zero_bits_pb_shift2: #if ptr_bits == 64 regs[INSTR_di_dest(instr)] = (uptr)INSTR_di_imm_unsigned(instr) << 32; #else regs[INSTR_di_dest(instr)] = 0; #endif break; case pb_mov16_pb_zero_bits_pb_shift3: #if ptr_bits == 64 regs[INSTR_di_dest(instr)] = (uptr)INSTR_di_imm_unsigned(instr) << 48; #else regs[INSTR_di_dest(instr)] = 0; #endif break; case pb_mov16_pb_keep_bits_pb_shift0: regs[INSTR_di_dest(instr)] |= (uptr)INSTR_di_imm_unsigned(instr); break; case pb_mov16_pb_keep_bits_pb_shift1: regs[INSTR_di_dest(instr)] |= (uptr)INSTR_di_imm_unsigned(instr) << 16; break; case pb_mov16_pb_keep_bits_pb_shift2: #if ptr_bits == 64 regs[INSTR_di_dest(instr)] |= (uptr)INSTR_di_imm_unsigned(instr) << 32; #endif break; case pb_mov16_pb_keep_bits_pb_shift3: #if ptr_bits == 64 regs[INSTR_di_dest(instr)] |= (uptr)INSTR_di_imm_unsigned(instr) << 48; #endif break; case pb_mov_pb_i_i: regs[INSTR_dr_dest(instr)] = regs[INSTR_dr_reg(instr)]; break; case pb_mov_pb_d_d: fpregs[INSTR_dr_dest(instr)] = fpregs[INSTR_dr_reg(instr)]; break; case pb_mov_pb_i_d: fpregs[INSTR_dr_dest(instr)] = (double)(iptr)regs[INSTR_dr_reg(instr)]; break; case pb_mov_pb_d_i: regs[INSTR_dr_dest(instr)] = (iptr)fpregs[INSTR_dr_reg(instr)]; break; #if ptr_bits == 64 case pb_mov_pb_i_bits_d_bits: memcpy(&fpregs[INSTR_dr_dest(instr)], ®s[INSTR_dr_reg(instr)], sizeof(double)); break; case pb_mov_pb_d_bits_i_bits: memcpy(®s[INSTR_dr_dest(instr)], &fpregs[INSTR_dr_reg(instr)], sizeof(double)); break; #else case pb_mov_pb_i_i_bits_d_bits: { uint64_t d; d = regs[INSTR_drr_reg1(instr)] | ((uint64_t)regs[INSTR_drr_reg2(instr)] << 32); memcpy(&fpregs[INSTR_drr_dest(instr)], &d, sizeof(double)); } break; case pb_mov_pb_d_lo_bits_i_bits: { uint64_t d; memcpy(&d, &fpregs[INSTR_dr_reg(instr)], sizeof(double)); regs[INSTR_dr_dest(instr)] = d; } break; case pb_mov_pb_d_hi_bits_i_bits: { uint64_t d; memcpy(&d, &fpregs[INSTR_dr_reg(instr)], sizeof(double)); d >>= 32; regs[INSTR_dr_dest(instr)] = d; } break; #endif case pb_mov_pb_s_d: { float f; #ifdef PORTABLE_BYTECODE_BIGENDIAN memcpy(&f, (char *)&fpregs[INSTR_dr_reg(instr)] + 4, sizeof(float)); #else memcpy(&f, &fpregs[INSTR_dr_reg(instr)], sizeof(float)); #endif fpregs[INSTR_dr_dest(instr)] = f; } break; case pb_mov_pb_d_s: { float f; f = fpregs[INSTR_dr_reg(instr)]; #ifdef PORTABLE_BYTECODE_BIGENDIAN memcpy((char *)&fpregs[INSTR_dr_dest(instr)] + 4, &f, sizeof(float)); #else memcpy(&fpregs[INSTR_dr_dest(instr)], &f, sizeof(float)); #endif } break; case pb_bin_op_pb_no_signal_pb_add_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_add_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] + (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_sub_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] - regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_sub_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] - (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_mul_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] * regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_mul_pb_immediate: regs[INSTR_dri_dest(instr)] = (uptr)regs[INSTR_dri_reg(instr)] * (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_div_pb_register: regs[INSTR_drr_dest(instr)] = (iptr)regs[INSTR_drr_reg1(instr)] / (iptr)regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_div_pb_immediate: regs[INSTR_dri_dest(instr)] = (iptr)regs[INSTR_dri_reg(instr)] / (iptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_and_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] & regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_and_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] & (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_ior_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] | regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_ior_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] | (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_xor_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] ^ regs[INSTR_drr_reg2(instr)]; break; case pb_bin_op_pb_no_signal_pb_xor_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] ^ (uptr)INSTR_dri_imm(instr); break; case pb_bin_op_pb_no_signal_pb_lsl_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] << SHIFT_MASK(regs[INSTR_drr_reg2(instr)]); break; case pb_bin_op_pb_no_signal_pb_lsl_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] << SHIFT_MASK(INSTR_dri_imm(instr)); break; case pb_bin_op_pb_no_signal_pb_lsr_pb_register: regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] >> SHIFT_MASK(regs[INSTR_drr_reg2(instr)]); break; case pb_bin_op_pb_no_signal_pb_lsr_pb_immediate: regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] >> SHIFT_MASK(INSTR_dri_imm(instr)); break; case pb_bin_op_pb_no_signal_pb_asr_pb_register: regs[INSTR_drr_dest(instr)] = (iptr)regs[INSTR_drr_reg1(instr)] >> SHIFT_MASK(regs[INSTR_drr_reg2(instr)]); break; case pb_bin_op_pb_no_signal_pb_asr_pb_immediate: regs[INSTR_dri_dest(instr)] = (iptr)regs[INSTR_dri_reg(instr)] >> SHIFT_MASK(INSTR_dri_imm(instr)); break; case pb_bin_op_pb_no_signal_pb_lslo_pb_register: #ifdef PORTABLE_BYTECODE_BIGENDIAN regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] >> regs[INSTR_drr_reg2(instr)]; #else regs[INSTR_drr_dest(instr)] = regs[INSTR_drr_reg1(instr)] << regs[INSTR_drr_reg2(instr)]; #endif break; case pb_bin_op_pb_no_signal_pb_lslo_pb_immediate: #ifdef PORTABLE_BYTECODE_BIGENDIAN regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] >> INSTR_dri_imm(instr); #else regs[INSTR_dri_dest(instr)] = regs[INSTR_dri_reg(instr)] << INSTR_dri_imm(instr); #endif break; case pb_bin_op_pb_signal_pb_add_pb_register: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_drr_reg1(instr)]; iptr b = (iptr)regs[INSTR_drr_reg2(instr)]; iptr r; flag = __builtin_add_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_drr_reg1(instr)]; uptr b = regs[INSTR_drr_reg2(instr)]; uptr r = a + b; regs[INSTR_drr_dest(instr)] = r; flag = SIGN_FLIP(r, a, b); #endif } break; case pb_bin_op_pb_signal_pb_add_pb_immediate: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_dri_reg(instr)]; iptr b = INSTR_dri_imm(instr); iptr r; flag = __builtin_add_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_dri_reg(instr)]; uptr b = (uptr)INSTR_dri_imm(instr); uptr r = a + b; regs[INSTR_dri_dest(instr)] = r; flag = SIGN_FLIP(r, a, b); #endif } break; case pb_bin_op_pb_signal_pb_sub_pb_register: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_drr_reg1(instr)]; iptr b = (iptr)regs[INSTR_drr_reg2(instr)]; iptr r; flag = __builtin_sub_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_drr_reg1(instr)]; uptr b = regs[INSTR_drr_reg2(instr)]; uptr r = a - b; regs[INSTR_drr_dest(instr)] = r; flag = SIGN_FLIP(r, a, ~b); #endif } break; case pb_bin_op_pb_signal_pb_sub_pb_immediate: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_dri_reg(instr)]; iptr b = INSTR_dri_imm(instr); iptr r; flag = __builtin_sub_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_dri_reg(instr)]; uptr b = (uptr)INSTR_dri_imm(instr); uptr r = a - b; regs[INSTR_dri_dest(instr)] = r; flag = SIGN_FLIP(r, a, ~b); #endif } break; case pb_bin_op_pb_signal_pb_mul_pb_register: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_drr_reg1(instr)]; iptr b = (iptr)regs[INSTR_drr_reg2(instr)]; iptr r; flag = __builtin_mul_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_drr_reg1(instr)]; uptr b = regs[INSTR_drr_reg2(instr)]; uptr r = a * b; regs[INSTR_drr_dest(instr)] = r; if (b != 0) { if (b == (uptr)-1) flag = (a != r * (uptr)-1); else flag = ((iptr)a != (iptr)r / (iptr)b); } else flag = 0; #endif } break; case pb_bin_op_pb_signal_pb_mul_pb_immediate: { #if USE_OVERFLOW_INTRINSICS iptr a = (iptr)regs[INSTR_dri_reg(instr)]; iptr b = INSTR_dri_imm(instr); iptr r; flag = __builtin_mul_overflow(a, b, &r); regs[INSTR_drr_dest(instr)] = (uptr)r; #else uptr a = regs[INSTR_dri_reg(instr)]; uptr b = (uptr)INSTR_dri_imm(instr); uptr r = a * b; regs[INSTR_dri_dest(instr)] = r; if (b != 0) { if (b == (uptr)-1) flag = (a != r * (uptr)-1); else flag = ((iptr)a != (iptr)r / (iptr)b); } else flag = 0; #endif } break; case pb_bin_op_pb_signal_pb_subz_pb_register: { iptr r = regs[INSTR_drr_reg1(instr)] - regs[INSTR_drr_reg2(instr)]; regs[INSTR_drr_dest(instr)] = r; flag = (r == 0); } break; case pb_bin_op_pb_signal_pb_subz_pb_immediate: { iptr r = regs[INSTR_dri_reg(instr)] - (uptr)INSTR_dri_imm(instr); regs[INSTR_dri_dest(instr)] = r; flag = (r == 0); } break; case pb_cmp_op_pb_eq_pb_register: flag = regs[INSTR_dr_dest(instr)] == regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_eq_pb_immediate: flag = regs[INSTR_di_dest(instr)] == (uptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_lt_pb_register: flag = (iptr)regs[INSTR_dr_dest(instr)] < (iptr)regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_lt_pb_immediate: flag = (iptr)regs[INSTR_di_dest(instr)] < (iptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_gt_pb_register: flag = (iptr)regs[INSTR_dr_dest(instr)] > (iptr)regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_gt_pb_immediate: flag = (iptr)regs[INSTR_di_dest(instr)] > (iptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_le_pb_register: flag = (iptr)regs[INSTR_dr_dest(instr)] <= (iptr)regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_le_pb_immediate: flag = (iptr)regs[INSTR_di_dest(instr)] <= (iptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_ge_pb_register: flag = (iptr)regs[INSTR_dr_dest(instr)] >= (iptr)regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_ge_pb_immediate: flag = (iptr)regs[INSTR_di_dest(instr)] >= (iptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_ab_pb_register: flag = regs[INSTR_dr_dest(instr)] > regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_ab_pb_immediate: flag = regs[INSTR_di_dest(instr)] > (uptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_bl_pb_register: flag = regs[INSTR_dr_dest(instr)] < regs[INSTR_dr_reg(instr)]; break; case pb_cmp_op_pb_bl_pb_immediate: flag = regs[INSTR_di_dest(instr)] < (uptr)INSTR_di_imm(instr); break; case pb_cmp_op_pb_cs_pb_register: flag = ((regs[INSTR_dr_dest(instr)] & regs[INSTR_dr_reg(instr)]) != 0); break; case pb_cmp_op_pb_cs_pb_immediate: flag = ((regs[INSTR_di_dest(instr)] & (uptr)INSTR_di_imm(instr)) != 0); break; case pb_cmp_op_pb_cc_pb_register: flag = ((regs[INSTR_dr_dest(instr)] & regs[INSTR_dr_reg(instr)]) == 0); break; case pb_cmp_op_pb_cc_pb_immediate: flag = ((regs[INSTR_di_dest(instr)] & (uptr)INSTR_di_imm(instr)) == 0); break; case pb_fp_bin_op_pb_add_pb_register: fpregs[INSTR_drr_dest(instr)] = fpregs[INSTR_drr_reg1(instr)] + fpregs[INSTR_drr_reg2(instr)]; break; case pb_fp_bin_op_pb_sub_pb_register: fpregs[INSTR_drr_dest(instr)] = fpregs[INSTR_drr_reg1(instr)] - fpregs[INSTR_drr_reg2(instr)]; break; case pb_fp_bin_op_pb_mul_pb_register: fpregs[INSTR_drr_dest(instr)] = fpregs[INSTR_drr_reg1(instr)] * fpregs[INSTR_drr_reg2(instr)]; break; case pb_fp_bin_op_pb_div_pb_register: fpregs[INSTR_drr_dest(instr)] = fpregs[INSTR_drr_reg1(instr)] / fpregs[INSTR_drr_reg2(instr)]; break; case pb_un_op_pb_not_pb_register: regs[INSTR_dr_dest(instr)] = ~(regs[INSTR_dr_reg(instr)]); break; case pb_un_op_pb_not_pb_immediate: regs[INSTR_di_dest(instr)] = ~((uptr)(iptr)INSTR_di_imm(instr)); break; case pb_fp_un_op_pb_sqrt_pb_register: fpregs[INSTR_dr_dest(instr)] = sqrt(fpregs[INSTR_dr_reg(instr)]); break; case pb_fp_cmp_op_pb_eq_pb_register: flag = fpregs[INSTR_dr_dest(instr)] == fpregs[INSTR_dr_reg(instr)]; break; case pb_fp_cmp_op_pb_lt_pb_register: flag = fpregs[INSTR_dr_dest(instr)] < fpregs[INSTR_dr_reg(instr)]; break; case pb_fp_cmp_op_pb_le_pb_register: flag = fpregs[INSTR_dr_dest(instr)] <= fpregs[INSTR_dr_reg(instr)]; break; case pb_rev_op_pb_int16_pb_register: #if ptr_bits == 64 regs[INSTR_dr_dest(instr)] = ((uptr)((iptr)(regs[INSTR_dr_reg(instr)] << 56) >> 48) | ((regs[INSTR_dr_reg(instr)] & 0xFF00) >> 8)); #else regs[INSTR_dr_dest(instr)] = ((uptr)((iptr)(regs[INSTR_dr_reg(instr)] << 24) >> 16) | ((regs[INSTR_dr_reg(instr)] & 0xFF00) >> 8)); #endif break; case pb_rev_op_pb_uint16_pb_register: regs[INSTR_dr_dest(instr)] = (((regs[INSTR_dr_reg(instr)] & 0x00FF) << 8) | ((regs[INSTR_dr_reg(instr)] & 0xFF00) >> 8)); break; case pb_rev_op_pb_int32_pb_register: #if ptr_bits == 64 regs[INSTR_dr_dest(instr)] = ((uptr)((iptr)(regs[INSTR_dr_reg(instr)] << 56) >> 32) | ((regs[INSTR_dr_reg(instr)] & (uptr)0xFF000000) >> 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00FF0000) >> 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000FF00) << 8)); #else regs[INSTR_dr_dest(instr)] = ((regs[INSTR_dr_reg(instr)] << 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0xFF000000) >> 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00FF0000) >> 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000FF00) << 8)); #endif break; case pb_rev_op_pb_uint32_pb_register: regs[INSTR_dr_dest(instr)] = (((regs[INSTR_dr_reg(instr)] & (uptr)0x000000FF) << 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0xFF000000) >> 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00FF0000) >> 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000FF00) << 8)); break; case pb_rev_op_pb_int64_pb_register: #if ptr_bits == 64 regs[INSTR_dr_dest(instr)] = (((regs[INSTR_dr_reg(instr)] & (uptr)0x00000000000000FF) << 56) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x000000000000FF00) << 40) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000000000FF0000) << 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00000000FF000000) << 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x000000FF00000000) >> 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000FF0000000000) >> 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00FF000000000000) >> 40) | ((regs[INSTR_dr_reg(instr)] & (uptr)0xFF00000000000000) >> 56)); #else regs[INSTR_dr_dest(instr)] = (((regs[INSTR_dr_reg(instr)] & (uptr)0x000000FF) << 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0xFF000000) >> 24) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x00FF0000) >> 8) | ((regs[INSTR_dr_reg(instr)] & (uptr)0x0000FF00) << 8)); #endif break; case pb_ld_op_pb_int8_pb_register: regs[INSTR_drr_dest(instr)] = *(int8_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_int8_pb_immediate: regs[INSTR_dri_dest(instr)] = *(int8_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_uint8_pb_register: regs[INSTR_drr_dest(instr)] = *(uint8_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_uint8_pb_immediate: regs[INSTR_dri_dest(instr)] = *(uint8_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_int16_pb_register: regs[INSTR_drr_dest(instr)] = *(int16_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_int16_pb_immediate: regs[INSTR_dri_dest(instr)] = *(int16_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_uint16_pb_register: regs[INSTR_drr_dest(instr)] = *(uint16_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_uint16_pb_immediate: regs[INSTR_dri_dest(instr)] = *(uint16_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_int32_pb_register: regs[INSTR_drr_dest(instr)] = *(int32_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_int32_pb_immediate: regs[INSTR_dri_dest(instr)] = *(int32_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_uint32_pb_register: regs[INSTR_drr_dest(instr)] = *(uint32_t *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_uint32_pb_immediate: regs[INSTR_dri_dest(instr)] = *(uint32_t *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_int64_pb_register: regs[INSTR_drr_dest(instr)] = *(uptr *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_int64_pb_immediate: regs[INSTR_dri_dest(instr)] = *(uptr *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_double_pb_register: fpregs[INSTR_drr_dest(instr)] = *(double *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_double_pb_immediate: fpregs[INSTR_dri_dest(instr)] = *(double *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_ld_op_pb_single_pb_register: fpregs[INSTR_drr_dest(instr)] = *(float *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]); break; case pb_ld_op_pb_single_pb_immediate: fpregs[INSTR_dri_dest(instr)] = *(float *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)); break; case pb_st_op_pb_int8_pb_register: *(char *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = (char)regs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_int8_pb_immediate: *(char *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = (char)regs[INSTR_dri_dest(instr)]; break; case pb_st_op_pb_int16_pb_register: *(short *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = (short)regs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_int16_pb_immediate: *(short *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = (short)regs[INSTR_dri_dest(instr)]; break; case pb_st_op_pb_int32_pb_register: *(int *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = (int)regs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_int32_pb_immediate: *(int *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = (int)regs[INSTR_dri_dest(instr)]; break; case pb_st_op_pb_int64_pb_register: *(uptr *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = regs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_int64_pb_immediate: *(uptr *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = regs[INSTR_dri_dest(instr)]; break; case pb_st_op_pb_double_pb_register: *(double *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = fpregs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_double_pb_immediate: *(double *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = fpregs[INSTR_dri_dest(instr)]; break; case pb_st_op_pb_single_pb_register: *(float *)TO_VOIDP(regs[INSTR_drr_reg1(instr)] + regs[INSTR_drr_reg2(instr)]) = fpregs[INSTR_drr_dest(instr)]; break; case pb_st_op_pb_single_pb_immediate: *(float *)TO_VOIDP(regs[INSTR_dri_reg(instr)] + INSTR_dri_imm(instr)) = fpregs[INSTR_dri_dest(instr)]; break; case pb_b_op_pb_fals_pb_register: if (!flag) { next_ip = (instruction_t *)TO_VOIDP(regs[INSTR_dr_reg(instr)]); TRACE(printf("branch %p -> %p\n", ip, next_ip), { branch_from = ip; branch_to = next_ip; }); } break; case pb_b_op_pb_fals_pb_immediate: if (!flag) { next_ip = (instruction_t *)TO_VOIDP((char *)next_ip + INSTR_i_imm(instr)); TRACE(printf("branch %p -> %p\n", ip, next_ip), { branch_from = ip; branch_to = next_ip; }); } break; case pb_b_op_pb_true_pb_register: if (flag) { next_ip = (instruction_t *)TO_VOIDP(regs[INSTR_dr_reg(instr)]); TRACE(printf("branch %p -> %p\n", ip, next_ip), { branch_from = ip; branch_to = next_ip; }); } break; case pb_b_op_pb_true_pb_immediate: if (flag) { next_ip = (instruction_t *)TO_VOIDP((char *)next_ip + INSTR_i_imm(instr)); TRACE(printf("branch %p -> %p\n", ip, next_ip), { branch_from = ip; branch_to = next_ip; }); } break; case pb_b_op_pb_always_pb_register: next_ip = (instruction_t *)TO_VOIDP(regs[INSTR_dr_reg(instr)]); TRACE(printf("jump %p -> %p\n", ip, next_ip), { jump_from = ip; jump_to = next_ip; }); break; case pb_b_op_pb_always_pb_immediate: next_ip = (instruction_t *)TO_VOIDP((char *)next_ip + INSTR_i_imm(instr)); TRACE(printf("jump %p -> %p\n", ip, next_ip), { jump_from = ip; jump_to = next_ip; }); break; case pb_bs_op_pb_register: next_ip = (instruction_t *)TO_VOIDP(*(uptr *)TO_VOIDP(regs[INSTR_dr_dest(instr)] + regs[INSTR_dr_reg(instr)])); TRACE(printf("jump %p -> %p\n", ip, next_ip), { jump_from = ip; jump_to = next_ip; }); break; case pb_bs_op_pb_immediate: next_ip = (instruction_t *)TO_VOIDP(*(uptr *)TO_VOIDP(regs[INSTR_di_dest(instr)] + INSTR_di_imm(instr))); TRACE(printf("jump %p -> %p\n", ip, next_ip), { jump_from = ip; jump_to = next_ip; }); break; case pb_return: return; /* <--- not break */ case pb_adr: regs[INSTR_di_dest(instr)] = (uptr)TO_PTR(next_ip) + INSTR_di_imm(instr); break; case pb_interp: { void *code = TO_VOIDP(regs[INSTR_d_dest(instr)]); TRACE(printf("interp %p -> %p\n", ip, code), { interp_from = ip; interp_to = (instruction_t *)regs[0]; }); S_pb_interp((ptr)regs[0], code); } break; case pb_call: { void *proc = TO_VOIDP(regs[INSTR_dri_dest(instr)]); TRACE(printf("call %p -> %p %x\n", ip, proc, INSTR_dri_imm(instr)), { call_from = ip; call_to = proc; }); switch (INSTR_dri_imm(instr)) { case pb_call_void: ((pb_void_t)proc)(); break; case pb_call_void_uptr: ((pb_void_uptr_t)proc)(regs[Carg1]); break; case pb_call_void_int32: ((pb_void_int32_t)proc)(regs[Carg1]); break; case pb_call_void_uint32: ((pb_void_uint32_t)proc)(regs[Carg1]); break; case pb_call_void_voids: ((pb_void_voids_t)proc)(TO_VOIDP(regs[Carg1])); break; case pb_call_void_uptr_uint32: ((pb_void_uptr_uint32_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_void_int32_uptr: ((pb_void_int32_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_void_int32_voids: ((pb_void_int32_voids_t)proc)(regs[Carg1], TO_VOIDP(regs[Carg2])); break; case pb_call_void_uptr_voids: ((pb_void_uptr_voids_t)proc)(regs[Carg1], TO_VOIDP(regs[Carg2])); break; case pb_call_void_int32_int32: ((pb_void_int32_int32_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_void_uptr_uptr: ((pb_void_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_void_voids_voids: ((pb_void_voids_voids_t)proc)(TO_VOIDP(regs[Carg1]), TO_VOIDP(regs[Carg2])); break; case pb_call_void_uptr_uptr_uptr: ((pb_void_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3]); break; case pb_call_void_uptr_uptr_uptr_uptr_uptr: ((pb_void_uptr_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5]); break; case pb_call_int32: regs[Cretval] = ((pb_int32_t)proc)(); break; case pb_call_int32_uptr: regs[Cretval] = ((pb_int32_uptr_t)proc)(regs[Carg1]); break; case pb_call_int32_voids: regs[Cretval] = ((pb_int32_voids_t)proc)(TO_VOIDP(regs[Carg1])); break; case pb_call_int32_uptr_int32: regs[Cretval] = ((pb_int32_uptr_int32_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_int32_uptr_uptr: regs[Cretval] = ((pb_int32_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_int32_int32_int32: regs[Cretval] = ((pb_int32_int32_int32_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_int32_voids_int32: regs[Cretval] = ((pb_int32_voids_int32_t)proc)(TO_VOIDP(regs[Carg1]), regs[Carg2]); break; case pb_call_int32_int32_voids: regs[Cretval] = ((pb_int32_int32_voids_t)proc)(regs[Carg1], TO_VOIDP(regs[Carg2])); break; case pb_call_int32_double_double_double_double_double_double: regs[Cretval] = ((pb_int32_double_double_double_double_double_double_t)proc)(fpregs[Cfparg1], fpregs[Cfparg2], fpregs[Cfparg3], fpregs[Cfparg4], fpregs[Cfparg5], fpregs[Cfparg6]); break; case pb_call_uint32: regs[Cretval] = ((pb_uint32_t)proc)(); break; case pb_call_double_double: fpregs[Cfpretval] = ((pb_double_double_t)proc)(fpregs[Cfparg1]); break; case pb_call_double_uptr: fpregs[Cfpretval] = ((pb_double_uptr_t)proc)(regs[Carg1]); break; case pb_call_double_double_double: fpregs[Cfpretval] = ((pb_double_double_double_t)proc)(fpregs[Cfparg1], fpregs[Cfparg2]); break; case pb_call_int32_int32: regs[Cretval] = ((pb_int32_int32_t)proc)(regs[Carg1]); break; case pb_call_int32_int32_uptr: regs[Cretval] = ((pb_int32_int32_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_int32_voids_voids_voids_voids_uptr: regs[Cretval] = ((pb_int32_voids_voids_voids_voids_uptr_t)proc)(TO_VOIDP(regs[Carg1]), TO_VOIDP(regs[Carg2]), TO_VOIDP(regs[Carg3]), TO_VOIDP(regs[Carg4]), regs[Carg5]); break; case pb_call_uptr: regs[Cretval] = ((pb_uptr_t)proc)(); break; case pb_call_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_t)proc)(regs[Carg1]); break; case pb_call_uptr_int32: regs[Cretval] = ((pb_uptr_int32_t)proc)(regs[Carg1]); break; case pb_call_uptr_voids: regs[Cretval] = ((pb_uptr_voids_t)proc)(TO_VOIDP(regs[Carg1])); break; case pb_call_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_uptr_uptr_int32: regs[Cretval] = ((pb_uptr_uptr_int32_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_uptr_uptr_int64: #if ptr_bits == 64 regs[Cretval] = ((pb_uptr_uptr_int64_t)proc)(regs[Carg1], regs[Carg2]); #else regs[Cretval] = ((pb_uptr_uptr_int64_t)proc)(regs[Carg1], regs[Carg2] | ((int64_t)regs[Carg3] << 32)); #endif break; case pb_call_uptr_int32_uptr: regs[Cretval] = ((pb_uptr_int32_uptr_t)proc)(regs[Carg1], regs[Carg2]); break; case pb_call_uptr_voids_uptr: regs[Cretval] = ((pb_uptr_voids_uptr_t)proc)(TO_VOIDP(regs[Carg1]), regs[Carg2]); break; case pb_call_uptr_uptr_voids: regs[Cretval] = ((pb_uptr_uptr_voids_t)proc)(regs[Carg1], TO_VOIDP(regs[Carg2])); break; case pb_call_uptr_voids_int32: regs[Cretval] = ((pb_uptr_voids_int32_t)proc)(TO_VOIDP(regs[Carg1]), regs[Carg2]); break; case pb_call_uptr_voids_voids: regs[Cretval] = ((pb_uptr_voids_voids_t)proc)(TO_VOIDP(regs[Carg1]), TO_VOIDP(regs[Carg2])); break; case pb_call_uptr_uptr_int32_int32: regs[Cretval] = ((pb_uptr_uptr_int32_int32_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3]); break; case pb_call_uptr_voids_int32_int32: regs[Cretval] = ((pb_uptr_voids_int32_int32_t)proc)(TO_VOIDP(regs[Carg1]), regs[Carg2], regs[Carg3]); break; case pb_call_uptr_voids_uptr_uptr: regs[Cretval] = ((pb_uptr_voids_uptr_uptr_t)proc)(TO_VOIDP(regs[Carg1]), regs[Carg2], regs[Carg3]); break; case pb_call_uptr_uptr_uptr_int32: regs[Cretval] = ((pb_uptr_uptr_uptr_int32_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3]); break; case pb_call_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3]); break; case pb_call_uptr_int32_int32_uptr: regs[Cretval] = ((pb_uptr_int32_int32_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3]); break; case pb_call_uptr_int32_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_int32_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4]); break; case pb_call_uptr_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4]); break; case pb_call_uptr_int32_int32_uptr_uptr: regs[Cretval] = ((pb_uptr_int32_int32_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4]); break; case pb_call_uptr_int32_voids_uptr_uptr: regs[Cretval] = ((pb_uptr_int32_voids_uptr_uptr_t)proc)(regs[Carg1], TO_VOIDP(regs[Carg2]), regs[Carg3], regs[Carg4]); break; case pb_call_uptr_uptr_uptr_uptr_uptr_int32: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_int32_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5]); break; case pb_call_uptr_uptr_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5]); break; case pb_call_uptr_voids_voids_voids_voids_uptr: regs[Cretval] = ((pb_uptr_voids_voids_voids_voids_uptr_t)proc)(TO_VOIDP(regs[Carg1]), TO_VOIDP(regs[Carg2]), TO_VOIDP(regs[Carg3]), TO_VOIDP(regs[Carg4]), regs[Carg5]); break; case pb_call_uptr_uptr_int32_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_int32_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5], regs[Carg6]); break; case pb_call_uptr_uptr_uptr_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5], regs[Carg6]); break; case pb_call_uptr_uptr_uptr_uptr_uptr_uptr_uptr_int32: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_int32_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5], regs[Carg6], regs[Carg7]); break; case pb_call_uptr_uptr_uptr_uptr_uptr_uptr_uptr_uptr: regs[Cretval] = ((pb_uptr_uptr_uptr_uptr_uptr_uptr_uptr_uptr_t)proc)(regs[Carg1], regs[Carg2], regs[Carg3], regs[Carg4], regs[Carg5], regs[Carg6], regs[Carg7]); break; case pb_call_uptr_double_double_double_double_double_double: regs[Cretval] = ((pb_uptr_double_double_double_double_double_double_t)proc)(fpregs[Cfparg1], fpregs[Cfparg2], fpregs[Cfparg3], fpregs[Cfparg4], fpregs[Cfparg5], fpregs[Cfparg6]); break; case pb_call_voids: regs[Cretval] = TO_PTR(((pb_voids_t)proc)()); break; case pb_call_voids_uptr: regs[Cretval] = TO_PTR(((pb_voids_uptr_t)proc)(regs[Carg1])); break; default: S_error_abort("unsupported call prototype"); break; } } break; case pb_inc_pb_register: { uptr r = *(uptr *)TO_VOIDP(regs[INSTR_dr_dest(instr)]) + regs[INSTR_dr_reg(instr)]; *(uptr *)TO_VOIDP(regs[INSTR_dr_dest(instr)]) = r; flag = (r == 0); } break; case pb_inc_pb_immediate: { uptr r = *(uptr *)TO_VOIDP(regs[INSTR_di_dest(instr)]) + INSTR_di_imm(instr); *(uptr *)TO_VOIDP(regs[INSTR_di_dest(instr)]) = r; flag = (r == 0); } break; case pb_lock: { uptr *l = TO_VOIDP(regs[INSTR_d_dest(instr)]); if (*l == 0) { *l = 1; flag = 1; } else flag = 0; } break; case pb_cas: { uptr *l = TO_VOIDP(regs[INSTR_drr_dest(instr)]); uptr old = regs[INSTR_drr_reg1(instr)]; uptr new = regs[INSTR_drr_reg2(instr)]; if (*l == old) { *l = new; flag = 1; } else flag = 0; } break; default: S_error_abort("illegal pb instruction"); break; } ip = next_ip; } }