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", | ... | ... |