mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-23 14:33:13 -04:00
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:
parent
d17db4cc18
commit
c1dc7cba08
|
@ -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")
|
||||
|
|
|
@ -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
183
device.c
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
4
device.h
4
device.h
|
@ -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
|
||||
|
|
12
options.c
12
options.c
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
477
vr4300/cp1.c
477
vr4300/cp1.c
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue