Commit ea6cf6be8e078cbe87f0e3fe226e3afdd92505e0
1 parent
6db45e65
Emulate more fpu opcodes, by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3002 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
183 additions
and
1 deletions
target-sh4/cpu.h
| ... | ... | @@ -99,6 +99,7 @@ typedef struct CPUSH4State { |
| 99 | 99 | /* temporary float registers */ |
| 100 | 100 | float32 ft0, ft1; |
| 101 | 101 | float64 dt0, dt1; |
| 102 | + float_status fp_status; | |
| 102 | 103 | |
| 103 | 104 | /* Those belong to the specific unit (SH7750) but are handled here */ |
| 104 | 105 | uint32_t mmucr; /* MMU control register */ | ... | ... |
target-sh4/op.c
| ... | ... | @@ -509,6 +509,9 @@ void OPPROTO op_##store##_##target##_T0 (void) \ |
| 509 | 509 | void OPPROTO op_lds_T0_fpscr(void) |
| 510 | 510 | { |
| 511 | 511 | env->fpscr = T0 & 0x003fffff; |
| 512 | + env->fp_status.float_rounding_mode = T0 & 0x01 ? | |
| 513 | + float_round_to_zero : float_round_nearest_even; | |
| 514 | + | |
| 512 | 515 | RETURN(); |
| 513 | 516 | } |
| 514 | 517 | |
| ... | ... | @@ -705,6 +708,18 @@ void OPPROTO op_fmov_drN_DT0(void) |
| 705 | 708 | RETURN(); |
| 706 | 709 | } |
| 707 | 710 | |
| 711 | +void OPPROTO op_fmov_frN_FT1(void) | |
| 712 | +{ | |
| 713 | + FT1 = *(float32 *)&env->fregs[PARAM1]; | |
| 714 | + RETURN(); | |
| 715 | +} | |
| 716 | + | |
| 717 | +void OPPROTO op_fmov_drN_DT1(void) | |
| 718 | +{ | |
| 719 | + DT1 = *(float64 *)&env->fregs[PARAM1]; | |
| 720 | + RETURN(); | |
| 721 | +} | |
| 722 | + | |
| 708 | 723 | void OPPROTO op_fmov_FT0_frN(void) |
| 709 | 724 | { |
| 710 | 725 | *(float32 *)&env->fregs[PARAM1] = FT0; |
| ... | ... | @@ -717,6 +732,84 @@ void OPPROTO op_fmov_DT0_drN(void) |
| 717 | 732 | RETURN(); |
| 718 | 733 | } |
| 719 | 734 | |
| 735 | +void OPPROTO op_fadd_FT(void) | |
| 736 | +{ | |
| 737 | + FT0 = float32_add(FT0, FT1, &env->fp_status); | |
| 738 | + RETURN(); | |
| 739 | +} | |
| 740 | + | |
| 741 | +void OPPROTO op_fadd_DT(void) | |
| 742 | +{ | |
| 743 | + DT0 = float64_add(DT0, DT1, &env->fp_status); | |
| 744 | + RETURN(); | |
| 745 | +} | |
| 746 | + | |
| 747 | +void OPPROTO op_fsub_FT(void) | |
| 748 | +{ | |
| 749 | + FT0 = float32_sub(FT0, FT1, &env->fp_status); | |
| 750 | + RETURN(); | |
| 751 | +} | |
| 752 | + | |
| 753 | +void OPPROTO op_fsub_DT(void) | |
| 754 | +{ | |
| 755 | + DT0 = float64_sub(DT0, DT1, &env->fp_status); | |
| 756 | + RETURN(); | |
| 757 | +} | |
| 758 | + | |
| 759 | +void OPPROTO op_fmul_FT(void) | |
| 760 | +{ | |
| 761 | + FT0 = float32_mul(FT0, FT1, &env->fp_status); | |
| 762 | + RETURN(); | |
| 763 | +} | |
| 764 | + | |
| 765 | +void OPPROTO op_fmul_DT(void) | |
| 766 | +{ | |
| 767 | + DT0 = float64_mul(DT0, DT1, &env->fp_status); | |
| 768 | + RETURN(); | |
| 769 | +} | |
| 770 | + | |
| 771 | +void OPPROTO op_fdiv_FT(void) | |
| 772 | +{ | |
| 773 | + FT0 = float32_div(FT0, FT1, &env->fp_status); | |
| 774 | + RETURN(); | |
| 775 | +} | |
| 776 | + | |
| 777 | +void OPPROTO op_fdiv_DT(void) | |
| 778 | +{ | |
| 779 | + DT0 = float64_div(DT0, DT1, &env->fp_status); | |
| 780 | + RETURN(); | |
| 781 | +} | |
| 782 | + | |
| 783 | +void OPPROTO op_float_FT(void) | |
| 784 | +{ | |
| 785 | + FT0 = int32_to_float32(env->fpul, &env->fp_status); | |
| 786 | + RETURN(); | |
| 787 | +} | |
| 788 | + | |
| 789 | +void OPPROTO op_float_DT(void) | |
| 790 | +{ | |
| 791 | + DT0 = int32_to_float64(env->fpul, &env->fp_status); | |
| 792 | + RETURN(); | |
| 793 | +} | |
| 794 | + | |
| 795 | +void OPPROTO op_ftrc_FT(void) | |
| 796 | +{ | |
| 797 | + env->fpul = float32_to_int32_round_to_zero(FT0, &env->fp_status); | |
| 798 | + RETURN(); | |
| 799 | +} | |
| 800 | + | |
| 801 | +void OPPROTO op_ftrc_DT(void) | |
| 802 | +{ | |
| 803 | + env->fpul = float64_to_int32_round_to_zero(DT0, &env->fp_status); | |
| 804 | + RETURN(); | |
| 805 | +} | |
| 806 | + | |
| 807 | +void OPPROTO op_fmov_T0_frN(void) | |
| 808 | +{ | |
| 809 | + *(unsigned int *)&env->fregs[PARAM1] = T0; | |
| 810 | + RETURN(); | |
| 811 | +} | |
| 812 | + | |
| 720 | 813 | void OPPROTO op_dec1_rN(void) |
| 721 | 814 | { |
| 722 | 815 | env->gregs[PARAM1] -= 1; | ... | ... |
target-sh4/translate.c
| ... | ... | @@ -131,7 +131,13 @@ void cpu_sh4_reset(CPUSH4State * env) |
| 131 | 131 | #endif |
| 132 | 132 | env->vbr = 0; |
| 133 | 133 | env->pc = 0xA0000000; |
| 134 | - env->fpscr = 0x00040001; | |
| 134 | +#if defined(CONFIG_USER_ONLY) | |
| 135 | + env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */ | |
| 136 | + env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */ | |
| 137 | +#else | |
| 138 | + env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */ | |
| 139 | + env->fp_status.float_rounding_mode = float_round_to_zero; | |
| 140 | +#endif | |
| 135 | 141 | env->mmucr = 0; |
| 136 | 142 | } |
| 137 | 143 | |
| ... | ... | @@ -238,6 +244,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) |
| 238 | 244 | #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) |
| 239 | 245 | #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) |
| 240 | 246 | #define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) |
| 247 | +#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */ | |
| 241 | 248 | |
| 242 | 249 | #define CHECK_NOT_DELAY_SLOT \ |
| 243 | 250 | if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ |
| ... | ... | @@ -768,6 +775,49 @@ void decode_opc(DisasContext * ctx) |
| 768 | 775 | gen_op_stfl_FT0_T1(ctx); |
| 769 | 776 | } |
| 770 | 777 | return; |
| 778 | + case 0xf000: /* fadd Rm,Rn */ | |
| 779 | + case 0xf001: /* fsub Rm,Rn */ | |
| 780 | + case 0xf002: /* fmul Rm,Rn */ | |
| 781 | + case 0xf003: /* fdiv Rm,Rn */ | |
| 782 | + case 0xf004: /* fcmp/eq Rm,Rn */ | |
| 783 | + case 0xf005: /* fcmp/gt Rm,Rn */ | |
| 784 | + if (ctx->fpscr & FPSCR_PR) { | |
| 785 | + if (ctx->opcode & 0x0110) | |
| 786 | + break; /* illegal instruction */ | |
| 787 | + gen_op_fmov_drN_DT1(DREG(B7_4)); | |
| 788 | + gen_op_fmov_drN_DT0(DREG(B11_8)); | |
| 789 | + } | |
| 790 | + else { | |
| 791 | + gen_op_fmov_frN_FT1(FREG(B7_4)); | |
| 792 | + gen_op_fmov_frN_FT0(FREG(B11_8)); | |
| 793 | + } | |
| 794 | + | |
| 795 | + switch (ctx->opcode & 0xf00f) { | |
| 796 | + case 0xf000: /* fadd Rm,Rn */ | |
| 797 | + ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT(); | |
| 798 | + break; | |
| 799 | + case 0xf001: /* fsub Rm,Rn */ | |
| 800 | + ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT(); | |
| 801 | + break; | |
| 802 | + case 0xf002: /* fmul Rm,Rn */ | |
| 803 | + ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT(); | |
| 804 | + break; | |
| 805 | + case 0xf003: /* fdiv Rm,Rn */ | |
| 806 | + ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT(); | |
| 807 | + break; | |
| 808 | + case 0xf004: /* fcmp/eq Rm,Rn */ | |
| 809 | + return; | |
| 810 | + case 0xf005: /* fcmp/gt Rm,Rn */ | |
| 811 | + return; | |
| 812 | + } | |
| 813 | + | |
| 814 | + if (ctx->fpscr & FPSCR_PR) { | |
| 815 | + gen_op_fmov_DT0_drN(DREG(B11_8)); | |
| 816 | + } | |
| 817 | + else { | |
| 818 | + gen_op_fmov_FT0_frN(FREG(B11_8)); | |
| 819 | + } | |
| 820 | + return; | |
| 771 | 821 | } |
| 772 | 822 | |
| 773 | 823 | switch (ctx->opcode & 0xff00) { |
| ... | ... | @@ -1079,6 +1129,44 @@ void decode_opc(DisasContext * ctx) |
| 1079 | 1129 | gen_op_fmov_frN_FT0(FREG(B11_8)); |
| 1080 | 1130 | gen_op_movl_FT0_fpul(); |
| 1081 | 1131 | return; |
| 1132 | + case 0xf02d: /* float FPUL,FRn/DRn */ | |
| 1133 | + if (ctx->fpscr & FPSCR_PR) { | |
| 1134 | + if (ctx->opcode & 0x0100) | |
| 1135 | + break; /* illegal instruction */ | |
| 1136 | + gen_op_float_DT(); | |
| 1137 | + gen_op_fmov_DT0_drN(DREG(B11_8)); | |
| 1138 | + } | |
| 1139 | + else { | |
| 1140 | + gen_op_float_FT(); | |
| 1141 | + gen_op_fmov_FT0_frN(FREG(B11_8)); | |
| 1142 | + } | |
| 1143 | + return; | |
| 1144 | + case 0xf03d: /* ftrc FRm/DRm,FPUL */ | |
| 1145 | + if (ctx->fpscr & FPSCR_PR) { | |
| 1146 | + if (ctx->opcode & 0x0100) | |
| 1147 | + break; /* illegal instruction */ | |
| 1148 | + gen_op_fmov_drN_DT0(DREG(B11_8)); | |
| 1149 | + gen_op_ftrc_DT(); | |
| 1150 | + } | |
| 1151 | + else { | |
| 1152 | + gen_op_fmov_frN_FT0(FREG(B11_8)); | |
| 1153 | + gen_op_ftrc_FT(); | |
| 1154 | + } | |
| 1155 | + return; | |
| 1156 | + case 0xf08d: /* fldi0 FRn */ | |
| 1157 | + if (!(ctx->fpscr & FPSCR_PR)) { | |
| 1158 | + gen_op_movl_imm_T0(0); | |
| 1159 | + gen_op_fmov_T0_frN(FREG(B11_8)); | |
| 1160 | + return; | |
| 1161 | + } | |
| 1162 | + break; | |
| 1163 | + case 0xf09d: /* fldi1 FRn */ | |
| 1164 | + if (!(ctx->fpscr & FPSCR_PR)) { | |
| 1165 | + gen_op_movl_imm_T0(0x3f800000); | |
| 1166 | + gen_op_fmov_T0_frN(FREG(B11_8)); | |
| 1167 | + return; | |
| 1168 | + } | |
| 1169 | + break; | |
| 1082 | 1170 | } |
| 1083 | 1171 | |
| 1084 | 1172 | fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", | ... | ... |