📄 translate.c.svn-base
字号:
case 6: /* fmovem */ case 7: { int addr; uint16_t mask; if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) goto undef; src = gen_lea(s, insn, OS_LONG); if (src == -1) { gen_addr_fault(s); return; } addr = gen_new_qreg(QMODE_I32); gen_op_mov32(addr, src); mask = 0x80; dest = QREG_F0; while (mask) { if (ext & mask) { s->is_mem = 1; if (ext & (1 << 13)) { /* store */ gen_st(s, f64, addr, dest); } else { /* load */ gen_ld(s, f64, dest, addr); } if (ext & (mask - 1)) gen_op_add32(addr, addr, gen_im32(8)); } mask >>= 1; dest++; } } return; } if (ext & (1 << 14)) { int tmp; /* Source effective address. */ switch ((ext >> 10) & 7) { case 0: opsize = OS_LONG; break; case 1: opsize = OS_SINGLE; break; case 4: opsize = OS_WORD; break; case 5: opsize = OS_DOUBLE; break; case 6: opsize = OS_BYTE; break; default: goto undef; } SRC_EA(tmp, opsize, -1, NULL); if (opsize == OS_DOUBLE) { src = tmp; } else { src = gen_new_qreg(QMODE_F64); switch (opsize) { case OS_LONG: case OS_WORD: case OS_BYTE: gen_op_i32_to_f64(src, tmp); break; case OS_SINGLE: gen_op_f32_to_f64(src, tmp); break; } } } else { /* Source register. */ src = FREG(ext, 10); } dest = FREG(ext, 7); res = gen_new_qreg(QMODE_F64); if (opmode != 0x3a) gen_op_movf64(res, dest); round = 1; switch (opmode) { case 0: case 0x40: case 0x44: /* fmove */ gen_op_movf64(res, src); break; case 1: /* fint */ gen_op_iround_f64(res, src); round = 0; break; case 3: /* fintrz */ gen_op_itrunc_f64(res, src); round = 0; break; case 4: case 0x41: case 0x45: /* fsqrt */ gen_op_sqrtf64(res, src); break; case 0x18: case 0x58: case 0x5c: /* fabs */ gen_op_absf64(res, src); break; case 0x1a: case 0x5a: case 0x5e: /* fneg */ gen_op_chsf64(res, src); break; case 0x20: case 0x60: case 0x64: /* fdiv */ gen_op_divf64(res, res, src); break; case 0x22: case 0x62: case 0x66: /* fadd */ gen_op_addf64(res, res, src); break; case 0x23: case 0x63: case 0x67: /* fmul */ gen_op_mulf64(res, res, src); break; case 0x28: case 0x68: case 0x6c: /* fsub */ gen_op_subf64(res, res, src); break; case 0x38: /* fcmp */ gen_op_sub_cmpf64(res, res, src); dest = 0; round = 0; break; case 0x3a: /* ftst */ gen_op_movf64(res, src); dest = 0; round = 0; break; default: goto undef; } if (round) { if (opmode & 0x40) { if ((opmode & 0x4) != 0) round = 0; } else if ((s->fpcr & M68K_FPCR_PREC) == 0) { round = 0; } } if (round) { int tmp; tmp = gen_new_qreg(QMODE_F32); gen_op_f64_to_f32(tmp, res); gen_op_f32_to_f64(res, tmp); } gen_op_fp_result(res); if (dest) { gen_op_movf64(dest, res); } return;undef: s->pc -= 2; disas_undef_fpu(s, insn);}DISAS_INSN(fbcc){ uint32_t offset; uint32_t addr; int flag; int zero; int l1; addr = s->pc; offset = ldsw_code(s->pc); s->pc += 2; if (insn & (1 << 6)) { offset = (offset << 16) | lduw_code(s->pc); s->pc += 2; } l1 = gen_new_label(); /* TODO: Raise BSUN exception. */ flag = gen_new_qreg(QMODE_I32); zero = gen_new_qreg(QMODE_F64); gen_op_zerof64(zero); gen_op_compare_quietf64(flag, QREG_FP_RESULT, zero); /* Jump to l1 if condition is true. */ switch (insn & 0xf) { case 0: /* f */ break; case 1: /* eq (=0) */ gen_op_jmp_z32(flag, l1); break; case 2: /* ogt (=1) */ gen_op_sub32(flag, flag, gen_im32(1)); gen_op_jmp_z32(flag, l1); break; case 3: /* oge (=0 or =1) */ gen_op_jmp_z32(flag, l1); gen_op_sub32(flag, flag, gen_im32(1)); gen_op_jmp_z32(flag, l1); break; case 4: /* olt (=-1) */ gen_op_jmp_s32(flag, l1); break; case 5: /* ole (=-1 or =0) */ gen_op_jmp_s32(flag, l1); gen_op_jmp_z32(flag, l1); break; case 6: /* ogl (=-1 or =1) */ gen_op_jmp_s32(flag, l1); gen_op_sub32(flag, flag, gen_im32(1)); gen_op_jmp_z32(flag, l1); break; case 7: /* or (=2) */ gen_op_sub32(flag, flag, gen_im32(2)); gen_op_jmp_z32(flag, l1); break; case 8: /* un (<2) */ gen_op_sub32(flag, flag, gen_im32(2)); gen_op_jmp_s32(flag, l1); break; case 9: /* ueq (=0 or =2) */ gen_op_jmp_z32(flag, l1); gen_op_sub32(flag, flag, gen_im32(2)); gen_op_jmp_z32(flag, l1); break; case 10: /* ugt (>0) */ /* ??? Add jmp_gtu. */ gen_op_sub32(flag, flag, gen_im32(1)); gen_op_jmp_ns32(flag, l1); break; case 11: /* uge (>=0) */ gen_op_jmp_ns32(flag, l1); break; case 12: /* ult (=-1 or =2) */ gen_op_jmp_s32(flag, l1); gen_op_sub32(flag, flag, gen_im32(2)); gen_op_jmp_z32(flag, l1); break; case 13: /* ule (!=1) */ gen_op_sub32(flag, flag, gen_im32(1)); gen_op_jmp_nz32(flag, l1); break; case 14: /* ne (!=0) */ gen_op_jmp_nz32(flag, l1); break; case 15: /* t */ gen_op_mov32(flag, gen_im32(1)); break; } gen_jmp_tb(s, 0, s->pc); gen_set_label(l1); gen_jmp_tb(s, 1, addr + offset);}DISAS_INSN(frestore){ /* TODO: Implement frestore. */ qemu_assert(0, "FRESTORE not implemented");}DISAS_INSN(fsave){ /* TODO: Implement fsave. */ qemu_assert(0, "FSAVE not implemented");}static inline int gen_mac_extract_word(DisasContext *s, int val, int upper){ int tmp = gen_new_qreg(QMODE_I32); if (s->env->macsr & MACSR_FI) { if (upper) gen_op_and32(tmp, val, gen_im32(0xffff0000)); else gen_op_shl32(tmp, val, gen_im32(16)); } else if (s->env->macsr & MACSR_SU) { if (upper) gen_op_sar32(tmp, val, gen_im32(16)); else gen_op_ext16s32(tmp, val); } else { if (upper) gen_op_shr32(tmp, val, gen_im32(16)); else gen_op_ext16u32(tmp, val); } return tmp;}DISAS_INSN(mac){ int rx; int ry; uint16_t ext; int acc; int l1; int tmp; int addr; int loadval; int dual; int saved_flags = -1; ext = lduw_code(s->pc); s->pc += 2; acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); dual = ((insn & 0x30) != 0 && (ext & 3) != 0); if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) { disas_undef(s, insn); return; } if (insn & 0x30) { /* MAC with load. */ tmp = gen_lea(s, insn, OS_LONG); addr = gen_new_qreg(QMODE_I32); gen_op_and32(addr, tmp, QREG_MAC_MASK); /* Load the value now to ensure correct exception behavior. Perform writeback after reading the MAC inputs. */ loadval = gen_load(s, OS_LONG, addr, 0); acc ^= 1; rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12); ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0); } else { loadval = addr = -1; rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); } gen_op_mac_clear_flags(); l1 = -1; if ((s->env->macsr & MACSR_OMC) != 0 && !dual) { /* Skip the multiply if we know we will ignore it. */ l1 = gen_new_label(); tmp = gen_new_qreg(QMODE_I32); gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8))); gen_op_jmp_nz32(tmp, l1); } if ((ext & 0x0800) == 0) { /* Word. */ rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0); ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0); } if (s->env->macsr & MACSR_FI) { gen_op_macmulf(rx, ry); } else { if (s->env->macsr & MACSR_SU) gen_op_macmuls(rx, ry); else gen_op_macmulu(rx, ry); switch ((ext >> 9) & 3) { case 1: gen_op_macshl(); break; case 3: gen_op_macshr(); break; } } if (dual) { /* Save the overflow flag from the multiply. */ saved_flags = gen_new_qreg(QMODE_I32); gen_op_mov32(saved_flags, QREG_MACSR); } if ((s->env->macsr & MACSR_OMC) != 0 && dual) { /* Skip the accumulate if the value is already saturated. */ l1 = gen_new_label(); tmp = gen_new_qreg(QMODE_I32); gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); gen_op_jmp_nz32(tmp, l1); } if (insn & 0x100) gen_op_macsub(acc); else gen_op_macadd(acc); if (s->env->macsr & MACSR_FI) gen_op_macsatf(acc); else if (s->env->macsr & MACSR_SU) gen_op_macsats(acc); else gen_op_macsatu(acc); if (l1 != -1) gen_set_label(l1); if (dual) { /* Dual accumulate variant. */ acc = (ext >> 2) & 3; /* Restore the overflow flag from the multiplier. */ gen_op_mov32(QREG_MACSR, saved_flags); if ((s->env->macsr & MACSR_OMC) != 0) { /* Skip the accumulate if the value is already saturated. */ l1 = gen_new_label(); tmp = gen_new_qreg(QMODE_I32); gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc)); gen_op_jmp_nz32(tmp, l1); } if (ext & 2) gen_op_macsub(acc); else gen_op_macadd(acc); if (s->env->macsr & MACSR_FI) gen_op_macsatf(acc); else if (s->env->macsr & MACSR_SU) gen_op_macsats(acc); else gen_op_macsatu(acc); if (l1 != -1) gen_set_label(l1); } gen_op_mac_set_flags(acc); if (insn & 0x30) { int rw; rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9); gen_op_mov32(rw, loadval); /* FIXME: Should address writeback happen with the masked or unmasked value? */ switch ((insn >> 3) & 7) { case 3: /* Post-increment. */ gen_op_add32(AREG(insn, 0), addr, gen_im32(4)); break; case 4: /* Pre-decrement. */ gen_op_mov32(AREG(insn, 0), addr); } }}DISAS_INSN(from_mac){ int rx; int acc; rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); acc = (insn >> 9) & 3; if (s->env->macsr & MACSR_FI) { gen_op_get_macf(rx, acc); } else if ((s->env->macsr & MACSR_OMC) == 0) { gen_op_get_maci(rx, acc); } else if (s->env->macsr & MACSR_SU) { gen_op_get_macs(rx, acc); } else { gen_op_get_macu(rx, acc); } if (insn & 0x40) gen_op_clear_mac(acc);}DISAS_INSN(move_mac){ int src; int dest; src = insn & 3; dest = (insn >> 9) & 3; gen_op_move_mac(dest, src); gen_op_mac_clear_flags(); gen_op_mac_set_flags(dest);}DISAS_INSN(from_macsr){ int reg; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); gen_op_mov32(reg, QREG_MACSR);}DISAS_INSN(from_mask){ int reg; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); gen_op_mov32(reg, QREG_MAC_MASK);}DISAS_INSN(from_mext){ int reg; int acc; reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0); acc = (insn & 0x400) ? 2 : 0; if (s->env->macsr & MACSR_FI) gen_op_get_mac_extf(reg, acc); else gen_op_get_mac_exti(reg, acc);}DISAS_INSN(macsr_to_ccr){ gen_op_mov32(QREG_CC_X, gen_im32(0)); gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf)); s->cc_op = CC_OP_FLAGS;}DISAS_INSN(to_mac){ int acc; int val; acc = (insn >>9) & 3; SRC_EA(val, OS_LONG, 0, NULL); if (s->env->macsr & MACSR_FI) { gen_op_set_macf(val, acc); } else if (s->env->macsr & MACSR_SU) { gen_op_set_macs(val, acc); } else { gen_op_set_macu(val, acc); } gen_op_mac_clear_flags(); gen_op_mac_set_flags(acc);}DISAS_INSN(to_macsr){ int val; SRC_EA(val, OS_LONG, 0, NULL); gen_op_set_macsr(val); gen_lookup_tb(s);}DISAS_INSN(to_mask){ int val; SRC_EA(val, OS_LONG, 0, NULL); gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000));}DISAS_INSN(to_mext){ int val; int acc; SRC_EA(val, OS_LONG, 0, NULL); acc = (insn & 0x400) ? 2 : 0; if (s->env->macsr & MACSR_FI) gen_op_set_mac_extf(val, acc); else if (s->env->macsr & MACSR_SU) gen_op_set_mac_exts(val, acc); else gen_op_set_mac_extu(val, acc);}static disas_proc opcode_table[65536];static voidregister_opcode (disas_proc proc, uint16_t opcode, uint16_t mask){ int i; int from; int to; /* Sanity check. All set bits must be included in the mask. */ if (opcode & ~mask) { fprintf(stderr, "qemu internal error: bogus opcode definition %04x/%04x\n", opcode, mask); abort(); } /* This could probably be cleverer. For now just optimize the case where the top bits are known. */ /* Find the first zero bit in the mask. */ i = 0x8000; while ((i & mask)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -