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,6 +99,7 @@ typedef struct CPUSH4State { | ||
| 99 | /* temporary float registers */ | 99 | /* temporary float registers */ |
| 100 | float32 ft0, ft1; | 100 | float32 ft0, ft1; |
| 101 | float64 dt0, dt1; | 101 | float64 dt0, dt1; |
| 102 | + float_status fp_status; | ||
| 102 | 103 | ||
| 103 | /* Those belong to the specific unit (SH7750) but are handled here */ | 104 | /* Those belong to the specific unit (SH7750) but are handled here */ |
| 104 | uint32_t mmucr; /* MMU control register */ | 105 | uint32_t mmucr; /* MMU control register */ |
target-sh4/op.c
| @@ -509,6 +509,9 @@ void OPPROTO op_##store##_##target##_T0 (void) \ | @@ -509,6 +509,9 @@ void OPPROTO op_##store##_##target##_T0 (void) \ | ||
| 509 | void OPPROTO op_lds_T0_fpscr(void) | 509 | void OPPROTO op_lds_T0_fpscr(void) |
| 510 | { | 510 | { |
| 511 | env->fpscr = T0 & 0x003fffff; | 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 | RETURN(); | 515 | RETURN(); |
| 513 | } | 516 | } |
| 514 | 517 | ||
| @@ -705,6 +708,18 @@ void OPPROTO op_fmov_drN_DT0(void) | @@ -705,6 +708,18 @@ void OPPROTO op_fmov_drN_DT0(void) | ||
| 705 | RETURN(); | 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 | void OPPROTO op_fmov_FT0_frN(void) | 723 | void OPPROTO op_fmov_FT0_frN(void) |
| 709 | { | 724 | { |
| 710 | *(float32 *)&env->fregs[PARAM1] = FT0; | 725 | *(float32 *)&env->fregs[PARAM1] = FT0; |
| @@ -717,6 +732,84 @@ void OPPROTO op_fmov_DT0_drN(void) | @@ -717,6 +732,84 @@ void OPPROTO op_fmov_DT0_drN(void) | ||
| 717 | RETURN(); | 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 | void OPPROTO op_dec1_rN(void) | 813 | void OPPROTO op_dec1_rN(void) |
| 721 | { | 814 | { |
| 722 | env->gregs[PARAM1] -= 1; | 815 | env->gregs[PARAM1] -= 1; |
target-sh4/translate.c
| @@ -131,7 +131,13 @@ void cpu_sh4_reset(CPUSH4State * env) | @@ -131,7 +131,13 @@ void cpu_sh4_reset(CPUSH4State * env) | ||
| 131 | #endif | 131 | #endif |
| 132 | env->vbr = 0; | 132 | env->vbr = 0; |
| 133 | env->pc = 0xA0000000; | 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 | env->mmucr = 0; | 141 | env->mmucr = 0; |
| 136 | } | 142 | } |
| 137 | 143 | ||
| @@ -238,6 +244,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) | @@ -238,6 +244,7 @@ static void gen_delayed_conditional_jump(DisasContext * ctx) | ||
| 238 | #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) | 244 | #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x)) |
| 239 | #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) | 245 | #define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe)) |
| 240 | #define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x)) | 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 | #define CHECK_NOT_DELAY_SLOT \ | 249 | #define CHECK_NOT_DELAY_SLOT \ |
| 243 | if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ | 250 | if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ |
| @@ -768,6 +775,49 @@ void decode_opc(DisasContext * ctx) | @@ -768,6 +775,49 @@ void decode_opc(DisasContext * ctx) | ||
| 768 | gen_op_stfl_FT0_T1(ctx); | 775 | gen_op_stfl_FT0_T1(ctx); |
| 769 | } | 776 | } |
| 770 | return; | 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 | switch (ctx->opcode & 0xff00) { | 823 | switch (ctx->opcode & 0xff00) { |
| @@ -1079,6 +1129,44 @@ void decode_opc(DisasContext * ctx) | @@ -1079,6 +1129,44 @@ void decode_opc(DisasContext * ctx) | ||
| 1079 | gen_op_fmov_frN_FT0(FREG(B11_8)); | 1129 | gen_op_fmov_frN_FT0(FREG(B11_8)); |
| 1080 | gen_op_movl_FT0_fpul(); | 1130 | gen_op_movl_FT0_fpul(); |
| 1081 | return; | 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 | fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", | 1172 | fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n", |