mirror of
https://github.com/dingusdev/dingusppc.git
synced 2025-01-23 06:31:28 +00:00
Add rounding control for the host FPU.
This commit is contained in:
parent
b59c2be12d
commit
6abb07e61b
@ -402,7 +402,8 @@ extern void ppc_store_result_regd();
|
||||
extern void ppc_store_result_rega();
|
||||
|
||||
void ppc_changecrf0(uint32_t set_result);
|
||||
void ppc_fp_changecrf1();
|
||||
void set_host_rounding_mode(uint8_t mode);
|
||||
void update_fpscr(uint32_t new_fpscr);
|
||||
|
||||
/* Exception handlers. */
|
||||
void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits);
|
||||
|
@ -751,6 +751,17 @@ void initialize_ppc_opcode_tables() {
|
||||
}
|
||||
}
|
||||
|
||||
void ppc_fpu_init() {
|
||||
// zero all FPRs as prescribed for MPC601
|
||||
// For later PPC CPUs, GPR content is undefined
|
||||
for (int i = 0; i < 32; i++) {
|
||||
ppc_state.fpr[i].int64_r = 0;
|
||||
}
|
||||
|
||||
ppc_state.fpscr = 0;
|
||||
set_host_rounding_mode(0);
|
||||
}
|
||||
|
||||
void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||
{
|
||||
int i;
|
||||
@ -783,12 +794,6 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||
ppc_state.gpr[i] = 0;
|
||||
}
|
||||
|
||||
/* zero all FPRs as prescribed for MPC601 */
|
||||
/* For later PPC CPUs, GPR content is undefined */
|
||||
for (i = 0; i < 32; i++) {
|
||||
ppc_state.fpr[i].int64_r = 0;
|
||||
}
|
||||
|
||||
/* zero all segment registers as prescribed for MPC601 */
|
||||
/* For later PPC CPUs, SR content is undefined */
|
||||
for (i = 0; i < 16; i++) {
|
||||
@ -796,7 +801,8 @@ void ppc_cpu_init(MemCtrlBase* mem_ctrl, uint32_t cpu_version, uint64_t tb_freq)
|
||||
}
|
||||
|
||||
ppc_state.cr = 0;
|
||||
ppc_state.fpscr = 0;
|
||||
|
||||
ppc_fpu_init();
|
||||
|
||||
ppc_state.pc = 0;
|
||||
|
||||
|
@ -24,6 +24,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#include "ppcemu.h"
|
||||
#include "ppcmmu.h"
|
||||
#include <stdlib.h>
|
||||
#include <cfenv>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
@ -134,6 +135,30 @@ int64_t round_to_nearest(double f) {
|
||||
}
|
||||
}
|
||||
|
||||
void set_host_rounding_mode(uint8_t mode) {
|
||||
switch(mode & FPSCR::RN_MASK) {
|
||||
case 0:
|
||||
std::fesetround(FE_TONEAREST);
|
||||
break;
|
||||
case 1:
|
||||
std::fesetround(FE_TOWARDZERO);
|
||||
break;
|
||||
case 2:
|
||||
std::fesetround(FE_UPWARD);
|
||||
break;
|
||||
case 3:
|
||||
std::fesetround(FE_DOWNWARD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void update_fpscr(uint32_t new_fpscr) {
|
||||
if ((new_fpscr & FPSCR::RN_MASK) != (ppc_state.fpscr & FPSCR::RN_MASK))
|
||||
set_host_rounding_mode(new_fpscr & FPSCR::RN_MASK);
|
||||
|
||||
ppc_state.fpscr = new_fpscr;
|
||||
}
|
||||
|
||||
int64_t round_to_zero(double f) {
|
||||
return static_cast<int32_t>(std::trunc(f));
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "../ppcdisasm.h"
|
||||
#include "../ppcemu.h"
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
@ -186,7 +187,7 @@ static void read_test_float_data() {
|
||||
lineno++;
|
||||
|
||||
if (line.empty() || !line.rfind("#", 0))
|
||||
continue; /* skip empty/comment lines */
|
||||
continue; // skip empty/comment lines
|
||||
|
||||
istringstream lnstream(line);
|
||||
|
||||
@ -208,16 +209,15 @@ static void read_test_float_data() {
|
||||
check_xer = 0;
|
||||
check_cr = 0;
|
||||
check_fpscr = 0;
|
||||
//sfp_dest = 0.0;
|
||||
//sfp_src1 = 0.0;
|
||||
//sfp_src2 = 0.0;
|
||||
//sfp_src3 = 0.0;
|
||||
dfp_dest = 0.0;
|
||||
dfp_src1 = 0.0;
|
||||
dfp_src2 = 0.0;
|
||||
dfp_src3 = 0.0;
|
||||
dest_64 = 0;
|
||||
|
||||
// switch to default rounding
|
||||
fesetround(FE_TONEAREST);
|
||||
|
||||
for (i = 2; i < tokens.size(); i++) {
|
||||
if (tokens[i].rfind("frD=", 0) == 0) {
|
||||
dest_64 = stoull(tokens[i].substr(4), NULL, 16);
|
||||
@ -229,22 +229,6 @@ static void read_test_float_data() {
|
||||
dfp_src3 = stod(tokens[i].substr(4), NULL);
|
||||
} else if (tokens[i].rfind("round=", 0) == 0) {
|
||||
rounding_mode = tokens[i].substr(6, 3);
|
||||
ppc_state.fpscr = 0;
|
||||
if (rounding_mode.compare("RTN") == 0) {
|
||||
ppc_state.fpscr = 0x0;
|
||||
} else if (rounding_mode.compare("RTZ") == 0) {
|
||||
ppc_state.fpscr = 0x1;
|
||||
} else if (rounding_mode.compare("RPI") == 0) {
|
||||
ppc_state.fpscr = 0x2;
|
||||
} else if (rounding_mode.compare("RNI") == 0) {
|
||||
ppc_state.fpscr = 0x3;
|
||||
} else if (rounding_mode.compare("VEN") == 0) {
|
||||
ppc_state.fpscr = FPSCR::VE;
|
||||
} else {
|
||||
cout << "ILLEGAL ROUNDING METHOD: " << tokens[i] << " in line " << lineno
|
||||
<< ". Exiting..." << endl;
|
||||
exit(0);
|
||||
}
|
||||
} else if (tokens[i].rfind("FPSCR=", 0) == 0) {
|
||||
check_fpscr = stoul(tokens[i].substr(6), NULL, 16);
|
||||
} else if (tokens[i].rfind("CR=", 0) == 0) {
|
||||
@ -256,6 +240,22 @@ static void read_test_float_data() {
|
||||
}
|
||||
}
|
||||
|
||||
if (rounding_mode.compare("RTN") == 0) {
|
||||
update_fpscr(0);
|
||||
} else if (rounding_mode.compare("RTZ") == 0) {
|
||||
update_fpscr(1);
|
||||
} else if (rounding_mode.compare("RPI") == 0) {
|
||||
update_fpscr(2);
|
||||
} else if (rounding_mode.compare("RNI") == 0) {
|
||||
update_fpscr(3);
|
||||
} else if (rounding_mode.compare("VEN") == 0) {
|
||||
update_fpscr(FPSCR::VE);
|
||||
} else {
|
||||
cout << "ILLEGAL ROUNDING METHOD: " << tokens[i] << " in line " << lineno
|
||||
<< ". Exiting..." << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ppc_state.gpr[3] = src1;
|
||||
ppc_state.gpr[4] = src2;
|
||||
|
||||
@ -263,7 +263,7 @@ static void read_test_float_data() {
|
||||
ppc_state.fpr[4].dbl64_r = dfp_src2;
|
||||
ppc_state.fpr[5].dbl64_r = dfp_src3;
|
||||
|
||||
ppc_state.cr = 0;
|
||||
ppc_state.cr = 0;
|
||||
|
||||
ppc_cur_instruction = opcode;
|
||||
|
||||
@ -271,6 +271,9 @@ static void read_test_float_data() {
|
||||
|
||||
ntested++;
|
||||
|
||||
// switch to default rounding
|
||||
fesetround(FE_TONEAREST);
|
||||
|
||||
if ((tokens[0].rfind("FCMP") && (ppc_state.fpr[3].int64_r != dest_64)) ||
|
||||
(ppc_state.fpscr != check_fpscr) ||
|
||||
(ppc_state.cr != check_cr)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user