Refactor for another major performance boost.

Since the CEN64 core now runs in it's own thread (and doesn't use
the FPU), we can steal the host's FPU state register and not have
to worry about preserving it.

Along with that major overhaul, don't force "extra" features like
simulation statistics and debugging if the user doesn't want them.
Including that code, even when it is not run, mucks with register
allocation or something ever so slightly.
This commit is contained in:
Tyler Stachecki 2014-11-15 18:13:00 -05:00
parent d17db4cc18
commit c1dc7cba08
13 changed files with 197 additions and 606 deletions

View file

@ -12,6 +12,9 @@ project(cen64)
find_package(OpenGL REQUIRED)
find_package(Threads REQUIRED)
# Ask if we should build with extra features (debugger, statistics, etc.).
option(CEN64_EXTRAFEATURES "Build CEN64 with features for developers/debuggers." OFF)
# If using GCC, configure it accordingly.
if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99")

View file

@ -166,6 +166,7 @@ void cen64_return(struct bus_controller *bus)
#define debug_mmio_write(what, mnemonic, val, dqm) do {} while (0)
#endif
#cmakedefine CEN64_EXTRAFEATURES
#cmakedefine VR4300_BUSY_WAIT_DETECTION
#include "common/debug.h"

183
device.c
View file

@ -14,6 +14,7 @@
#include <stdlib.h>
#include "common.h"
#include "device.h"
#include "fpu/fpu.h"
#include "os/rom_file.h"
#include "bus/controller.h"
@ -24,6 +25,7 @@
#include "rsp/cpu.h"
#include "vi/controller.h"
#include "vr4300/cpu.h"
#include "vr4300/cp1.h"
// Only used when passed -nointerface.
bool device_exit_requested;
@ -37,8 +39,12 @@ cen64_cold static void device_destroy(struct cen64_device *device);
cen64_cold static struct cen64_device *device_create(struct cen64_device *device,
uint8_t *ram, const struct rom_file *pifrom, const struct rom_file *cart);
static int device_runmode_fast(struct cen64_device *device);
static int device_runmode_extra(struct cen64_device *device);
#ifdef CEN64_EXTRAFEATURES
cen64_hot static int device_spin_extra(struct cen64_device *device,
fpu_state_t *saved_fpu_state, struct vr4300_stats *vr4300_stats);
#else
cen64_hot static int device_spin_fast(struct cen64_device *device);
#endif
// Creates and initializes a device.
struct cen64_device *device_create(struct cen64_device *device,
@ -123,90 +129,6 @@ void device_request_exit(struct bus_controller *bus) {
longjmp(bus->unwind_data, 1);
}
// Kicks off threads and starts the device.
static int device_runmode_fast(struct cen64_device *device) {
rsp_vect_t acc_lo, acc_md, acc_hi;
struct rsp *rsp = &device->rsp;
unsigned i;
// Preserve host registers pinned to RSP accumulators.
// On many hosts, these will have no real effect.
acc_lo = read_acc_lo(rsp->cp2.acc);
acc_md = read_acc_md(rsp->cp2.acc);
acc_hi = read_acc_hi(rsp->cp2.acc);
write_acc_lo(rsp->cp2.acc, rsp_vzero());
write_acc_md(rsp->cp2.acc, rsp_vzero());
write_acc_hi(rsp->cp2.acc, rsp_vzero());
if (setjmp(device->bus.unwind_data)) {
write_acc_lo(rsp->cp2.acc, acc_lo);
write_acc_md(rsp->cp2.acc, acc_md);
write_acc_hi(rsp->cp2.acc, acc_hi);
return 0;
}
while (1) {
for (i = 0; i < 2; i++) {
vi_cycle(&device->vi);
rsp_cycle(rsp);
vr4300_cycle(&device->vr4300);
}
vr4300_cycle(&device->vr4300);
}
return 0;
}
// Kicks off threads and starts the device.
static int device_runmode_extra(struct cen64_device *device) {
rsp_vect_t acc_lo, acc_md, acc_hi;
struct rsp *rsp = &device->rsp;
struct vr4300_stats vr4300_stats;
unsigned i;
memset(&vr4300_stats, 0, sizeof(vr4300_stats));
// Preserve host registers pinned to RSP accumulators.
// On many hosts, these will have no real effect.
acc_lo = read_acc_lo(rsp->cp2.acc);
acc_md = read_acc_md(rsp->cp2.acc);
acc_hi = read_acc_hi(rsp->cp2.acc);
write_acc_lo(rsp->cp2.acc, rsp_vzero());
write_acc_md(rsp->cp2.acc, rsp_vzero());
write_acc_hi(rsp->cp2.acc, rsp_vzero());
if (setjmp(device->bus.unwind_data)) {
write_acc_lo(rsp->cp2.acc, acc_lo);
write_acc_md(rsp->cp2.acc, acc_md);
write_acc_hi(rsp->cp2.acc, acc_hi);
vr4300_print_summary(&vr4300_stats);
return 0;
}
while (1) {
for (i = 0; i < 2; i++) {
vi_cycle(&device->vi);
rsp_cycle(rsp);
vr4300_cycle(&device->vr4300);
vr4300_cycle_extra(&device->vr4300, &vr4300_stats);
}
vr4300_cycle(&device->vr4300);
vr4300_cycle_extra(&device->vr4300, &vr4300_stats);
}
return 0;
}
// Create a device and proceed to the main loop.
int device_run(struct cen64_device *device, struct cen64_options *options,
uint8_t *ram, const struct rom_file *pifrom, const struct rom_file *cart) {
@ -218,9 +140,41 @@ int device_run(struct cen64_device *device, struct cen64_options *options,
// Memory is already allocated; just spawn the device.
else if (device_create(device, ram, pifrom, cart) != NULL) {
status = unlikely(options->extra_mode)
? device_runmode_extra(device)
: device_runmode_fast(device);
rsp_vect_t acc_lo, acc_md, acc_hi;
fpu_state_t saved_fpu_state;
struct vr4300_stats vr4300_stats;
memset(&vr4300_stats, 0, sizeof(vr4300_stats));
// Preserve host registers pinned to the device.
acc_lo = read_acc_lo(device->rsp.cp2.acc);
acc_md = read_acc_md(device->rsp.cp2.acc);
acc_hi = read_acc_hi(device->rsp.cp2.acc);
saved_fpu_state = fpu_get_state();
write_acc_lo(device->rsp.cp2.acc, rsp_vzero());
write_acc_md(device->rsp.cp2.acc, rsp_vzero());
write_acc_hi(device->rsp.cp2.acc, rsp_vzero());
vr4300_cp1_init(&device->vr4300);
// Spin the device until we return (from setjmp).
#ifdef CEN64_EXTRAFEATURES
device_spin_extra(device, &saved_fpu_state, &vr4300_stats);
#else
device_spin_fast(device);
#endif
// Restore host registers pinned to the device.
write_acc_lo(device->rsp.cp2.acc, acc_lo);
write_acc_md(device->rsp.cp2.acc, acc_md);
write_acc_hi(device->rsp.cp2.acc, acc_hi);
fpu_set_state(saved_fpu_state);
// Finalize simulation, release memory, etc.
#ifdef CEN64_EXTRAFEATURES
if (options->print_sim_stats)
vr4300_print_summary(&vr4300_stats);
#endif
device_destroy(device);
}
@ -228,3 +182,54 @@ int device_run(struct cen64_device *device, struct cen64_options *options,
return status;
}
// Continually cycles the device until setjmp returns.
#ifdef CEN64_EXTRAFEATURES
int device_spin_extra(struct cen64_device *device,
fpu_state_t *saved_fpu_state, struct vr4300_stats *vr4300_stats) {
if (setjmp(device->bus.unwind_data))
return 1;
while (1) {
unsigned i;
for (i = 0; i < 2; i++) {
vi_cycle(&device->vi);
rsp_cycle(&device->rsp);
vr4300_cycle(&device->vr4300);
// Perform additional simulation tasks NOW.
// Make sure to preserve the FPU state.
vr4300_cycle_extra(&device->vr4300, vr4300_stats);
}
vr4300_cycle(&device->vr4300);
// Perform additional simulation tasks NOW.
// Make sure to preserve the FPU state.
vr4300_cycle_extra(&device->vr4300, vr4300_stats);
}
}
#endif
// Continually cycles the device until setjmp returns.
int device_spin_fast(struct cen64_device *device) {
if (setjmp(device->bus.unwind_data))
return 1;
while (1) {
unsigned i;
for (i = 0; i < 2; i++) {
vi_cycle(&device->vi);
rsp_cycle(&device->rsp);
vr4300_cycle(&device->vr4300);
}
vr4300_cycle(&device->vr4300);
}
return 0;
}

View file

@ -31,7 +31,6 @@ extern bool device_exit_requested;
struct cen64_device {
struct bus_controller bus;
uint8_t padding_bus[32];
struct vr4300 vr4300;
struct ai_controller ai;
@ -46,8 +45,7 @@ struct cen64_device {
};
cen64_cold void device_request_exit(struct bus_controller *bus);
cen64_hot int device_run(struct cen64_device *device, struct cen64_options *options,
cen64_cold int device_run(struct cen64_device *device, struct cen64_options *options,
uint8_t *ram, const struct rom_file *pifrom, const struct rom_file *cart);
#endif

View file

@ -17,8 +17,8 @@ const struct cen64_options default_cen64_options = {
#ifdef _WIN32
false, // console
#endif
false, // extra_mode
false, // no_interface
false, // print_sim_stats
};
// Parses the passed command line arguments.
@ -37,8 +37,10 @@ int parse_options(struct cen64_options *options, int argc, const char *argv[]) {
if (!strcmp(argv[i], "-nointerface"))
options->no_interface = true;
#ifdef CEN64_EXTRAFEATURES
else if (!strcmp(argv[i], "-printsimstats"))
options->extra_mode = true;
options->print_sim_stats = true;
#endif
else
return 1;
@ -58,9 +60,11 @@ void print_command_line_usage(const char *invokation_string) {
" -console : Creates/shows the system console.\n"
#endif
" -nointerface : Run simulator without a user interface.\n"
" -printsimstats : Print simulation statistics at exit.\n",
#ifdef CEN64_EXTRAFEATURES
" -printsimstats : Print simulation statistics at exit.\n"
#endif
invokation_string
,invokation_string
);
}

View file

@ -19,8 +19,9 @@ struct cen64_options {
#ifdef _WIN32
bool console;
#endif
bool extra_mode;
bool no_interface;
bool print_sim_stats;
};
extern const struct cen64_options default_cen64_options;

View file

@ -51,7 +51,7 @@ extern const char *sp_register_mnemonics[NUM_SP_REGISTERS];
struct rsp {
struct rsp_pipeline pipeline;
uint32_t pad[3];
uint32_t pad[1];
struct rsp_cp2 cp2;
uint32_t regs[NUM_RSP_REGISTERS * 2];
@ -67,7 +67,7 @@ struct rsp {
cen64_cold int rsp_init(struct rsp *rsp, struct bus_controller *bus);
cen64_cold void rsp_destroy(struct rsp *rsp);
void rsp_cycle(struct rsp *rsp);
cen64_hot void rsp_cycle(struct rsp *rsp);
#endif

File diff suppressed because it is too large Load diff

View file

@ -16,8 +16,6 @@
struct vr4300;
struct vr4300_cp1 {
fpu_state_t native_state;
fpu_state_t native_enables;
};
int VR4300_BC1(struct vr4300 *vr4300, uint32_t iw, uint64_t fs, uint64_t ft);

View file

@ -120,8 +120,8 @@ struct vr4300_stats {
cen64_cold int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus);
cen64_cold void vr4300_print_summary(struct vr4300_stats *stats);
void vr4300_cycle(struct vr4300 *vr4300);
cen64_cold void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *stats);
cen64_hot void vr4300_cycle(struct vr4300 *vr4300);
cen64_hot void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *stats);
#endif

View file

@ -23,6 +23,7 @@
#define GET_FMT(iw) ((iw) >> 21 & 0x1F)
#define OPCODE_INFO_NONE (0)
#define OPCODE_INFO_FPU (1U << 2)
#define OPCODE_INFO_BRANCH (1U << 31)
#define OPCODE_INFO_NEEDRS (1U << 3)
#define OPCODE_INFO_NEEDFS ((1U << 3) | (1U << 0))

View file

@ -159,54 +159,54 @@
#define TLBWI VR4300_BUILD_OP(TLBWI, TLBWI, INFO1(NONE))
#define TLBWR VR4300_BUILD_OP(TLBWR, INVALID, INFO1(NONE))
#define BC1 VR4300_BUILD_OP(BC1, BC1, INFO1(BRANCH))
#define CFC1 VR4300_BUILD_OP(CFC1, CFC1, INFO1(NONE))
#define CTC1 VR4300_BUILD_OP(CTC1, CTC1, INFO1(NONE))
#define DMFC1 VR4300_BUILD_OP(DMFC1, DMFC1, INFO1(NEEDFS))
#define DMTC1 VR4300_BUILD_OP(DMTC1, DMTC1, INFO1(NEEDRT))
#define LDC1 VR4300_BUILD_OP(LDC1, LDC1, INFO1(NEEDRS))
#define LWC1 VR4300_BUILD_OP(LWC1, LWC1, INFO2(NEEDRS, NEEDFT))
#define MFC1 VR4300_BUILD_OP(MFC1, MFC1, INFO1(NEEDFS))
#define MTC1 VR4300_BUILD_OP(MTC1, MTC1, INFO2(NEEDFS, NEEDRT))
#define SDC1 VR4300_BUILD_OP(SDC1, SDC1, INFO2(NEEDRS, NEEDFT))
#define SWC1 VR4300_BUILD_OP(SWC1, SWC1, INFO2(NEEDRS, NEEDFT))
#define BC1 VR4300_BUILD_OP(BC1, BC1, INFO2(FPU, BRANCH))
#define CFC1 VR4300_BUILD_OP(CFC1, CFC1, INFO2(FPU, NONE))
#define CTC1 VR4300_BUILD_OP(CTC1, CTC1, INFO2(FPU, NONE))
#define DMFC1 VR4300_BUILD_OP(DMFC1, DMFC1, INFO2(FPU, NEEDFS))
#define DMTC1 VR4300_BUILD_OP(DMTC1, DMTC1, INFO2(FPU, NEEDRT))
#define LDC1 VR4300_BUILD_OP(LDC1, LDC1, INFO2(FPU, NEEDRS))
#define LWC1 VR4300_BUILD_OP(LWC1, LWC1, INFO3(FPU, NEEDRS, NEEDFT))
#define MFC1 VR4300_BUILD_OP(MFC1, MFC1, INFO2(FPU, NEEDFS))
#define MTC1 VR4300_BUILD_OP(MTC1, MTC1, INFO3(FPU, NEEDFS, NEEDRT))
#define SDC1 VR4300_BUILD_OP(SDC1, SDC1, INFO3(FPU, NEEDRS, NEEDFT))
#define SWC1 VR4300_BUILD_OP(SWC1, SWC1, INFO3(FPU, NEEDRS, NEEDFT))
#define CP1_ABS VR4300_BUILD_OP(CP1_ABS, CP1_ABS, INFO1(NEEDFS))
#define CP1_ADD VR4300_BUILD_OP(CP1_ADD, CP1_ADD, INFO2(NEEDFS, NEEDFT))
#define CP1_C_EQ VR4300_BUILD_OP(CP1_C_EQ, CP1_C_EQ_C_SEQ, INFO2(NEEDFS, NEEDFT))
#define CP1_C_F VR4300_BUILD_OP(CP1_C_F, CP1_C_F_C_SF, INFO2(NEEDFS, NEEDFT))
#define CP1_C_LE VR4300_BUILD_OP(CP1_C_LE, CP1_C_OLE_C_LE, INFO2(NEEDFS, NEEDFT))
#define CP1_C_LT VR4300_BUILD_OP(CP1_C_LT, CP1_C_OLT_C_LT, INFO2(NEEDFS, NEEDFT))
#define CP1_C_NGE VR4300_BUILD_OP(CP1_C_NGE, CP1_C_ULT_C_NGE, INFO2(NEEDFS, NEEDFT))
#define CP1_C_NGL VR4300_BUILD_OP(CP1_C_NGL, CP1_C_UEQ_C_NGL, INFO2(NEEDFS, NEEDFT))
#define CP1_C_NGLE VR4300_BUILD_OP(CP1_C_NGLE, CP1_C_UN_C_NGLE, INFO2(NEEDFS, NEEDFT))
#define CP1_C_NGT VR4300_BUILD_OP(CP1_C_NGT, CP1_C_ULE_C_NGT, INFO2(NEEDFS, NEEDFT))
#define CP1_C_OLE VR4300_BUILD_OP(CP1_C_OLE, CP1_C_OLE_C_LE, INFO2(NEEDFS, NEEDFT))
#define CP1_C_OLT VR4300_BUILD_OP(CP1_C_OLT, CP1_C_OLT_C_LT, INFO2(NEEDFS, NEEDFT))
#define CP1_C_SEQ VR4300_BUILD_OP(CP1_C_SEQ, CP1_C_EQ_C_SEQ, INFO2(NEEDFS, NEEDFT))
#define CP1_C_SF VR4300_BUILD_OP(CP1_C_SF, CP1_C_F_C_SF, INFO2(NEEDFS, NEEDFT))
#define CP1_C_UEQ VR4300_BUILD_OP(CP1_C_UEQ, CP1_C_UEQ_C_NGL, INFO2(NEEDFS, NEEDFT))
#define CP1_C_ULE VR4300_BUILD_OP(CP1_C_ULE, CP1_C_ULE_C_NGT, INFO2(NEEDFS, NEEDFT))
#define CP1_C_ULT VR4300_BUILD_OP(CP1_C_ULT, CP1_C_ULT_C_NGE, INFO2(NEEDFS, NEEDFT))
#define CP1_C_UN VR4300_BUILD_OP(CP1_C_UN, CP1_C_UN_C_NGLE, INFO2(NEEDFS, NEEDFT))
#define CP1_CEIL_L VR4300_BUILD_OP(CP1_CEIL_L, CP1_CEIL_L, INFO1(NEEDFS))
#define CP1_CEIL_W VR4300_BUILD_OP(CP1_CEIL_W, CP1_CEIL_W, INFO1(NEEDFS))
#define CP1_CVT_D VR4300_BUILD_OP(CP1_CVT_D, CP1_CVT_D, INFO1(NEEDFS))
#define CP1_CVT_L VR4300_BUILD_OP(CP1_CVT_L, CP1_CVT_L, INFO1(NEEDFS))
#define CP1_CVT_S VR4300_BUILD_OP(CP1_CVT_S, CP1_CVT_S, INFO1(NEEDFS))
#define CP1_CVT_W VR4300_BUILD_OP(CP1_CVT_W, CP1_CVT_W, INFO1(NEEDFS))
#define CP1_DIV VR4300_BUILD_OP(CP1_DIV, CP1_DIV, INFO2(NEEDFS, NEEDFT))
#define CP1_FLOOR_L VR4300_BUILD_OP(CP1_FLOOR_L, CP1_FLOOR_L, INFO1(NEEDFS))
#define CP1_FLOOR_W VR4300_BUILD_OP(CP1_FLOOR_W, CP1_FLOOR_W, INFO1(NEEDFS))
#define CP1_MOV VR4300_BUILD_OP(CP1_MOV, CP1_MOV, INFO1(NEEDFS))
#define CP1_MUL VR4300_BUILD_OP(CP1_MUL, CP1_MUL, INFO2(NEEDFS, NEEDFT))
#define CP1_NEG VR4300_BUILD_OP(CP1_NEG, CP1_NEG, INFO1(NEEDFS))
#define CP1_ROUND_L VR4300_BUILD_OP(CP1_ROUND_L, CP1_ROUND_L, INFO1(NEEDFS))
#define CP1_ROUND_W VR4300_BUILD_OP(CP1_ROUND_W, CP1_ROUND_W, INFO1(NEEDFS))
#define CP1_SQRT VR4300_BUILD_OP(CP1_SQRT, CP1_SQRT, INFO1(NEEDFS))
#define CP1_SUB VR4300_BUILD_OP(CP1_SUB, CP1_SUB, INFO2(NEEDFS, NEEDFT))
#define CP1_TRUNC_L VR4300_BUILD_OP(CP1_TRUNC_L, CP1_TRUNC_L, INFO1(NEEDFS))
#define CP1_TRUNC_W VR4300_BUILD_OP(CP1_TRUNC_W, CP1_TRUNC_W, INFO1(NEEDFS))
#define CP1_ABS VR4300_BUILD_OP(CP1_ABS, CP1_ABS, INFO3(FPU, FPU, NEEDFS))
#define CP1_ADD VR4300_BUILD_OP(CP1_ADD, CP1_ADD, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_EQ VR4300_BUILD_OP(CP1_C_EQ, CP1_C_EQ_C_SEQ, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_F VR4300_BUILD_OP(CP1_C_F, CP1_C_F_C_SF, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_LE VR4300_BUILD_OP(CP1_C_LE, CP1_C_OLE_C_LE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_LT VR4300_BUILD_OP(CP1_C_LT, CP1_C_OLT_C_LT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGE VR4300_BUILD_OP(CP1_C_NGE, CP1_C_ULT_C_NGE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGL VR4300_BUILD_OP(CP1_C_NGL, CP1_C_UEQ_C_NGL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGLE VR4300_BUILD_OP(CP1_C_NGLE, CP1_C_UN_C_NGLE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGT VR4300_BUILD_OP(CP1_C_NGT, CP1_C_ULE_C_NGT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_OLE VR4300_BUILD_OP(CP1_C_OLE, CP1_C_OLE_C_LE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_OLT VR4300_BUILD_OP(CP1_C_OLT, CP1_C_OLT_C_LT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_SEQ VR4300_BUILD_OP(CP1_C_SEQ, CP1_C_EQ_C_SEQ, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_SF VR4300_BUILD_OP(CP1_C_SF, CP1_C_F_C_SF, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_UEQ VR4300_BUILD_OP(CP1_C_UEQ, CP1_C_UEQ_C_NGL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_ULE VR4300_BUILD_OP(CP1_C_ULE, CP1_C_ULE_C_NGT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_ULT VR4300_BUILD_OP(CP1_C_ULT, CP1_C_ULT_C_NGE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_UN VR4300_BUILD_OP(CP1_C_UN, CP1_C_UN_C_NGLE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_CEIL_L VR4300_BUILD_OP(CP1_CEIL_L, CP1_CEIL_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_CEIL_W VR4300_BUILD_OP(CP1_CEIL_W, CP1_CEIL_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_D VR4300_BUILD_OP(CP1_CVT_D, CP1_CVT_D, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_L VR4300_BUILD_OP(CP1_CVT_L, CP1_CVT_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_S VR4300_BUILD_OP(CP1_CVT_S, CP1_CVT_S, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_W VR4300_BUILD_OP(CP1_CVT_W, CP1_CVT_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_DIV VR4300_BUILD_OP(CP1_DIV, CP1_DIV, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_FLOOR_L VR4300_BUILD_OP(CP1_FLOOR_L, CP1_FLOOR_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_FLOOR_W VR4300_BUILD_OP(CP1_FLOOR_W, CP1_FLOOR_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_MOV VR4300_BUILD_OP(CP1_MOV, CP1_MOV, INFO3(FPU, FPU, NEEDFS))
#define CP1_MUL VR4300_BUILD_OP(CP1_MUL, CP1_MUL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_NEG VR4300_BUILD_OP(CP1_NEG, CP1_NEG, INFO3(FPU, FPU, NEEDFS))
#define CP1_ROUND_L VR4300_BUILD_OP(CP1_ROUND_L, CP1_ROUND_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_ROUND_W VR4300_BUILD_OP(CP1_ROUND_W, CP1_ROUND_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_SQRT VR4300_BUILD_OP(CP1_SQRT, CP1_SQRT, INFO3(FPU, FPU, NEEDFS))
#define CP1_SUB VR4300_BUILD_OP(CP1_SUB, CP1_SUB, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_TRUNC_L VR4300_BUILD_OP(CP1_TRUNC_L, CP1_TRUNC_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_TRUNC_W VR4300_BUILD_OP(CP1_TRUNC_W, CP1_TRUNC_W, INFO3(FPU, FPU, NEEDFS))
#define BC2 VR4300_BUILD_OP(BC1, INVALID, INFO1(BRANCH))
#define CFC2 VR4300_BUILD_OP(CFC2, INVALID, INFO1(NONE))

View file

@ -140,11 +140,18 @@ static inline int vr4300_ex_stage(struct vr4300 *vr4300) {
rs = GET_RS(iw);
rt = GET_RT(iw);
// Check if one of the sources is an FPU register. Furthermore,
// if Status.FR bit is clear, we depend on even registers only.
if (flags & 0x3) {
unsigned fr = (status >> 26 & 0x1) ^ 1;
if (flags & OPCODE_INFO_FPU) {
unsigned fr;
// Dealing with FPU state, is CP1 usable?
if (!(status & 0x20000000U)) {
VR4300_CPU(vr4300);
return 1;
}
// Check if one of the sources is an FPU register. Furthermore,
// if Status.FR bit is clear, we depend on even registers only.
fr = (status >> 26 & 0x1) ^ 1;
rslutidx = flags & 0x1;
rtlutidx = flags & 0x2;