improved aica timer accuracy

improved accuracy of aggregate counters
updated options in readme
removed some bool usage
This commit is contained in:
Anthony Pesch 2016-12-11 17:42:53 -08:00
parent ae3d459960
commit f0c7fe825e
28 changed files with 175 additions and 180 deletions

View File

@ -43,11 +43,13 @@ Command line flags are loaded from and saved to `$HOME/.redream/flags` each run.
### All options ### All options
``` ```
--bios Path to BIOS [default: dc_boot.bin] --bios Path to BIOS [default: dc_boot.bin]
--flash Path to flash ROM [default: dc_flash.bin] --flash Path to flash ROM [default: dc_flash.bin]
--debug Start GDB debug server --controller Path to controller profile
--perf Write perf-compatible maps for generated code --throttle Throttle emulation speed to match the original hardware [default: 1]
--profile Path to controller profile --verbose Enable debug logging [default: 0]
--perf Write perf-compatible maps for generated code [default: 0]
--gdb Start GDB debug server [default: 0]
``` ```
### Debugging ### Debugging

View File

@ -4,7 +4,7 @@
#include "core/debug_break.h" #include "core/debug_break.h"
#include "core/log.h" #include "core/log.h"
// CHECK_* macros are usually true, hint this to the compiler if possible /* CHECK_* macros are usually true, hint this to the compiler if possible */
#if defined(PLATFORM_LINUX) || defined(PLATFORM_DARWIN) #if defined(PLATFORM_LINUX) || defined(PLATFORM_DARWIN)
#define CHECK_EXPECT_TRUE(expr) (__builtin_expect(!!(expr), 1)) #define CHECK_EXPECT_TRUE(expr) (__builtin_expect(!!(expr), 1))
#else #else
@ -17,8 +17,8 @@ const char *format_check_error_ex(const char *filename, int linenum,
const char *format_check_error(const char *filename, int linenum, const char *format_check_error(const char *filename, int linenum,
const char *expr, const char *unused); const char *expr, const char *unused);
// 3: VA_ARGS = format_check_error /* 3: VA_ARGS = format_check_error */
// 4+: VA_ARGS = format_check_error_ex /* 4+: VA_ARGS = format_check_error_ex */
#define SELECT_FORMAT_CHECK_ERROR(_1, _2, _3, _4, _5, _6, NAME, ...) NAME #define SELECT_FORMAT_CHECK_ERROR(_1, _2, _3, _4, _5, _6, NAME, ...) NAME
#define EXPAND_FORMAT_CHECK_ERROR(x) x #define EXPAND_FORMAT_CHECK_ERROR(x) x
@ -28,7 +28,7 @@ const char *format_check_error(const char *filename, int linenum,
format_check_error_ex, format_check_error_ex, format_check_error_ex, \ format_check_error_ex, format_check_error_ex, format_check_error_ex, \
format_check_error)(filename, linenum, expr, ##__VA_ARGS__)) format_check_error)(filename, linenum, expr, ##__VA_ARGS__))
// checks ran for all build configurations /* checks ran for all build configurations */
#define CHECK_BINARY_OP(v1, v2, op, ...) \ #define CHECK_BINARY_OP(v1, v2, op, ...) \
do { \ do { \
if (!CHECK_EXPECT_TRUE((v1)op(v2))) { \ if (!CHECK_EXPECT_TRUE((v1)op(v2))) { \
@ -60,7 +60,7 @@ const char *format_check_error(const char *filename, int linenum,
} \ } \
} while (0) } while (0)
// checks ran only for debug builds /* checks ran only for debug builds */
#ifndef NDEBUG #ifndef NDEBUG
#define DCHECK_EQ(v1, v2, ...) CHECK_EQ(v1, v2, ##__VA_ARGS__) #define DCHECK_EQ(v1, v2, ...) CHECK_EQ(v1, v2, ##__VA_ARGS__)
#define DCHECK_NE(v1, v2, ...) CHECK_NE(v1, v2, ##__VA_ARGS__) #define DCHECK_NE(v1, v2, ...) CHECK_NE(v1, v2, ##__VA_ARGS__)

View File

@ -32,7 +32,7 @@
#else #else
// not supported /* not supported */
#endif #endif

View File

@ -31,7 +31,7 @@ void list_add_after(struct list *list, struct list_node *after,
} }
} }
// no need to check list->tail == NULL, in that case after would be NULL /* no need to check list->tail == NULL, in that case after would be NULL */
if (list->tail == after) { if (list->tail == after) {
list->tail = n; list->tail = n;
} }
@ -57,8 +57,8 @@ void list_clear(struct list *list) {
list->head = list->tail = NULL; list->head = list->tail = NULL;
} }
// Implements the mergesort for linked lists as described at /* implements the mergesort for linked lists as described at
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html */
void list_sort(struct list *list, list_node_cmp cmp) { void list_sort(struct list *list, list_node_cmp cmp) {
struct list_node *head = list->head; struct list_node *head = list->head;
struct list_node *tail = NULL; struct list_node *tail = NULL;
@ -72,10 +72,10 @@ void list_sort(struct list *list, list_node_cmp cmp) {
tail = NULL; tail = NULL;
while (p) { while (p) {
// track the number of lists merged this pass /* track the number of lists merged this pass */
merges++; merges++;
// step q forward k places, tracking the size of p /* step q forward k places, tracking the size of p */
int psize = 0; int psize = 0;
int qsize = k; int qsize = k;
struct list_node *q = p; struct list_node *q = p;
@ -84,8 +84,8 @@ void list_sort(struct list *list, list_node_cmp cmp) {
q = q->next; q = q->next;
} }
// merge the list starting at p of length psize with the list starting /* merge the list starting at p of length psize with the list starting
// at q of at most, length qsize at q of at most, length qsize */
while (psize || (qsize && q)) { while (psize || (qsize && q)) {
struct list_node *next; struct list_node *next;
@ -107,7 +107,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
psize--; psize--;
} }
// move merged node to tail /* move merged node to tail */
if (!tail) { if (!tail) {
head = next; head = next;
} else { } else {
@ -124,7 +124,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
tail->next = NULL; tail->next = NULL;
} }
// if only 1 pair of lists was merged, this is the end /* if only 1 pair of lists was merged, this is the end */
if (merges <= 1) { if (merges <= 1) {
break; break;
} }
@ -132,7 +132,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
k *= 2; k *= 2;
} }
// update internal head and tail with sorted head and tail /* update internal head and tail with sorted head and tail */
list->head = head; list->head = head;
list->tail = tail; list->tail = tail;
} }

View File

@ -2,15 +2,15 @@
#include <stdio.h> #include <stdio.h>
#include "core/log.h" #include "core/log.h"
DEFINE_OPTION_BOOL(debug, false, "Enable debug logging"); DEFINE_OPTION_INT(verbose, 0, "Enable debug logging");
void log_line(enum log_level level, const char *format, ...) { void log_line(enum log_level level, const char *format, ...) {
static char sbuffer[0x1000]; static char sbuffer[0x1000];
int buffer_size = sizeof(sbuffer); int buffer_size = sizeof(sbuffer);
char *buffer = sbuffer; char *buffer = sbuffer;
/* allocate a temporary buffer if need be to fit the string */
va_list args; va_list args;
// allocate a temporary buffer if need be to fit the string
va_start(args, format); va_start(args, format);
int len = vsnprintf(0, 0, format, args); int len = vsnprintf(0, 0, format, args);
if (len >= buffer_size) { if (len >= buffer_size) {
@ -40,7 +40,7 @@ void log_line(enum log_level level, const char *format, ...) {
printf("%s\n", buffer); printf("%s\n", buffer);
#endif #endif
// cleanup the temporary buffer /* cleanup the temporary buffer */
if (buffer != sbuffer) { if (buffer != sbuffer) {
free(buffer); free(buffer);
} }

View File

@ -5,7 +5,7 @@
#include "core/debug_break.h" #include "core/debug_break.h"
#include "core/option.h" #include "core/option.h"
DECLARE_OPTION_BOOL(debug); DECLARE_OPTION_INT(verbose);
enum log_level { enum log_level {
LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG,
@ -25,7 +25,7 @@ enum log_level {
void log_line(enum log_level level, const char *format, ...); void log_line(enum log_level level, const char *format, ...);
#define LOG_DEBUG(...) \ #define LOG_DEBUG(...) \
if (OPTION_debug) { \ if (OPTION_verbose) { \
log_line(LOG_LEVEL_DEBUG, ##__VA_ARGS__); \ log_line(LOG_LEVEL_DEBUG, ##__VA_ARGS__); \
} }

View File

@ -19,13 +19,15 @@ static struct option *options_find(const char *name) {
static void options_parse_value(struct option *opt, const char *value) { static void options_parse_value(struct option *opt, const char *value) {
switch (opt->type) { switch (opt->type) {
case OPT_BOOL: case OPT_INT: {
*(bool *)opt->storage = strcmp(value, "false") && strcmp(value, "0"); if (!strcmp(value, "false")) {
break; *(int *)opt->storage = 0;
} else if (!strcmp(value, "true")) {
case OPT_INT: *(int *)opt->storage = 1;
*(int *)opt->storage = atoi(value); } else {
break; *(int *)opt->storage = atoi(value);
}
} break;
case OPT_STRING: case OPT_STRING:
strncpy((char *)opt->storage, value, MAX_OPTION_LENGTH); strncpy((char *)opt->storage, value, MAX_OPTION_LENGTH);
@ -37,9 +39,6 @@ static const char *options_format_value(struct option *opt) {
static char value[MAX_OPTION_LENGTH]; static char value[MAX_OPTION_LENGTH];
switch (opt->type) { switch (opt->type) {
case OPT_BOOL:
return *(bool *)opt->storage ? "true" : "false";
case OPT_INT: case OPT_INT:
snprintf(value, sizeof(value), "%d", *(int *)opt->storage); snprintf(value, sizeof(value), "%d", *(int *)opt->storage);
return value; return value;
@ -65,7 +64,7 @@ void options_parse(int *argc, char ***argv) {
for (int i = 1; i < end;) { for (int i = 1; i < end;) {
char *arg = (*argv)[i]; char *arg = (*argv)[i];
// move non-option to the end for parsing by the application /* move non-option to the end for parsing by the application */
if (arg[0] != '-') { if (arg[0] != '-') {
(*argv)[i] = (*argv)[end - 1]; (*argv)[i] = (*argv)[end - 1];
(*argv)[end - 1] = arg; (*argv)[end - 1] = arg;
@ -73,12 +72,12 @@ void options_parse(int *argc, char ***argv) {
continue; continue;
} }
// chomp leading - /* chomp leading - */
while (arg[0] == '-') { while (arg[0] == '-') {
arg++; arg++;
} }
// terminate arg and extract value /* terminate arg and extract value */
char *value = arg; char *value = arg;
while (value[0] && value[0] != '=') { while (value[0] && value[0] != '=') {
@ -89,7 +88,7 @@ void options_parse(int *argc, char ***argv) {
*(value++) = 0; *(value++) = 0;
} }
// lookup the option and assign the parsed value to it /* lookup the option and assign the parsed value to it */
struct option *opt = options_find(arg); struct option *opt = options_find(arg);
if (opt) { if (opt) {
@ -114,15 +113,15 @@ static int options_ini_handler(void *user, const char *section,
return 0; return 0;
} }
bool options_read(const char *filename) { int options_read(const char *filename) {
return ini_parse(filename, options_ini_handler, NULL) >= 0; return ini_parse(filename, options_ini_handler, NULL) >= 0;
} }
bool options_write(const char *filename) { int options_write(const char *filename) {
FILE *output = fopen(filename, "wt"); FILE *output = fopen(filename, "wt");
if (!output) { if (!output) {
return false; return 0;
} }
list_for_each_entry(opt, &s_options, struct option, it) { list_for_each_entry(opt, &s_options, struct option, it) {
@ -131,7 +130,7 @@ bool options_write(const char *filename) {
fclose(output); fclose(output);
return true; return 1;
} }
void options_print_help() { void options_print_help() {

View File

@ -1,27 +1,12 @@
#ifndef OPTIONS_H #ifndef OPTIONS_H
#define OPTIONS_H #define OPTIONS_H
#include <stdbool.h>
#include <string.h> #include <string.h>
#include "core/constructor.h" #include "core/constructor.h"
#include "core/list.h" #include "core/list.h"
#define MAX_OPTION_LENGTH 1024 #define MAX_OPTION_LENGTH 1024
#define DECLARE_OPTION_BOOL(name) extern bool OPTION_##name;
#define DEFINE_OPTION_BOOL(name, value, desc) \
bool OPTION_##name; \
static struct option OPTION_T_##name = { \
OPT_BOOL, #name, desc, &OPTION_##name, {0}}; \
CONSTRUCTOR(OPTION_REGISTER_##name) { \
*(bool *)(&OPTION_##name) = value; \
options_register(&OPTION_T_##name); \
} \
DESTRUCTOR(OPTION_UNREGISTER_##name) { \
options_unregister(&OPTION_T_##name); \
}
#define DECLARE_OPTION_INT(name) extern int OPTION_##name; #define DECLARE_OPTION_INT(name) extern int OPTION_##name;
#define DEFINE_OPTION_INT(name, value, desc) \ #define DEFINE_OPTION_INT(name, value, desc) \
@ -54,7 +39,6 @@
#define OPTION_HIDDEN NULL #define OPTION_HIDDEN NULL
enum option_type { enum option_type {
OPT_BOOL,
OPT_INT, OPT_INT,
OPT_STRING, OPT_STRING,
}; };
@ -71,8 +55,8 @@ void options_register(struct option *option);
void options_unregister(struct option *option); void options_unregister(struct option *option);
void options_parse(int *argc, char ***argv); void options_parse(int *argc, char ***argv);
bool options_read(const char *filename); int options_read(const char *filename);
bool options_write(const char *filename); int options_write(const char *filename);
void options_print_help(); void options_print_help();

View File

@ -103,9 +103,8 @@ prof_token_t prof_get_aggregate_token(const char *name) {
return tok; return tok;
} }
void prof_flip() { void prof_update(int64_t now) {
/* flip aggregate counters every second */ /* update time-based aggregate counters every second */
int64_t now = time_nanoseconds();
int64_t next_aggregation = prof.last_aggregation + NS_PER_SEC; int64_t next_aggregation = prof.last_aggregation + NS_PER_SEC;
if (now > next_aggregation) { if (now > next_aggregation) {
@ -120,7 +119,10 @@ void prof_flip() {
prof.last_aggregation = now; prof.last_aggregation = now;
} }
}
void prof_flip() {
/* flip frame-based profile zones at the end of every frame */
MicroProfileFlip(); MicroProfileFlip();
} }

View File

@ -47,6 +47,10 @@ int64_t prof_counter_load(prof_token_t tok);
void prof_counter_add(prof_token_t tok, int64_t count); void prof_counter_add(prof_token_t tok, int64_t count);
void prof_counter_set(prof_token_t tok, int64_t count); void prof_counter_set(prof_token_t tok, int64_t count);
/* called at the end of every frame to aggregate frame-based profile zones */
void prof_flip(); void prof_flip();
/* called periodically to aggregate time-based aggregate counters */
void prof_update(int64_t now);
#endif #endif

View File

@ -1,8 +1,8 @@
/* would be nice to convert this file to C once MSVC supports stdatomic.h */ /* would be nice to convert this file to C once MSVC supports stdatomic.h */
#include <atomic> #include <atomic>
extern "C" { extern "C" {
#include "core/ringbuf.h"
#include "core/assert.h" #include "core/assert.h"
#include "core/ringbuf.h"
} }
struct ringbuf { struct ringbuf {

View File

@ -40,8 +40,8 @@ int strnrep(char *dst, size_t dst_size, const char *token, size_t token_len,
break; break;
} }
// move substring starting at the end of the token to the end of where the /* move substring starting at the end of the token to the end of where the
// new value will be) new value will be) */
size_t dst_len = strnlen(dst, dst_size); size_t dst_len = strnlen(dst, dst_size);
size_t move_size = (dst_len + 1) - ((ptr - dst) + token_len); size_t move_size = (dst_len + 1) - ((ptr - dst) + token_len);
@ -51,7 +51,7 @@ int strnrep(char *dst, size_t dst_size, const char *token, size_t token_len,
memmove(ptr + value_len, ptr + token_len, move_size); memmove(ptr + value_len, ptr + token_len, move_size);
// copy new value into token position /* copy new value into token position */
memmove(ptr, value, value_len); memmove(ptr, value, value_len);
} }

View File

@ -1,6 +1,7 @@
#include "emu/emulator.h" #include "emu/emulator.h"
#include "core/option.h" #include "core/option.h"
#include "core/profiler.h" #include "core/profiler.h"
#include "hw/aica/aica.h"
#include "hw/arm7/arm7.h" #include "hw/arm7/arm7.h"
#include "hw/dreamcast.h" #include "hw/dreamcast.h"
#include "hw/gdrom/gdrom.h" #include "hw/gdrom/gdrom.h"
@ -15,6 +16,9 @@
#include "ui/nuklear.h" #include "ui/nuklear.h"
#include "ui/window.h" #include "ui/window.h"
DEFINE_OPTION_INT(throttle, 1,
"Throttle emulation speed to match the original hardware");
DEFINE_AGGREGATE_COUNTER(frames); DEFINE_AGGREGATE_COUNTER(frames);
struct emu { struct emu {
@ -22,7 +26,6 @@ struct emu {
struct window_listener listener; struct window_listener listener;
struct dreamcast *dc; struct dreamcast *dc;
int running; int running;
int throttled;
/* render state */ /* render state */
struct tr *tr; struct tr *tr;
@ -119,7 +122,7 @@ static void emu_debug_menu(void *data, struct nk_context *ctx) {
if (nk_menu_begin_label(ctx, "EMULATOR", NK_TEXT_LEFT, if (nk_menu_begin_label(ctx, "EMULATOR", NK_TEXT_LEFT,
nk_vec2(140.0f, 200.0f))) { nk_vec2(140.0f, 200.0f))) {
nk_layout_row_dynamic(ctx, DEBUG_MENU_HEIGHT, 1); nk_layout_row_dynamic(ctx, DEBUG_MENU_HEIGHT, 1);
nk_checkbox_label(ctx, "throttled", &emu->throttled); nk_checkbox_label(ctx, "throttled", &OPTION_throttle);
nk_menu_end(ctx); nk_menu_end(ctx);
} }
@ -164,16 +167,23 @@ static void *emu_core_thread(void *data) {
static const int64_t MACHINE_STEP = HZ_TO_NANO(1000); static const int64_t MACHINE_STEP = HZ_TO_NANO(1000);
int64_t current_time = time_nanoseconds(); int64_t current_time = time_nanoseconds();
int64_t next_time = current_time; int64_t next_time = current_time;
int64_t delta_time = 0;
while (emu->running) { while (emu->running) {
current_time = time_nanoseconds(); current_time = time_nanoseconds();
int64_t delta_time = current_time - next_time; if (OPTION_throttle) {
delta_time = current_time - next_time;
if (!emu->throttled || delta_time >= 0) { } else {
dc_tick(emu->dc, MACHINE_STEP); delta_time = 0;
next_time = current_time + MACHINE_STEP;
} }
if (delta_time >= 0) {
dc_tick(emu->dc, MACHINE_STEP);
next_time = current_time + MACHINE_STEP - delta_time;
}
prof_update(current_time);
} }
return 0; return 0;
@ -205,17 +215,17 @@ void emu_run(struct emu *emu, const char *path) {
dc_resume(emu->dc); dc_resume(emu->dc);
} }
/* start core emulator thread */
thread_t core_thread;
emu->running = 1; emu->running = 1;
core_thread = thread_create(&emu_core_thread, NULL, emu);
/* start core emulator thread */
thread_t core_thread = thread_create(&emu_core_thread, NULL, emu);
/* run the renderer / ui in the main thread */ /* run the renderer / ui in the main thread */
while (emu->running) { while (emu->running) {
win_pump_events(emu->window); win_pump_events(emu->window);
} }
/* wait for the graphics thread to exit */ /* wait for the core thread to exit */
void *result; void *result;
thread_join(core_thread, &result); thread_join(core_thread, &result);
} }

View File

@ -1,6 +1,7 @@
#include "hw/aica/aica.h" #include "hw/aica/aica.h"
#include "core/log.h" #include "core/log.h"
#include "core/option.h" #include "core/option.h"
#include "core/profiler.h"
#include "hw/aica/aica_types.h" #include "hw/aica/aica_types.h"
#include "hw/arm7/arm7.h" #include "hw/arm7/arm7.h"
#include "hw/dreamcast.h" #include "hw/dreamcast.h"
@ -11,11 +12,13 @@
DEFINE_OPTION_INT(rtc, 0, OPTION_HIDDEN); DEFINE_OPTION_INT(rtc, 0, OPTION_HIDDEN);
#define AICA_CLOCK_FREQ INT64_C(22579200) DEFINE_AGGREGATE_COUNTER(aica_samples);
#define AICA_SAMPLE_FREQ INT64_C(44100)
#define AICA_NUM_CHANNELS 64 #define AICA_NUM_CHANNELS 64
#define AICA_TIMER_PERIOD 0xff #define AICA_SAMPLE_FREQ INT64_C(44100)
#define AICA_SAMPLE_BATCH 10
#define AICA_SAMPLE_SHIFT 10 #define AICA_SAMPLE_SHIFT 10
#define AICA_TIMER_PERIOD 0xff
struct aica_channel { struct aica_channel {
struct channel_data *data; struct channel_data *data;
@ -36,25 +39,28 @@ struct aica {
struct device; struct device;
uint8_t reg[0x11000]; uint8_t reg[0x11000];
uint8_t *wave_ram; uint8_t *wave_ram;
/* reset state */ /* reset state */
int arm_resetting; int arm_resetting;
/* interrupts */ /* interrupts */
uint32_t arm_irq_l; uint32_t arm_irq_l;
uint32_t arm_irq_m; uint32_t arm_irq_m;
/* timers */ /* timers */
struct timer *timers[3]; struct timer *timers[3];
/* real-time clock */ /* real-time clock */
struct timer *rtc_timer; struct timer *rtc_timer;
int rtc_write; int rtc_write;
uint32_t rtc; uint32_t rtc;
/* channels */ /* channels */
struct common_data *common_data; struct common_data *common_data;
struct aica_channel channels[AICA_NUM_CHANNELS]; struct aica_channel channels[AICA_NUM_CHANNELS];
struct timer *sample_timer;
}; };
/*
* interrupts
*/
static void aica_raise_interrupt(struct aica *aica, int intr) { static void aica_raise_interrupt(struct aica *aica, int intr) {
aica->common_data->MCIPD |= (1 << intr); aica->common_data->MCIPD |= (1 << intr);
aica->common_data->SCIPD |= (1 << intr); aica->common_data->SCIPD |= (1 << intr);
@ -118,9 +124,6 @@ static void aica_update_sh(struct aica *aica) {
} }
} }
/*
* timers
*/
static void aica_timer_reschedule(struct aica *aica, int n, uint32_t period); static void aica_timer_reschedule(struct aica *aica, int n, uint32_t period);
static void aica_timer_expire(struct aica *aica, int n) { static void aica_timer_expire(struct aica *aica, int n) {
@ -197,9 +200,6 @@ static void aica_timer_init(struct aica *aica) {
} }
} }
/*
* rtc
*/
static uint32_t aica_rtc_reg_read(struct aica *aica, uint32_t addr, static uint32_t aica_rtc_reg_read(struct aica *aica, uint32_t addr,
uint32_t data_mask) { uint32_t data_mask) {
switch (addr) { switch (addr) {
@ -262,9 +262,6 @@ static void aica_rtc_init(struct aica *aica) {
scheduler_start_timer(aica->scheduler, &aica_rtc_timer, aica, NS_PER_SEC); scheduler_start_timer(aica->scheduler, &aica_rtc_timer, aica, NS_PER_SEC);
} }
/*
* channels
*/
static uint32_t aica_channel_step(struct aica_channel *ch) { static uint32_t aica_channel_step(struct aica_channel *ch) {
uint32_t oct = ch->data->OCT; uint32_t oct = ch->data->OCT;
uint32_t step = (1 << AICA_SAMPLE_SHIFT) | ch->data->FNS; uint32_t step = (1 << AICA_SAMPLE_SHIFT) | ch->data->FNS;
@ -334,6 +331,7 @@ static void aica_channel_update(struct aica *aica, struct aica_channel *ch) {
uint32_t ca = ch->offset >> AICA_SAMPLE_SHIFT; uint32_t ca = ch->offset >> AICA_SAMPLE_SHIFT;
if (ca > ch->data->LEA) { if (ca > ch->data->LEA) {
if (ch->data->LPCTL) { if (ch->data->LPCTL) {
LOG_INFO("aica_channel_step %d restart", ch - aica->channels);
ch->offset = ch->data->LSA << AICA_SAMPLE_SHIFT; ch->offset = ch->data->LSA << AICA_SAMPLE_SHIFT;
ch->looped = 1; ch->looped = 1;
} else { } else {
@ -349,6 +347,8 @@ static void aica_generate_samples(struct aica *aica, int samples) {
aica_channel_update(aica, ch); aica_channel_update(aica, ch);
} }
} }
prof_counter_add(COUNTER_aica_samples, samples);
} }
static uint32_t aica_channel_reg_read(struct aica *aica, uint32_t addr, static uint32_t aica_channel_reg_read(struct aica *aica, uint32_t addr,
@ -475,9 +475,6 @@ static void aica_common_reg_write(struct aica *aica, uint32_t addr,
} }
} }
/*
* memory callbacks
*/
uint32_t aica_reg_read(struct aica *aica, uint32_t addr, uint32_t data_mask) { uint32_t aica_reg_read(struct aica *aica, uint32_t addr, uint32_t data_mask) {
if (addr < 0x2000) { if (addr < 0x2000) {
return aica_channel_reg_read(aica, addr, data_mask); return aica_channel_reg_read(aica, addr, data_mask);
@ -505,19 +502,18 @@ void aica_reg_write(struct aica *aica, uint32_t addr, uint32_t data,
WRITE_DATA(&aica->reg[addr]); WRITE_DATA(&aica->reg[addr]);
} }
/* static void aica_next_sample(void *data) {
* device struct aica *aica = data;
*/
static void aica_run(struct device *dev, int64_t ns) {
struct aica *aica = (struct aica *)dev;
int samples = (int)NANO_TO_CYCLES(ns, AICA_SAMPLE_FREQ);
aica_generate_samples(aica, samples);
aica_generate_samples(aica, AICA_SAMPLE_BATCH);
aica_raise_interrupt(aica, AICA_INT_SAMPLE); aica_raise_interrupt(aica, AICA_INT_SAMPLE);
aica_update_arm(aica); aica_update_arm(aica);
aica_update_sh(aica); aica_update_sh(aica);
/* reschedule */
aica->sample_timer =
scheduler_start_timer(aica->scheduler, &aica_next_sample, aica,
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_SAMPLE_BATCH));
} }
static bool aica_init(struct device *dev) { static bool aica_init(struct device *dev) {
@ -536,28 +532,27 @@ static bool aica_init(struct device *dev) {
aica_timer_init(aica); aica_timer_init(aica);
aica_rtc_init(aica); aica_rtc_init(aica);
arm7_suspend(aica->arm); aica->sample_timer =
scheduler_start_timer(aica->scheduler, &aica_next_sample, aica,
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_SAMPLE_BATCH));
return true; return true;
} }
void aica_destroy(struct aica *aica) {
scheduler_cancel_timer(aica->scheduler, aica->sample_timer);
aica_rtc_shutdown(aica);
aica_timer_shutdown(aica);
dc_destroy_device((struct device *)aica);
}
struct aica *aica_create(struct dreamcast *dc) { struct aica *aica_create(struct dreamcast *dc) {
struct aica *aica = struct aica *aica =
dc_create_device(dc, sizeof(struct aica), "aica", &aica_init); dc_create_device(dc, sizeof(struct aica), "aica", &aica_init);
aica->execute_if = dc_create_execute_interface(&aica_run, 1);
return aica; return aica;
} }
void aica_destroy(struct aica *aica) {
aica_rtc_shutdown(aica);
aica_timer_shutdown(aica);
dc_destroy_execute_interface(aica->execute_if);
dc_destroy_device((struct device *)aica);
}
/* clang-format off */ /* clang-format off */
AM_BEGIN(struct aica, aica_reg_map); AM_BEGIN(struct aica, aica_reg_map);
/* over-allocate to align with the host allocation granularity */ /* over-allocate to align with the host allocation granularity */

View File

@ -7,10 +7,10 @@
struct aica; struct aica;
struct dreamcast; struct dreamcast;
struct aica *aica_create(struct dreamcast *dc);
void aica_destroy(struct aica *aica);
AM_DECLARE(aica_reg_map); AM_DECLARE(aica_reg_map);
AM_DECLARE(aica_data_map); AM_DECLARE(aica_data_map);
struct aica *aica_create(struct dreamcast *dc);
void aica_destroy(struct aica *aica);
#endif #endif

View File

@ -15,7 +15,7 @@
#include "hw/scheduler.h" #include "hw/scheduler.h"
#include "hw/sh4/sh4.h" #include "hw/sh4/sh4.h"
DEFINE_OPTION_BOOL(gdb, false, "Run gdb debug server"); DEFINE_OPTION_INT(gdb, 0, "Run gdb debug server");
void dc_joy_remove(struct dreamcast *dc, int joystick_index) { void dc_joy_remove(struct dreamcast *dc, int joystick_index) {
list_for_each_entry(dev, &dc->devices, struct device, it) { list_for_each_entry(dev, &dc->devices, struct device, it) {

View File

@ -50,7 +50,7 @@ static int get_region_handle(page_entry_t page) {
struct mirror_iterator { struct mirror_iterator {
uint32_t base, mask, imask, step; uint32_t base, mask, imask, step;
uint32_t i, addr; uint32_t i, addr;
bool first; int first;
}; };
static void mirror_iterator_init(struct mirror_iterator *it, uint32_t addr, static void mirror_iterator_init(struct mirror_iterator *it, uint32_t addr,
@ -61,19 +61,19 @@ static void mirror_iterator_init(struct mirror_iterator *it, uint32_t addr,
it->step = 1 << ctz32(it->imask); it->step = 1 << ctz32(it->imask);
it->i = 0; it->i = 0;
it->addr = it->base; it->addr = it->base;
it->first = true; it->first = 1;
} }
static bool mirror_iterator_next(struct mirror_iterator *it) { static bool mirror_iterator_next(struct mirror_iterator *it) {
/* first iteration just returns base */ /* first iteration just returns base */
if (it->first) { if (it->first) {
it->first = false; it->first = 0;
return true; return 1;
} }
/* stop once mask complement is completely set */ /* stop once mask complement is completely set */
if ((it->addr & it->imask) == it->imask) { if ((it->addr & it->imask) == it->imask) {
return false; return 0;
} }
/* step to the next permutation */ /* step to the next permutation */
@ -89,7 +89,7 @@ static bool mirror_iterator_next(struct mirror_iterator *it) {
/* merge with the base */ /* merge with the base */
it->addr = it->base | it->i; it->addr = it->base | it->i;
return true; return 1;
} }
static bool reserve_address_space(uint8_t **base) { static bool reserve_address_space(uint8_t **base) {
@ -109,12 +109,12 @@ static bool reserve_address_space(uint8_t **base) {
into it */ into it */
release_pages(*base, ADDRESS_SPACE_SIZE); release_pages(*base, ADDRESS_SPACE_SIZE);
return true; return 1;
} }
LOG_WARNING("Failed to reserve address space"); LOG_WARNING("Failed to reserve address space");
return false; return 0;
} }
struct memory_region *memory_get_region(struct memory *memory, struct memory_region *memory_get_region(struct memory *memory,
@ -187,17 +187,17 @@ uint8_t *memory_translate(struct memory *memory, const char *name,
return memory->shmem_base + region->physical.shmem_offset + offset; return memory->shmem_base + region->physical.shmem_offset + offset;
} }
static bool memory_create_shmem(struct memory *memory) { static int memory_create_shmem(struct memory *memory) {
/* create the shared memory object to back the address space */ /* create the shared memory object to back the address space */
memory->shmem = memory->shmem =
create_shared_memory("/redream", ADDRESS_SPACE_SIZE, ACC_READWRITE); create_shared_memory("/redream", ADDRESS_SPACE_SIZE, ACC_READWRITE);
if (memory->shmem == SHMEM_INVALID) { if (memory->shmem == SHMEM_INVALID) {
LOG_WARNING("Failed to create shared memory object"); LOG_WARNING("Failed to create shared memory object");
return false; return 0;
} }
return true; return 1;
} }
static void memory_destroy_shmem(struct memory *memory) { static void memory_destroy_shmem(struct memory *memory) {
@ -206,9 +206,9 @@ static void memory_destroy_shmem(struct memory *memory) {
destroy_shared_memory(memory->shmem); destroy_shared_memory(memory->shmem);
} }
bool memory_init(struct memory *memory) { int memory_init(struct memory *memory) {
if (!memory_create_shmem(memory)) { if (!memory_create_shmem(memory)) {
return false; return 0;
} }
/* map each memory interface's address space */ /* map each memory interface's address space */
@ -225,15 +225,15 @@ bool memory_init(struct memory *memory) {
/* map raw address space */ /* map raw address space */
if (!reserve_address_space(&memory->shmem_base)) { if (!reserve_address_space(&memory->shmem_base)) {
return false; return 0;
} }
if (!map_shared_memory(memory->shmem, 0, memory->shmem_base, if (!map_shared_memory(memory->shmem, 0, memory->shmem_base,
memory->shmem_size, ACC_READWRITE)) { memory->shmem_size, ACC_READWRITE)) {
return false; return 0;
} }
return true; return 1;
} }
void memory_destroy(struct memory *memory) { void memory_destroy(struct memory *memory) {
@ -574,8 +574,8 @@ void as_unmap(struct address_space *space) {
} }
} }
bool as_map(struct address_space *space, const char *name, int as_map(struct address_space *space, const char *name,
const struct address_map *map) { const struct address_map *map) {
as_unmap(space); as_unmap(space);
/* flatten the supplied address map out into a virtual page table */ /* flatten the supplied address map out into a virtual page table */
@ -588,7 +588,7 @@ bool as_map(struct address_space *space, const char *name,
#endif #endif
if (!reserve_address_space(&space->base)) { if (!reserve_address_space(&space->base)) {
return false; return 0;
} }
/* iterate the virtual page table, mapping it to the reserved address space */ /* iterate the virtual page table, mapping it to the reserved address space */
@ -621,21 +621,21 @@ bool as_map(struct address_space *space, const char *name,
if (!map_shared_memory(space->dc->memory->shmem, shmem_offset, addr, size, if (!map_shared_memory(space->dc->memory->shmem, shmem_offset, addr, size,
ACC_READWRITE)) { ACC_READWRITE)) {
return false; return 0;
} }
} else { } else {
/* disable access to virtual address range for mmio regions, resulting in /* disable access to virtual address range for mmio regions, resulting in
SIGSEGV on access */ SIGSEGV on access */
if (!map_shared_memory(space->dc->memory->shmem, 0, addr, size, if (!map_shared_memory(space->dc->memory->shmem, 0, addr, size,
ACC_NONE)) { ACC_NONE)) {
return false; return 0;
} }
} }
page_index += num_pages; page_index += num_pages;
} }
return true; return 1;
} }
void as_destroy(struct address_space *space) { void as_destroy(struct address_space *space) {

View File

@ -51,7 +51,7 @@ struct memory;
struct memory *memory_create(struct dreamcast *dc); struct memory *memory_create(struct dreamcast *dc);
void memory_destroy(struct memory *memory); void memory_destroy(struct memory *memory);
bool memory_init(struct memory *memory); int memory_init(struct memory *memory);
uint8_t *memory_translate(struct memory *memory, const char *name, uint8_t *memory_translate(struct memory *memory, const char *name,
uint32_t offset); uint32_t offset);
@ -186,8 +186,8 @@ struct address_space {
struct address_space *as_create(struct dreamcast *dc); struct address_space *as_create(struct dreamcast *dc);
void as_destroy(struct address_space *space); void as_destroy(struct address_space *space);
bool as_map(struct address_space *space, const char *name, int as_map(struct address_space *space, const char *name,
const struct address_map *map); const struct address_map *map);
void as_unmap(struct address_space *space); void as_unmap(struct address_space *space);
void as_lookup(struct address_space *space, uint32_t addr, void as_lookup(struct address_space *space, uint32_t addr,

View File

@ -8,9 +8,10 @@ struct dreamcast;
struct timer; struct timer;
struct scheduler; struct scheduler;
#define HZ_TO_NANO(hz) (int64_t)(NS_PER_SEC / (float)hz) #define HZ_TO_NANO(hz) (int64_t)(NS_PER_SEC / (float)(hz))
#define NANO_TO_CYCLES(ns, hz) (int64_t)((ns / (float)NS_PER_SEC) * hz) #define NANO_TO_CYCLES(ns, hz) (int64_t)(((ns) / (float)NS_PER_SEC) * (hz))
#define CYCLES_TO_NANO(cycles, hz) (int64_t)((cycles / (float)hz) * NS_PER_SEC) #define CYCLES_TO_NANO(cycles, hz) \
(int64_t)(((cycles) / (float)(hz)) * NS_PER_SEC)
typedef void (*timer_cb)(void *); typedef void (*timer_cb)(void *);

View File

@ -45,13 +45,13 @@ static void sh4_arg_mask(const char *instr_code, char c, uint16_t *mask,
} }
static void sh4_init_opdefs() { static void sh4_init_opdefs() {
static bool initialized = false; static int initialized = 0;
if (initialized) { if (initialized) {
return; return;
} }
initialized = true; initialized = 1;
/* /*
* finalize type information by extracting argument encoding information * finalize type information by extracting argument encoding information

View File

@ -154,7 +154,7 @@ static void ir_store_t(struct sh4_frontend *frontend, struct ir *ir,
struct ir_value *sr_t = ir_or(ir, sr, ir_alloc_i32(ir, T)); struct ir_value *sr_t = ir_or(ir, sr, ir_alloc_i32(ir, T));
struct ir_value *sr_not = ir_and(ir, sr, ir_alloc_i32(ir, ~T)); struct ir_value *sr_not = ir_and(ir, sr, ir_alloc_i32(ir, ~T));
struct ir_value *res = ir_select(ir, v, sr_t, sr_not); struct ir_value *res = ir_select(ir, v, sr_t, sr_not);
store_sr(res, false); store_sr(res, 0);
} }
static struct ir_value *ir_load_gbr(struct ir *ir) { static struct ir_value *ir_load_gbr(struct ir *ir) {
@ -734,7 +734,7 @@ EMITTER(DIV0U) {
ir_store_context(ir, offsetof(struct sh4_ctx, sr_qm), ir_store_context(ir, offsetof(struct sh4_ctx, sr_qm),
ir_alloc_i32(ir, 0x80000000)); ir_alloc_i32(ir, 0x80000000));
store_sr(ir_and(ir, load_sr(), ir_alloc_i32(ir, ~T)), false); store_sr(ir_and(ir, load_sr(), ir_alloc_i32(ir, ~T)), 0);
} }
// code cycles t-bit // code cycles t-bit
@ -1314,7 +1314,7 @@ EMITTER(CLRMAC) {
EMITTER(CLRS) { EMITTER(CLRS) {
struct ir_value *sr = load_sr(); struct ir_value *sr = load_sr();
sr = ir_and(ir, sr, ir_alloc_i32(ir, ~S)); sr = ir_and(ir, sr, ir_alloc_i32(ir, ~S));
store_sr(sr, true); store_sr(sr, 1);
} }
// code cycles t-bit // code cycles t-bit
@ -1327,7 +1327,7 @@ EMITTER(CLRT) {
// LDC Rm,SR // LDC Rm,SR
EMITTER(LDCSR) { EMITTER(LDCSR) {
struct ir_value *rm = load_gpr(i->Rm, VALUE_I32); struct ir_value *rm = load_gpr(i->Rm, VALUE_I32);
store_sr(rm, true); store_sr(rm, 1);
} }
// LDC Rm,GBR // LDC Rm,GBR
@ -1371,7 +1371,7 @@ EMITTER(LDCRBANK) {
EMITTER(LDCMSR) { EMITTER(LDCMSR) {
struct ir_value *addr = load_gpr(i->Rm, VALUE_I32); struct ir_value *addr = load_gpr(i->Rm, VALUE_I32);
struct ir_value *v = load_guest(addr, VALUE_I32); struct ir_value *v = load_guest(addr, VALUE_I32);
store_sr(v, true); store_sr(v, 1);
/* reload Rm, sr store could have swapped banks */ /* reload Rm, sr store could have swapped banks */
addr = load_gpr(i->Rm, VALUE_I32); addr = load_gpr(i->Rm, VALUE_I32);
addr = ir_add(ir, addr, ir_alloc_i32(ir, 4)); addr = ir_add(ir, addr, ir_alloc_i32(ir, 4));
@ -1518,7 +1518,7 @@ EMITTER(RTE) {
ir_load_context(ir, offsetof(struct sh4_ctx, spc), VALUE_I32); ir_load_context(ir, offsetof(struct sh4_ctx, spc), VALUE_I32);
struct ir_value *ssr = struct ir_value *ssr =
ir_load_context(ir, offsetof(struct sh4_ctx, ssr), VALUE_I32); ir_load_context(ir, offsetof(struct sh4_ctx, ssr), VALUE_I32);
store_sr(ssr, true); store_sr(ssr, 1);
emit_delay_instr(); emit_delay_instr();
branch(spc); branch(spc);
} }
@ -1526,7 +1526,7 @@ EMITTER(RTE) {
// SETS // SETS
EMITTER(SETS) { EMITTER(SETS) {
struct ir_value *sr = ir_or(ir, load_sr(), ir_alloc_i32(ir, S)); struct ir_value *sr = ir_or(ir, load_sr(), ir_alloc_i32(ir, S));
store_sr(sr, true); store_sr(sr, 1);
} }
// SETT // SETT

View File

@ -227,10 +227,6 @@ void ir_replace_uses(struct ir_value *v, struct ir_value *other) {
} }
} }
bool ir_is_constant(const struct ir_value *v) {
return !v->def;
}
uint64_t ir_zext_constant(const struct ir_value *v) { uint64_t ir_zext_constant(const struct ir_value *v) {
switch (v->type) { switch (v->type) {
case VALUE_I8: case VALUE_I8:

View File

@ -161,19 +161,23 @@ static inline int ir_type_size(enum ir_type type) {
} }
} }
static inline bool ir_is_int(enum ir_type type) { static inline int ir_is_int(enum ir_type type) {
return type == VALUE_I8 || type == VALUE_I16 || type == VALUE_I32 || return type == VALUE_I8 || type == VALUE_I16 || type == VALUE_I32 ||
type == VALUE_I64; type == VALUE_I64;
} }
static inline bool ir_is_float(enum ir_type type) { static inline int ir_is_float(enum ir_type type) {
return type == VALUE_F32 || type == VALUE_F64; return type == VALUE_F32 || type == VALUE_F64;
} }
static inline bool ir_is_vector(enum ir_type type) { static inline int ir_is_vector(enum ir_type type) {
return type == VALUE_V128; return type == VALUE_V128;
} }
static inline int ir_is_constant(const struct ir_value *v) {
return !v->def;
}
int ir_read(FILE *input, struct ir *ir); int ir_read(FILE *input, struct ir *ir);
void ir_write(struct ir *ir, FILE *output); void ir_write(struct ir *ir, FILE *output);
@ -202,7 +206,6 @@ void ir_set_arg2(struct ir *ir, struct ir_instr *instr, struct ir_value *v);
void ir_replace_use(struct ir_use *use, struct ir_value *other); void ir_replace_use(struct ir_use *use, struct ir_value *other);
void ir_replace_uses(struct ir_value *v, struct ir_value *other); void ir_replace_uses(struct ir_value *v, struct ir_value *other);
bool ir_is_constant(const struct ir_value *v);
uint64_t ir_zext_constant(const struct ir_value *v); uint64_t ir_zext_constant(const struct ir_value *v);
// direct access to host memory // direct access to host memory

View File

@ -17,8 +17,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
DEFINE_OPTION_BOOL(perf, false, DEFINE_OPTION_INT(perf, 0, "Generate perf-compatible maps for genrated code");
"Generate perf-compatible maps for genrated code");
struct jit_block { struct jit_block {
/* address of source block in guest memory */ /* address of source block in guest memory */

View File

@ -6,7 +6,7 @@
#include "sys/filesystem.h" #include "sys/filesystem.h"
#include "ui/window.h" #include "ui/window.h"
DEFINE_OPTION_BOOL(help, false, "Show help"); DEFINE_OPTION_INT(help, 0, "Show help");
int main(int argc, char **argv) { int main(int argc, char **argv) {
const char *appdir = fs_appdir(); const char *appdir = fs_appdir();

View File

@ -21,7 +21,7 @@ static const int FONT_WIDTH = 1024;
static const int FONT_HEIGHT = 9; static const int FONT_HEIGHT = 9;
#include "ui/microprofile_font.inc" #include "ui/microprofile_font.inc"
static const int MAX_2D_VERTICES = 16384; static const int MAX_2D_VERTICES = 32768;
static const int MAX_2D_SURFACES = 256; static const int MAX_2D_SURFACES = 256;
struct microprofile { struct microprofile {

View File

@ -15,6 +15,6 @@ recc [options] <path to file or directory>
### Options ### Options
``` ```
--pass Comma-separated list of passes to run [default: lse, dce, ra] --pass Comma-separated list of passes to run [default: lse, dce, ra]
--stats Print pass stats [default: true] --stats Print pass stats [default: 1]
--print_after_all Print IR after each pass [default: true] --print_after_all Print IR after each pass [default: 1]
``` ```

View File

@ -12,11 +12,11 @@
#include "jit/jit.h" #include "jit/jit.h"
#include "sys/filesystem.h" #include "sys/filesystem.h"
DEFINE_OPTION_BOOL(help, false, "Show help"); DEFINE_OPTION_INT(help, 0, "Show help");
DEFINE_OPTION_STRING(pass, "lse,cve,esimp,dce,ra", DEFINE_OPTION_STRING(pass, "lse,cve,esimp,dce,ra",
"Comma-separated list of passes to run"); "Comma-separated list of passes to run");
DEFINE_OPTION_BOOL(stats, true, "Print pass stats"); DEFINE_OPTION_INT(stats, 1, "Print pass stats");
DEFINE_OPTION_BOOL(print_after_all, true, "Print IR after each pass"); DEFINE_OPTION_INT(print_after_all, 1, "Print IR after each pass");
DEFINE_STAT(backend_size, "Backend code size"); DEFINE_STAT(backend_size, "Backend code size");
DEFINE_STAT(num_instrs, "Total instructions"); DEFINE_STAT(num_instrs, "Total instructions");
@ -39,7 +39,7 @@ static int get_num_instrs(const struct ir *ir) {
} }
static void process_file(struct jit *jit, const char *filename, static void process_file(struct jit *jit, const char *filename,
bool disable_ir_dump) { int disable_ir_dump) {
struct ir ir = {0}; struct ir ir = {0};
ir.buffer = ir_buffer; ir.buffer = ir_buffer;
ir.capacity = sizeof(ir_buffer); ir.capacity = sizeof(ir_buffer);
@ -121,7 +121,7 @@ static void process_dir(struct jit *jit, const char *path) {
LOG_INFO("Processing %s", filename); LOG_INFO("Processing %s", filename);
process_file(jit, filename, true); process_file(jit, filename, 1);
} }
closedir(dir); closedir(dir);
@ -144,7 +144,7 @@ int main(int argc, char **argv) {
CHECK(jit_init(jit, &guest, NULL, backend)); CHECK(jit_init(jit, &guest, NULL, backend));
if (fs_isfile(path)) { if (fs_isfile(path)) {
process_file(jit, path, false); process_file(jit, path, 0);
} else { } else {
process_dir(jit, path); process_dir(jit, path);
} }