mirror of https://github.com/inolen/redream.git
improved aica timer accuracy
improved accuracy of aggregate counters updated options in readme removed some bool usage
This commit is contained in:
parent
ae3d459960
commit
f0c7fe825e
12
README.md
12
README.md
|
@ -43,11 +43,13 @@ Command line flags are loaded from and saved to `$HOME/.redream/flags` each run.
|
|||
|
||||
### All options
|
||||
```
|
||||
--bios Path to BIOS [default: dc_boot.bin]
|
||||
--flash Path to flash ROM [default: dc_flash.bin]
|
||||
--debug Start GDB debug server
|
||||
--perf Write perf-compatible maps for generated code
|
||||
--profile Path to controller profile
|
||||
--bios Path to BIOS [default: dc_boot.bin]
|
||||
--flash Path to flash ROM [default: dc_flash.bin]
|
||||
--controller Path to controller profile
|
||||
--throttle Throttle emulation speed to match the original hardware [default: 1]
|
||||
--verbose Enable debug logging [default: 0]
|
||||
--perf Write perf-compatible maps for generated code [default: 0]
|
||||
--gdb Start GDB debug server [default: 0]
|
||||
```
|
||||
|
||||
### Debugging
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "core/debug_break.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)
|
||||
#define CHECK_EXPECT_TRUE(expr) (__builtin_expect(!!(expr), 1))
|
||||
#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 *expr, const char *unused);
|
||||
|
||||
// 3: VA_ARGS = format_check_error
|
||||
// 4+: VA_ARGS = format_check_error_ex
|
||||
/* 3: VA_ARGS = format_check_error */
|
||||
/* 4+: VA_ARGS = format_check_error_ex */
|
||||
#define SELECT_FORMAT_CHECK_ERROR(_1, _2, _3, _4, _5, _6, NAME, ...) NAME
|
||||
#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)(filename, linenum, expr, ##__VA_ARGS__))
|
||||
|
||||
// checks ran for all build configurations
|
||||
/* checks ran for all build configurations */
|
||||
#define CHECK_BINARY_OP(v1, v2, op, ...) \
|
||||
do { \
|
||||
if (!CHECK_EXPECT_TRUE((v1)op(v2))) { \
|
||||
|
@ -60,7 +60,7 @@ const char *format_check_error(const char *filename, int linenum,
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
// checks ran only for debug builds
|
||||
/* checks ran only for debug builds */
|
||||
#ifndef NDEBUG
|
||||
#define DCHECK_EQ(v1, v2, ...) CHECK_EQ(v1, v2, ##__VA_ARGS__)
|
||||
#define DCHECK_NE(v1, v2, ...) CHECK_NE(v1, v2, ##__VA_ARGS__)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#else
|
||||
|
||||
// not supported
|
||||
/* not supported */
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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) {
|
||||
list->tail = n;
|
||||
}
|
||||
|
@ -57,8 +57,8 @@ void list_clear(struct list *list) {
|
|||
list->head = list->tail = NULL;
|
||||
}
|
||||
|
||||
// Implements the mergesort for linked lists as described at
|
||||
// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html
|
||||
/* implements the mergesort for linked lists as described at
|
||||
http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html */
|
||||
void list_sort(struct list *list, list_node_cmp cmp) {
|
||||
struct list_node *head = list->head;
|
||||
struct list_node *tail = NULL;
|
||||
|
@ -72,10 +72,10 @@ void list_sort(struct list *list, list_node_cmp cmp) {
|
|||
tail = NULL;
|
||||
|
||||
while (p) {
|
||||
// track the number of lists merged this pass
|
||||
/* track the number of lists merged this pass */
|
||||
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 qsize = k;
|
||||
struct list_node *q = p;
|
||||
|
@ -84,8 +84,8 @@ void list_sort(struct list *list, list_node_cmp cmp) {
|
|||
q = q->next;
|
||||
}
|
||||
|
||||
// merge the list starting at p of length psize with the list starting
|
||||
// at q of at most, length qsize
|
||||
/* merge the list starting at p of length psize with the list starting
|
||||
at q of at most, length qsize */
|
||||
while (psize || (qsize && q)) {
|
||||
struct list_node *next;
|
||||
|
||||
|
@ -107,7 +107,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
|
|||
psize--;
|
||||
}
|
||||
|
||||
// move merged node to tail
|
||||
/* move merged node to tail */
|
||||
if (!tail) {
|
||||
head = next;
|
||||
} else {
|
||||
|
@ -124,7 +124,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
|
|||
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) {
|
||||
break;
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ void list_sort(struct list *list, list_node_cmp cmp) {
|
|||
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->tail = tail;
|
||||
}
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
#include <stdio.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, ...) {
|
||||
static char sbuffer[0x1000];
|
||||
int buffer_size = sizeof(sbuffer);
|
||||
char *buffer = sbuffer;
|
||||
|
||||
/* allocate a temporary buffer if need be to fit the string */
|
||||
va_list args;
|
||||
// allocate a temporary buffer if need be to fit the string
|
||||
va_start(args, format);
|
||||
int len = vsnprintf(0, 0, format, args);
|
||||
if (len >= buffer_size) {
|
||||
|
@ -40,7 +40,7 @@ void log_line(enum log_level level, const char *format, ...) {
|
|||
printf("%s\n", buffer);
|
||||
#endif
|
||||
|
||||
// cleanup the temporary buffer
|
||||
/* cleanup the temporary buffer */
|
||||
if (buffer != sbuffer) {
|
||||
free(buffer);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#include "core/debug_break.h"
|
||||
#include "core/option.h"
|
||||
|
||||
DECLARE_OPTION_BOOL(debug);
|
||||
DECLARE_OPTION_INT(verbose);
|
||||
|
||||
enum log_level {
|
||||
LOG_LEVEL_DEBUG,
|
||||
|
@ -25,7 +25,7 @@ enum log_level {
|
|||
void log_line(enum log_level level, const char *format, ...);
|
||||
|
||||
#define LOG_DEBUG(...) \
|
||||
if (OPTION_debug) { \
|
||||
if (OPTION_verbose) { \
|
||||
log_line(LOG_LEVEL_DEBUG, ##__VA_ARGS__); \
|
||||
}
|
||||
|
||||
|
|
|
@ -19,13 +19,15 @@ static struct option *options_find(const char *name) {
|
|||
|
||||
static void options_parse_value(struct option *opt, const char *value) {
|
||||
switch (opt->type) {
|
||||
case OPT_BOOL:
|
||||
*(bool *)opt->storage = strcmp(value, "false") && strcmp(value, "0");
|
||||
break;
|
||||
|
||||
case OPT_INT:
|
||||
*(int *)opt->storage = atoi(value);
|
||||
break;
|
||||
case OPT_INT: {
|
||||
if (!strcmp(value, "false")) {
|
||||
*(int *)opt->storage = 0;
|
||||
} else if (!strcmp(value, "true")) {
|
||||
*(int *)opt->storage = 1;
|
||||
} else {
|
||||
*(int *)opt->storage = atoi(value);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OPT_STRING:
|
||||
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];
|
||||
|
||||
switch (opt->type) {
|
||||
case OPT_BOOL:
|
||||
return *(bool *)opt->storage ? "true" : "false";
|
||||
|
||||
case OPT_INT:
|
||||
snprintf(value, sizeof(value), "%d", *(int *)opt->storage);
|
||||
return value;
|
||||
|
@ -65,7 +64,7 @@ void options_parse(int *argc, char ***argv) {
|
|||
for (int i = 1; i < end;) {
|
||||
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] != '-') {
|
||||
(*argv)[i] = (*argv)[end - 1];
|
||||
(*argv)[end - 1] = arg;
|
||||
|
@ -73,12 +72,12 @@ void options_parse(int *argc, char ***argv) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// chomp leading -
|
||||
/* chomp leading - */
|
||||
while (arg[0] == '-') {
|
||||
arg++;
|
||||
}
|
||||
|
||||
// terminate arg and extract value
|
||||
/* terminate arg and extract value */
|
||||
char *value = arg;
|
||||
|
||||
while (value[0] && value[0] != '=') {
|
||||
|
@ -89,7 +88,7 @@ void options_parse(int *argc, char ***argv) {
|
|||
*(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);
|
||||
|
||||
if (opt) {
|
||||
|
@ -114,15 +113,15 @@ static int options_ini_handler(void *user, const char *section,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool options_read(const char *filename) {
|
||||
int options_read(const char *filename) {
|
||||
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");
|
||||
|
||||
if (!output) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
list_for_each_entry(opt, &s_options, struct option, it) {
|
||||
|
@ -131,7 +130,7 @@ bool options_write(const char *filename) {
|
|||
|
||||
fclose(output);
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void options_print_help() {
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "core/constructor.h"
|
||||
#include "core/list.h"
|
||||
|
||||
#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 DEFINE_OPTION_INT(name, value, desc) \
|
||||
|
@ -54,7 +39,6 @@
|
|||
#define OPTION_HIDDEN NULL
|
||||
|
||||
enum option_type {
|
||||
OPT_BOOL,
|
||||
OPT_INT,
|
||||
OPT_STRING,
|
||||
};
|
||||
|
@ -71,8 +55,8 @@ void options_register(struct option *option);
|
|||
void options_unregister(struct option *option);
|
||||
|
||||
void options_parse(int *argc, char ***argv);
|
||||
bool options_read(const char *filename);
|
||||
bool options_write(const char *filename);
|
||||
int options_read(const char *filename);
|
||||
int options_write(const char *filename);
|
||||
|
||||
void options_print_help();
|
||||
|
||||
|
|
|
@ -103,9 +103,8 @@ prof_token_t prof_get_aggregate_token(const char *name) {
|
|||
return tok;
|
||||
}
|
||||
|
||||
void prof_flip() {
|
||||
/* flip aggregate counters every second */
|
||||
int64_t now = time_nanoseconds();
|
||||
void prof_update(int64_t now) {
|
||||
/* update time-based aggregate counters every second */
|
||||
int64_t next_aggregation = prof.last_aggregation + NS_PER_SEC;
|
||||
|
||||
if (now > next_aggregation) {
|
||||
|
@ -120,7 +119,10 @@ void prof_flip() {
|
|||
|
||||
prof.last_aggregation = now;
|
||||
}
|
||||
}
|
||||
|
||||
void prof_flip() {
|
||||
/* flip frame-based profile zones at the end of every frame */
|
||||
MicroProfileFlip();
|
||||
}
|
||||
|
||||
|
|
|
@ -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_set(prof_token_t tok, int64_t count);
|
||||
|
||||
/* called at the end of every frame to aggregate frame-based profile zones */
|
||||
void prof_flip();
|
||||
|
||||
/* called periodically to aggregate time-based aggregate counters */
|
||||
void prof_update(int64_t now);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/* would be nice to convert this file to C once MSVC supports stdatomic.h */
|
||||
#include <atomic>
|
||||
extern "C" {
|
||||
#include "core/ringbuf.h"
|
||||
#include "core/assert.h"
|
||||
#include "core/ringbuf.h"
|
||||
}
|
||||
|
||||
struct ringbuf {
|
||||
|
|
|
@ -40,8 +40,8 @@ int strnrep(char *dst, size_t dst_size, const char *token, size_t token_len,
|
|||
break;
|
||||
}
|
||||
|
||||
// move substring starting at the end of the token to the end of where the
|
||||
// new value will be)
|
||||
/* move substring starting at the end of the token to the end of where the
|
||||
new value will be) */
|
||||
size_t dst_len = strnlen(dst, dst_size);
|
||||
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);
|
||||
|
||||
// copy new value into token position
|
||||
/* copy new value into token position */
|
||||
memmove(ptr, value, value_len);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "emu/emulator.h"
|
||||
#include "core/option.h"
|
||||
#include "core/profiler.h"
|
||||
#include "hw/aica/aica.h"
|
||||
#include "hw/arm7/arm7.h"
|
||||
#include "hw/dreamcast.h"
|
||||
#include "hw/gdrom/gdrom.h"
|
||||
|
@ -15,6 +16,9 @@
|
|||
#include "ui/nuklear.h"
|
||||
#include "ui/window.h"
|
||||
|
||||
DEFINE_OPTION_INT(throttle, 1,
|
||||
"Throttle emulation speed to match the original hardware");
|
||||
|
||||
DEFINE_AGGREGATE_COUNTER(frames);
|
||||
|
||||
struct emu {
|
||||
|
@ -22,7 +26,6 @@ struct emu {
|
|||
struct window_listener listener;
|
||||
struct dreamcast *dc;
|
||||
int running;
|
||||
int throttled;
|
||||
|
||||
/* render state */
|
||||
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,
|
||||
nk_vec2(140.0f, 200.0f))) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -164,16 +167,23 @@ static void *emu_core_thread(void *data) {
|
|||
static const int64_t MACHINE_STEP = HZ_TO_NANO(1000);
|
||||
int64_t current_time = time_nanoseconds();
|
||||
int64_t next_time = current_time;
|
||||
int64_t delta_time = 0;
|
||||
|
||||
while (emu->running) {
|
||||
current_time = time_nanoseconds();
|
||||
|
||||
int64_t delta_time = current_time - next_time;
|
||||
|
||||
if (!emu->throttled || delta_time >= 0) {
|
||||
dc_tick(emu->dc, MACHINE_STEP);
|
||||
next_time = current_time + MACHINE_STEP;
|
||||
if (OPTION_throttle) {
|
||||
delta_time = current_time - next_time;
|
||||
} else {
|
||||
delta_time = 0;
|
||||
}
|
||||
|
||||
if (delta_time >= 0) {
|
||||
dc_tick(emu->dc, MACHINE_STEP);
|
||||
next_time = current_time + MACHINE_STEP - delta_time;
|
||||
}
|
||||
|
||||
prof_update(current_time);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -205,17 +215,17 @@ void emu_run(struct emu *emu, const char *path) {
|
|||
dc_resume(emu->dc);
|
||||
}
|
||||
|
||||
/* start core emulator thread */
|
||||
thread_t core_thread;
|
||||
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 */
|
||||
while (emu->running) {
|
||||
win_pump_events(emu->window);
|
||||
}
|
||||
|
||||
/* wait for the graphics thread to exit */
|
||||
/* wait for the core thread to exit */
|
||||
void *result;
|
||||
thread_join(core_thread, &result);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "hw/aica/aica.h"
|
||||
#include "core/log.h"
|
||||
#include "core/option.h"
|
||||
#include "core/profiler.h"
|
||||
#include "hw/aica/aica_types.h"
|
||||
#include "hw/arm7/arm7.h"
|
||||
#include "hw/dreamcast.h"
|
||||
|
@ -11,11 +12,13 @@
|
|||
|
||||
DEFINE_OPTION_INT(rtc, 0, OPTION_HIDDEN);
|
||||
|
||||
#define AICA_CLOCK_FREQ INT64_C(22579200)
|
||||
#define AICA_SAMPLE_FREQ INT64_C(44100)
|
||||
DEFINE_AGGREGATE_COUNTER(aica_samples);
|
||||
|
||||
#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_TIMER_PERIOD 0xff
|
||||
|
||||
struct aica_channel {
|
||||
struct channel_data *data;
|
||||
|
@ -36,25 +39,28 @@ struct aica {
|
|||
struct device;
|
||||
uint8_t reg[0x11000];
|
||||
uint8_t *wave_ram;
|
||||
|
||||
/* reset state */
|
||||
int arm_resetting;
|
||||
|
||||
/* interrupts */
|
||||
uint32_t arm_irq_l;
|
||||
uint32_t arm_irq_m;
|
||||
|
||||
/* timers */
|
||||
struct timer *timers[3];
|
||||
|
||||
/* real-time clock */
|
||||
struct timer *rtc_timer;
|
||||
int rtc_write;
|
||||
uint32_t rtc;
|
||||
|
||||
/* channels */
|
||||
struct common_data *common_data;
|
||||
struct aica_channel channels[AICA_NUM_CHANNELS];
|
||||
struct timer *sample_timer;
|
||||
};
|
||||
|
||||
/*
|
||||
* interrupts
|
||||
*/
|
||||
static void aica_raise_interrupt(struct aica *aica, int intr) {
|
||||
aica->common_data->MCIPD |= (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_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,
|
||||
uint32_t data_mask) {
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* channels
|
||||
*/
|
||||
static uint32_t aica_channel_step(struct aica_channel *ch) {
|
||||
uint32_t oct = ch->data->OCT;
|
||||
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;
|
||||
if (ca > ch->data->LEA) {
|
||||
if (ch->data->LPCTL) {
|
||||
LOG_INFO("aica_channel_step %d restart", ch - aica->channels);
|
||||
ch->offset = ch->data->LSA << AICA_SAMPLE_SHIFT;
|
||||
ch->looped = 1;
|
||||
} else {
|
||||
|
@ -349,6 +347,8 @@ static void aica_generate_samples(struct aica *aica, int samples) {
|
|||
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,
|
||||
|
@ -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) {
|
||||
if (addr < 0x2000) {
|
||||
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]);
|
||||
}
|
||||
|
||||
/*
|
||||
* device
|
||||
*/
|
||||
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);
|
||||
static void aica_next_sample(void *data) {
|
||||
struct aica *aica = data;
|
||||
|
||||
aica_generate_samples(aica, AICA_SAMPLE_BATCH);
|
||||
aica_raise_interrupt(aica, AICA_INT_SAMPLE);
|
||||
aica_update_arm(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) {
|
||||
|
@ -536,28 +532,27 @@ static bool aica_init(struct device *dev) {
|
|||
aica_timer_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;
|
||||
}
|
||||
|
||||
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 =
|
||||
dc_create_device(dc, sizeof(struct aica), "aica", &aica_init);
|
||||
|
||||
aica->execute_if = dc_create_execute_interface(&aica_run, 1);
|
||||
|
||||
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 */
|
||||
AM_BEGIN(struct aica, aica_reg_map);
|
||||
/* over-allocate to align with the host allocation granularity */
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
struct aica;
|
||||
struct dreamcast;
|
||||
|
||||
struct aica *aica_create(struct dreamcast *dc);
|
||||
void aica_destroy(struct aica *aica);
|
||||
|
||||
AM_DECLARE(aica_reg_map);
|
||||
AM_DECLARE(aica_data_map);
|
||||
|
||||
struct aica *aica_create(struct dreamcast *dc);
|
||||
void aica_destroy(struct aica *aica);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "hw/scheduler.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) {
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
|
|
|
@ -50,7 +50,7 @@ static int get_region_handle(page_entry_t page) {
|
|||
struct mirror_iterator {
|
||||
uint32_t base, mask, imask, step;
|
||||
uint32_t i, addr;
|
||||
bool first;
|
||||
int first;
|
||||
};
|
||||
|
||||
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->i = 0;
|
||||
it->addr = it->base;
|
||||
it->first = true;
|
||||
it->first = 1;
|
||||
}
|
||||
|
||||
static bool mirror_iterator_next(struct mirror_iterator *it) {
|
||||
/* first iteration just returns base */
|
||||
if (it->first) {
|
||||
it->first = false;
|
||||
return true;
|
||||
it->first = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* stop once mask complement is completely set */
|
||||
if ((it->addr & it->imask) == it->imask) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* step to the next permutation */
|
||||
|
@ -89,7 +89,7 @@ static bool mirror_iterator_next(struct mirror_iterator *it) {
|
|||
/* merge with the base */
|
||||
it->addr = it->base | it->i;
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool reserve_address_space(uint8_t **base) {
|
||||
|
@ -109,12 +109,12 @@ static bool reserve_address_space(uint8_t **base) {
|
|||
into it */
|
||||
release_pages(*base, ADDRESS_SPACE_SIZE);
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG_WARNING("Failed to reserve address space");
|
||||
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
memory->shmem =
|
||||
create_shared_memory("/redream", ADDRESS_SPACE_SIZE, ACC_READWRITE);
|
||||
|
||||
if (memory->shmem == SHMEM_INVALID) {
|
||||
LOG_WARNING("Failed to create shared memory object");
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool memory_init(struct memory *memory) {
|
||||
int memory_init(struct memory *memory) {
|
||||
if (!memory_create_shmem(memory)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* map each memory interface's address space */
|
||||
|
@ -225,15 +225,15 @@ bool memory_init(struct memory *memory) {
|
|||
|
||||
/* map raw address space */
|
||||
if (!reserve_address_space(&memory->shmem_base)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!map_shared_memory(memory->shmem, 0, memory->shmem_base,
|
||||
memory->shmem_size, ACC_READWRITE)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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,
|
||||
const struct address_map *map) {
|
||||
int as_map(struct address_space *space, const char *name,
|
||||
const struct address_map *map) {
|
||||
as_unmap(space);
|
||||
|
||||
/* 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
|
||||
|
||||
if (!reserve_address_space(&space->base)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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,
|
||||
ACC_READWRITE)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/* disable access to virtual address range for mmio regions, resulting in
|
||||
SIGSEGV on access */
|
||||
if (!map_shared_memory(space->dc->memory->shmem, 0, addr, size,
|
||||
ACC_NONE)) {
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
page_index += num_pages;
|
||||
}
|
||||
|
||||
return true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void as_destroy(struct address_space *space) {
|
||||
|
|
|
@ -51,7 +51,7 @@ struct memory;
|
|||
|
||||
struct memory *memory_create(struct dreamcast *dc);
|
||||
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,
|
||||
uint32_t offset);
|
||||
|
@ -186,8 +186,8 @@ struct address_space {
|
|||
struct address_space *as_create(struct dreamcast *dc);
|
||||
void as_destroy(struct address_space *space);
|
||||
|
||||
bool as_map(struct address_space *space, const char *name,
|
||||
const struct address_map *map);
|
||||
int as_map(struct address_space *space, const char *name,
|
||||
const struct address_map *map);
|
||||
void as_unmap(struct address_space *space);
|
||||
|
||||
void as_lookup(struct address_space *space, uint32_t addr,
|
||||
|
|
|
@ -8,9 +8,10 @@ struct dreamcast;
|
|||
struct timer;
|
||||
struct scheduler;
|
||||
|
||||
#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 CYCLES_TO_NANO(cycles, hz) (int64_t)((cycles / (float)hz) * NS_PER_SEC)
|
||||
#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 CYCLES_TO_NANO(cycles, hz) \
|
||||
(int64_t)(((cycles) / (float)(hz)) * NS_PER_SEC)
|
||||
|
||||
typedef void (*timer_cb)(void *);
|
||||
|
||||
|
|
|
@ -45,13 +45,13 @@ static void sh4_arg_mask(const char *instr_code, char c, uint16_t *mask,
|
|||
}
|
||||
|
||||
static void sh4_init_opdefs() {
|
||||
static bool initialized = false;
|
||||
static int initialized = 0;
|
||||
|
||||
if (initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
initialized = 1;
|
||||
|
||||
/*
|
||||
* finalize type information by extracting argument encoding information
|
||||
|
|
|
@ -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_not = ir_and(ir, sr, ir_alloc_i32(ir, ~T));
|
||||
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) {
|
||||
|
@ -734,7 +734,7 @@ EMITTER(DIV0U) {
|
|||
ir_store_context(ir, offsetof(struct sh4_ctx, sr_qm),
|
||||
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
|
||||
|
@ -1314,7 +1314,7 @@ EMITTER(CLRMAC) {
|
|||
EMITTER(CLRS) {
|
||||
struct ir_value *sr = load_sr();
|
||||
sr = ir_and(ir, sr, ir_alloc_i32(ir, ~S));
|
||||
store_sr(sr, true);
|
||||
store_sr(sr, 1);
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -1327,7 +1327,7 @@ EMITTER(CLRT) {
|
|||
// LDC Rm,SR
|
||||
EMITTER(LDCSR) {
|
||||
struct ir_value *rm = load_gpr(i->Rm, VALUE_I32);
|
||||
store_sr(rm, true);
|
||||
store_sr(rm, 1);
|
||||
}
|
||||
|
||||
// LDC Rm,GBR
|
||||
|
@ -1371,7 +1371,7 @@ EMITTER(LDCRBANK) {
|
|||
EMITTER(LDCMSR) {
|
||||
struct ir_value *addr = load_gpr(i->Rm, 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 */
|
||||
addr = load_gpr(i->Rm, VALUE_I32);
|
||||
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);
|
||||
struct ir_value *ssr =
|
||||
ir_load_context(ir, offsetof(struct sh4_ctx, ssr), VALUE_I32);
|
||||
store_sr(ssr, true);
|
||||
store_sr(ssr, 1);
|
||||
emit_delay_instr();
|
||||
branch(spc);
|
||||
}
|
||||
|
@ -1526,7 +1526,7 @@ EMITTER(RTE) {
|
|||
// SETS
|
||||
EMITTER(SETS) {
|
||||
struct ir_value *sr = ir_or(ir, load_sr(), ir_alloc_i32(ir, S));
|
||||
store_sr(sr, true);
|
||||
store_sr(sr, 1);
|
||||
}
|
||||
|
||||
// SETT
|
||||
|
|
|
@ -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) {
|
||||
switch (v->type) {
|
||||
case VALUE_I8:
|
||||
|
|
|
@ -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 ||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline bool ir_is_vector(enum ir_type type) {
|
||||
static inline int ir_is_vector(enum ir_type type) {
|
||||
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);
|
||||
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_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);
|
||||
|
||||
// direct access to host memory
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
DEFINE_OPTION_BOOL(perf, false,
|
||||
"Generate perf-compatible maps for genrated code");
|
||||
DEFINE_OPTION_INT(perf, 0, "Generate perf-compatible maps for genrated code");
|
||||
|
||||
struct jit_block {
|
||||
/* address of source block in guest memory */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#include "sys/filesystem.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) {
|
||||
const char *appdir = fs_appdir();
|
||||
|
|
|
@ -21,7 +21,7 @@ static const int FONT_WIDTH = 1024;
|
|||
static const int FONT_HEIGHT = 9;
|
||||
#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;
|
||||
|
||||
struct microprofile {
|
||||
|
|
|
@ -15,6 +15,6 @@ recc [options] <path to file or directory>
|
|||
### Options
|
||||
```
|
||||
--pass Comma-separated list of passes to run [default: lse, dce, ra]
|
||||
--stats Print pass stats [default: true]
|
||||
--print_after_all Print IR after each pass [default: true]
|
||||
--stats Print pass stats [default: 1]
|
||||
--print_after_all Print IR after each pass [default: 1]
|
||||
```
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
#include "jit/jit.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",
|
||||
"Comma-separated list of passes to run");
|
||||
DEFINE_OPTION_BOOL(stats, true, "Print pass stats");
|
||||
DEFINE_OPTION_BOOL(print_after_all, true, "Print IR after each pass");
|
||||
DEFINE_OPTION_INT(stats, 1, "Print pass stats");
|
||||
DEFINE_OPTION_INT(print_after_all, 1, "Print IR after each pass");
|
||||
|
||||
DEFINE_STAT(backend_size, "Backend code size");
|
||||
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,
|
||||
bool disable_ir_dump) {
|
||||
int disable_ir_dump) {
|
||||
struct ir ir = {0};
|
||||
ir.buffer = 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);
|
||||
|
||||
process_file(jit, filename, true);
|
||||
process_file(jit, filename, 1);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
@ -144,7 +144,7 @@ int main(int argc, char **argv) {
|
|||
CHECK(jit_init(jit, &guest, NULL, backend));
|
||||
|
||||
if (fs_isfile(path)) {
|
||||
process_file(jit, path, false);
|
||||
process_file(jit, path, 0);
|
||||
} else {
|
||||
process_dir(jit, path);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue