mirror of
https://github.com/n64dev/cen64.git
synced 2024-06-22 22:12:45 -04:00
Add a -printsimstats switch.
Start working in a "extra" mode for debugging and other features that we don't want on the main path. As a demonstration of what we can do with this extra mode, print out a bunch of simulation info that can help us optimize offline.
This commit is contained in:
parent
4ec470fed7
commit
d45cab877a
27
cen64.c
27
cen64.c
|
@ -17,7 +17,7 @@ static int load_roms(const char *pifrom_path, const char *cart_path,
|
|||
struct rom_file *pifrom, struct rom_file *cart);
|
||||
|
||||
static int setup_and_run_device(struct cen64_device *device,
|
||||
const char *pifrom_path, const char *cart_path);
|
||||
const char *pifrom_path, const char *cart_path, bool extra_mode);
|
||||
|
||||
// Called when a simulation instance is terminating.
|
||||
void cen64_cleanup(struct cen64_device *device) {
|
||||
|
@ -28,7 +28,8 @@ void cen64_cleanup(struct cen64_device *device) {
|
|||
// Called when another simulation instance is desired.
|
||||
int cen64_main(struct cen64_device *device, int argc, const char *argv[]) {
|
||||
struct gl_window_hints hints;
|
||||
int status;
|
||||
bool extra_mode = false;
|
||||
int status, i;
|
||||
|
||||
// Prevent debugging tools from raising warnings
|
||||
// about uninitialized memory being read, etc.
|
||||
|
@ -36,7 +37,11 @@ int cen64_main(struct cen64_device *device, int argc, const char *argv[]) {
|
|||
get_default_gl_window_hints(&hints);
|
||||
|
||||
if (argc < 3) {
|
||||
printf("%s <pifrom.bin> <rom>\n", argv[0]);
|
||||
printf("%s <pifrom.bin> <rom>\n\n"
|
||||
"Options:\n"
|
||||
" -printsimstats : Print simulation statistics at exit.\n",
|
||||
argv[0]);
|
||||
|
||||
return 255;
|
||||
}
|
||||
|
||||
|
@ -45,8 +50,13 @@ int cen64_main(struct cen64_device *device, int argc, const char *argv[]) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Parse arguments.
|
||||
for (i = 1; i < argc - 2; i++)
|
||||
if (!strcmp(argv[i], "-printsimstats"))
|
||||
extra_mode = true;
|
||||
|
||||
// Start simulation.
|
||||
if ((status = setup_and_run_device(device, argv[1], argv[2])))
|
||||
if ((status = setup_and_run_device(device, argv[i], argv[i + 1], extra_mode)))
|
||||
destroy_gl_window(&device->vi.gl_window);
|
||||
|
||||
return status;
|
||||
|
@ -79,7 +89,7 @@ int load_roms(const char *pifrom_path, const char *cart_path,
|
|||
|
||||
// Create a device, Load ROM images, etc. and run.
|
||||
int setup_and_run_device(struct cen64_device *device,
|
||||
const char *pifrom_path, const char *cart_path) {
|
||||
const char *pifrom_path, const char *cart_path, bool extra_mode) {
|
||||
struct rom_file pifrom, cart;
|
||||
int status;
|
||||
|
||||
|
@ -90,8 +100,11 @@ int setup_and_run_device(struct cen64_device *device,
|
|||
device->cart_size = cart.size;
|
||||
|
||||
// Create a device and roceed to the main application loop.
|
||||
if (!(status = device_create(device) == NULL))
|
||||
status = device_run(device);
|
||||
if (!(status = device_create(device) == NULL)) {
|
||||
status = unlikely(extra_mode)
|
||||
? device_run_extra(device)
|
||||
: device_run(device);
|
||||
}
|
||||
|
||||
close_rom_file(&cart);
|
||||
close_rom_file(&pifrom);
|
||||
|
|
25
device.c
25
device.c
|
@ -118,3 +118,28 @@ int device_run(struct cen64_device *device) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Kicks off threads and starts the device.
|
||||
int device_run_extra(struct cen64_device *device) {
|
||||
unsigned i;
|
||||
|
||||
if (setjmp(device->bus.unwind_data)) {
|
||||
vr4300_print_summary(&device->vr4300_stats);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
for (i = 0; i < 2; i++) {
|
||||
vi_cycle(&device->vi);
|
||||
|
||||
rsp_cycle(&device->rsp);
|
||||
vr4300_cycle(&device->vr4300);
|
||||
vr4300_cycle_extra(&device->vr4300, &device->vr4300_stats);
|
||||
}
|
||||
|
||||
vr4300_cycle(&device->vr4300);
|
||||
vr4300_cycle_extra(&device->vr4300, &device->vr4300_stats);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
5
device.h
5
device.h
|
@ -45,11 +45,16 @@ struct cen64_device {
|
|||
|
||||
const uint8_t *pifrom;
|
||||
const uint8_t *cart;
|
||||
|
||||
// Debugging/statistical data.
|
||||
struct vr4300_stats vr4300_stats;
|
||||
};
|
||||
|
||||
struct cen64_device *device_create(struct cen64_device *device);
|
||||
void device_destroy(struct cen64_device *device);
|
||||
|
||||
int device_run(struct cen64_device *device);
|
||||
int device_run_extra(struct cen64_device *device);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
48
vr4300/cpu.c
48
vr4300/cpu.c
|
@ -48,3 +48,51 @@ int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Prints out simulation information to stdout.
|
||||
void vr4300_print_summary(struct vr4300_stats *stats) {
|
||||
unsigned i, j;
|
||||
float secs;
|
||||
float cpi;
|
||||
|
||||
// Print banner.
|
||||
printf("###############################\n"
|
||||
" NEC VR4300 Simulation Summary\n"
|
||||
"###############################\n"
|
||||
"\n"
|
||||
);
|
||||
|
||||
// Print configuration, summary, whatever.
|
||||
secs = stats->total_cycles / 93750000.0f;
|
||||
|
||||
printf(" %16s: %.1f sec.\n"
|
||||
"\n\n",
|
||||
|
||||
"Actual runtime", secs
|
||||
);
|
||||
|
||||
// Print performance statistics.
|
||||
cpi = (float) stats->executed_instructions / stats->total_cycles;
|
||||
|
||||
printf(" * Performance statistics:\n\n"
|
||||
" %16s: %llu\n"
|
||||
" %16s: %llu\n"
|
||||
" %16s: %1.2f\n"
|
||||
"\n\n",
|
||||
|
||||
"Elapsed pcycles", stats->total_cycles,
|
||||
"Insns executed", stats->executed_instructions,
|
||||
"Average CPI", cpi
|
||||
);
|
||||
|
||||
// Print executed opcode counts.
|
||||
printf(" * Executed instruction counts:\n\n");
|
||||
|
||||
for (i = 1; i < NUM_VR4300_OPCODES; i += 2) {
|
||||
for (j = 0; i + j < NUM_VR4300_OPCODES && j < 2; j++)
|
||||
printf(" %16s: %16llu\t", vr4300_opcode_mnemonics[i + j],
|
||||
stats->opcode_counts[i + j]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
11
vr4300/cpu.h
11
vr4300/cpu.h
|
@ -15,6 +15,7 @@
|
|||
#include "vr4300/cp1.h"
|
||||
#include "vr4300/dcache.h"
|
||||
#include "vr4300/icache.h"
|
||||
#include "vr4300/opcodes.h"
|
||||
#include "vr4300/pipeline.h"
|
||||
|
||||
struct bus_controller;
|
||||
|
@ -110,8 +111,18 @@ struct vr4300 {
|
|||
|
||||
};
|
||||
|
||||
struct vr4300_stats {
|
||||
unsigned long long executed_instructions;
|
||||
unsigned long long total_cycles;
|
||||
|
||||
unsigned long long opcode_counts[NUM_VR4300_OPCODES];
|
||||
};
|
||||
|
||||
void vr4300_cycle(struct vr4300 *vr4300);
|
||||
void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *stats);
|
||||
int vr4300_init(struct vr4300 *vr4300, struct bus_controller *bus);
|
||||
|
||||
void vr4300_print_summary(struct vr4300_stats *stats);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -460,6 +460,22 @@ void vr4300_cycle(struct vr4300 *vr4300) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Collects additional information about the pipeline each cycle.
|
||||
void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *stats) {
|
||||
struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
|
||||
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
|
||||
|
||||
// Collect information for CPI.
|
||||
stats->executed_instructions +=
|
||||
!dcwb_latch->common.fault &&
|
||||
!vr4300->pipeline.cycles_to_stall;
|
||||
|
||||
stats->total_cycles++;
|
||||
|
||||
// Collect information about executed instructions.
|
||||
stats->opcode_counts[rfex_latch->opcode.id]++;
|
||||
}
|
||||
|
||||
// Initializes the pipeline with default values.
|
||||
void vr4300_pipeline_init(struct vr4300_pipeline *pipeline) {
|
||||
pipeline->icrf_latch.segment = get_default_segment();
|
||||
|
|
Loading…
Reference in a new issue