mirror of https://github.com/inolen/redream.git
remove cached device references on each device
remove device interface create routines
This commit is contained in:
parent
e17a21b1f2
commit
e06ce8fa71
|
@ -282,6 +282,7 @@ static uint32_t aica_encode_arm_irq_l(struct aica *aica, uint32_t intr) {
|
|||
}
|
||||
|
||||
static void aica_update_arm(struct aica *aica) {
|
||||
struct arm7 *arm7 = aica->dc->arm7;
|
||||
uint32_t enabled_intr = aica->common_data->SCIEB;
|
||||
uint32_t pending_intr = aica->common_data->SCIPD & enabled_intr;
|
||||
|
||||
|
@ -301,18 +302,19 @@ static void aica_update_arm(struct aica *aica) {
|
|||
|
||||
if (aica->common_data->L) {
|
||||
/* FIQ handler will load L from common data to check interrupt type */
|
||||
arm7_raise_interrupt(aica->arm7, ARM7_INT_FIQ);
|
||||
arm7_raise_interrupt(arm7, ARM7_INT_FIQ);
|
||||
}
|
||||
}
|
||||
|
||||
static void aica_update_sh(struct aica *aica) {
|
||||
struct holly *hl = aica->dc->holly;
|
||||
uint32_t enabled_intr = aica->common_data->MCIEB;
|
||||
uint32_t pending_intr = aica->common_data->MCIPD & enabled_intr;
|
||||
|
||||
if (pending_intr) {
|
||||
holly_raise_interrupt(aica->holly, HOLLY_INT_G2AICINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G2AICINT);
|
||||
} else {
|
||||
holly_clear_interrupt(aica->holly, HOLLY_INT_G2AICINT);
|
||||
holly_clear_interrupt(hl, HOLLY_INT_G2AICINT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,6 +351,7 @@ static uint32_t aica_timer_tctl(struct aica *aica, int n) {
|
|||
}
|
||||
|
||||
static uint32_t aica_timer_tcnt(struct aica *aica, int n) {
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
struct timer *timer = aica->timers[n];
|
||||
if (!timer) {
|
||||
/* if no timer has been created, return the raw value */
|
||||
|
@ -359,12 +362,13 @@ static uint32_t aica_timer_tcnt(struct aica *aica, int n) {
|
|||
/* else, dynamically compute the value based on the timer's remaining time */
|
||||
int tctl = aica_timer_tctl(aica, n);
|
||||
int64_t freq = AICA_SAMPLE_FREQ >> tctl;
|
||||
int64_t remaining = scheduler_remaining_time(aica->scheduler, timer);
|
||||
int64_t remaining = sched_remaining_time(sched, timer);
|
||||
int64_t cycles = NANO_TO_CYCLES(remaining, freq);
|
||||
return (uint32_t)cycles;
|
||||
}
|
||||
|
||||
static void aica_timer_reschedule(struct aica *aica, int n, uint32_t period) {
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
struct timer **timer = &aica->timers[n];
|
||||
|
||||
int64_t freq = AICA_SAMPLE_FREQ >> aica_timer_tctl(aica, n);
|
||||
|
@ -372,14 +376,13 @@ static void aica_timer_reschedule(struct aica *aica, int n, uint32_t period) {
|
|||
int64_t remaining = CYCLES_TO_NANO(cycles, freq);
|
||||
|
||||
if (*timer) {
|
||||
scheduler_cancel_timer(aica->scheduler, *timer);
|
||||
sched_cancel_timer(sched, *timer);
|
||||
*timer = NULL;
|
||||
}
|
||||
|
||||
static timer_cb timer_cbs[3] = {&aica_timer_expire_0, &aica_timer_expire_1,
|
||||
&aica_timer_expire_2};
|
||||
*timer =
|
||||
scheduler_start_timer(aica->scheduler, timer_cbs[n], aica, remaining);
|
||||
*timer = sched_start_timer(sched, timer_cbs[n], aica, remaining);
|
||||
}
|
||||
|
||||
static uint32_t aica_rtc_reg_read(struct aica *aica, uint32_t addr,
|
||||
|
@ -422,9 +425,9 @@ static void aica_rtc_reg_write(struct aica *aica, uint32_t addr, uint32_t data,
|
|||
|
||||
static void aica_rtc_timer(void *data) {
|
||||
struct aica *aica = data;
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
aica->rtc++;
|
||||
aica->rtc_timer =
|
||||
scheduler_start_timer(aica->scheduler, &aica_rtc_timer, aica, NS_PER_SEC);
|
||||
aica->rtc_timer = sched_start_timer(sched, &aica_rtc_timer, aica, NS_PER_SEC);
|
||||
}
|
||||
|
||||
static float aica_channel_hz(struct aica_channel *ch) {
|
||||
|
@ -750,6 +753,7 @@ static uint32_t aica_common_reg_read(struct aica *aica, uint32_t addr,
|
|||
|
||||
static void aica_common_reg_write(struct aica *aica, uint32_t addr,
|
||||
uint32_t data, uint32_t mask) {
|
||||
struct arm7 *arm7 = aica->dc->arm7;
|
||||
uint32_t old_data = READ_DATA((uint8_t *)aica->common_data + addr);
|
||||
WRITE_DATA((uint8_t *)aica->common_data + addr);
|
||||
|
||||
|
@ -807,11 +811,11 @@ static void aica_common_reg_write(struct aica *aica, uint32_t addr,
|
|||
if (aica->common_data->ARMRST) {
|
||||
/* suspend arm when reset is pulled low */
|
||||
aica->arm_resetting = 1;
|
||||
arm7_suspend(aica->arm7);
|
||||
arm7_suspend(arm7);
|
||||
} else if (aica->arm_resetting) {
|
||||
/* reset and resume arm when reset is released */
|
||||
aica->arm_resetting = 0;
|
||||
arm7_reset(aica->arm7);
|
||||
arm7_reset(arm7);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -833,6 +837,7 @@ static void aica_common_reg_write(struct aica *aica, uint32_t addr,
|
|||
|
||||
static void aica_next_sample(void *data) {
|
||||
struct aica *aica = data;
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
|
||||
aica_generate_frames(aica);
|
||||
aica_raise_interrupt(aica, AICA_INT_SAMPLE);
|
||||
|
@ -841,8 +846,8 @@ static void aica_next_sample(void *data) {
|
|||
|
||||
/* reschedule */
|
||||
aica->sample_timer =
|
||||
scheduler_start_timer(aica->scheduler, &aica_next_sample, aica,
|
||||
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_BATCH_SIZE));
|
||||
sched_start_timer(sched, &aica_next_sample, aica,
|
||||
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_BATCH_SIZE));
|
||||
}
|
||||
|
||||
static void aica_toggle_recording(struct aica *aica) {
|
||||
|
@ -865,9 +870,10 @@ static void aica_toggle_recording(struct aica *aica) {
|
|||
|
||||
static int aica_init(struct device *dev) {
|
||||
struct aica *aica = (struct aica *)dev;
|
||||
struct dreamcast *dc = aica->dc;
|
||||
struct memory *mem = aica->dc->mem;
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
|
||||
aica->aram = mem_aram(dc->mem, 0x0);
|
||||
aica->aram = mem_aram(mem, 0x0);
|
||||
|
||||
/* init channels */
|
||||
{
|
||||
|
@ -878,8 +884,8 @@ static int aica_init(struct device *dev) {
|
|||
}
|
||||
aica->common_data = (struct common_data *)(aica->reg + 0x2800);
|
||||
aica->sample_timer =
|
||||
scheduler_start_timer(aica->scheduler, &aica_next_sample, aica,
|
||||
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_BATCH_SIZE));
|
||||
sched_start_timer(sched, &aica_next_sample, aica,
|
||||
HZ_TO_NANO(AICA_SAMPLE_FREQ / AICA_BATCH_SIZE));
|
||||
}
|
||||
|
||||
/* init timers */
|
||||
|
@ -892,8 +898,8 @@ static int aica_init(struct device *dev) {
|
|||
/* init rtc */
|
||||
{
|
||||
/* increment clock every second */
|
||||
aica->rtc_timer = scheduler_start_timer(aica->scheduler, &aica_rtc_timer,
|
||||
aica, NS_PER_SEC);
|
||||
aica->rtc_timer =
|
||||
sched_start_timer(sched, &aica_rtc_timer, aica, NS_PER_SEC);
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -993,10 +999,12 @@ void aica_debug_menu(struct aica *aica) {
|
|||
#endif
|
||||
|
||||
void aica_destroy(struct aica *aica) {
|
||||
struct scheduler *sched = aica->dc->sched;
|
||||
|
||||
/* shutdown rtc */
|
||||
{
|
||||
if (aica->rtc_timer) {
|
||||
scheduler_cancel_timer(aica->scheduler, aica->rtc_timer);
|
||||
sched_cancel_timer(sched, aica->rtc_timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1004,7 +1012,7 @@ void aica_destroy(struct aica *aica) {
|
|||
{
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (aica->timers[i]) {
|
||||
scheduler_cancel_timer(aica->scheduler, aica->timers[i]);
|
||||
sched_cancel_timer(sched, aica->timers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1012,7 +1020,7 @@ void aica_destroy(struct aica *aica) {
|
|||
/* shutdown channels */
|
||||
{
|
||||
if (aica->sample_timer) {
|
||||
scheduler_cancel_timer(aica->scheduler, aica->sample_timer);
|
||||
sched_cancel_timer(sched, aica->sample_timer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -131,20 +131,24 @@ static void arm7_compile_code(struct arm7 *arm, uint32_t addr) {
|
|||
|
||||
void arm7_mem_write(struct arm7 *arm, uint32_t addr, uint32_t data,
|
||||
uint32_t mask) {
|
||||
struct aica *aica = arm->dc->aica;
|
||||
|
||||
if (/*addr >= ARM7_AICA_MEM_BEGIN &&*/ addr <= ARM7_AICA_MEM_END) {
|
||||
aica_mem_write(arm->aica, addr, data, mask);
|
||||
aica_mem_write(aica, addr, data, mask);
|
||||
} else if (addr >= ARM7_AICA_REG_BEGIN && addr <= ARM7_AICA_REG_END) {
|
||||
aica_reg_write(arm->aica, addr - ARM7_AICA_REG_BEGIN, data, mask);
|
||||
aica_reg_write(aica, addr - ARM7_AICA_REG_BEGIN, data, mask);
|
||||
} else {
|
||||
LOG_FATAL("arm7_mem_write addr=0x%08x", addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t arm7_mem_read(struct arm7 *arm, uint32_t addr, uint32_t mask) {
|
||||
struct aica *aica = arm->dc->aica;
|
||||
|
||||
if (/*addr >= ARM7_AICA_MEM_BEGIN &&*/ addr <= ARM7_AICA_MEM_END) {
|
||||
return aica_mem_read(arm->aica, addr, mask);
|
||||
return aica_mem_read(aica, addr, mask);
|
||||
} else if (addr >= ARM7_AICA_REG_BEGIN && addr <= ARM7_AICA_REG_END) {
|
||||
return aica_reg_read(arm->aica, addr - ARM7_AICA_REG_BEGIN, mask);
|
||||
return aica_reg_read(aica, addr - ARM7_AICA_REG_BEGIN, mask);
|
||||
} else {
|
||||
LOG_FATAL("arm7_mem_read addr=0x%08x", addr);
|
||||
}
|
||||
|
@ -168,11 +172,11 @@ void arm7_reset(struct arm7 *arm) {
|
|||
arm->ctx.r[R13_SVC] = 0x03007fe0;
|
||||
arm->ctx.r[CPSR] = F_MASK | MODE_SYS;
|
||||
|
||||
arm->execute_if->running = 1;
|
||||
arm->runif.running = 1;
|
||||
}
|
||||
|
||||
void arm7_suspend(struct arm7 *arm) {
|
||||
arm->execute_if->running = 0;
|
||||
arm->runif.running = 0;
|
||||
}
|
||||
|
||||
static void arm7_run(struct device *dev, int64_t ns) {
|
||||
|
@ -200,8 +204,8 @@ static struct jit_guest *arm7_guest_create(struct arm7 *arm) {
|
|||
|
||||
/* memory interface */
|
||||
guest->ctx = &arm->ctx;
|
||||
guest->membase = arm7_base(arm->mem);
|
||||
guest->mem = arm->mem;
|
||||
guest->membase = arm7_base(arm->dc->mem);
|
||||
guest->mem = arm->dc->mem;
|
||||
guest->lookup = &arm7_lookup;
|
||||
guest->r8 = &arm7_read8;
|
||||
guest->r16 = &arm7_read16;
|
||||
|
@ -265,15 +269,16 @@ void arm7_destroy(struct arm7 *arm) {
|
|||
arm7_guest_destroy(arm->guest);
|
||||
arm->frontend->destroy(arm->frontend);
|
||||
arm->backend->destroy(arm->backend);
|
||||
|
||||
dc_destroy_execute_interface(arm->execute_if);
|
||||
dc_destroy_device((struct device *)arm);
|
||||
}
|
||||
|
||||
struct arm7 *arm7_create(struct dreamcast *dc) {
|
||||
struct arm7 *arm =
|
||||
dc_create_device(dc, sizeof(struct arm7), "arm", &arm7_init, NULL);
|
||||
arm->execute_if = dc_create_execute_interface(&arm7_run, 0);
|
||||
|
||||
/* setup run interface */
|
||||
arm->runif.enabled = 1;
|
||||
arm->runif.run = &arm7_run;
|
||||
|
||||
return arm;
|
||||
}
|
||||
|
|
|
@ -32,30 +32,30 @@ static void debugger_gdb_server_resume(void *data) {
|
|||
|
||||
static void debugger_gdb_server_step(void *data) {
|
||||
struct debugger *dbg = data;
|
||||
dbg->dev->debug_if->step(dbg->dev);
|
||||
dbg->dev->dbgif.step(dbg->dev);
|
||||
}
|
||||
|
||||
static void debugger_gdb_server_add_bp(void *data, int type, intmax_t addr) {
|
||||
struct debugger *dbg = data;
|
||||
dbg->dev->debug_if->add_bp(dbg->dev, type, (uint32_t)addr);
|
||||
dbg->dev->dbgif.add_bp(dbg->dev, type, (uint32_t)addr);
|
||||
}
|
||||
|
||||
static void debugger_gdb_server_rem_bp(void *data, int type, intmax_t addr) {
|
||||
struct debugger *dbg = data;
|
||||
dbg->dev->debug_if->rem_bp(dbg->dev, type, (uint32_t)addr);
|
||||
dbg->dev->dbgif.rem_bp(dbg->dev, type, (uint32_t)addr);
|
||||
}
|
||||
|
||||
static void debugger_gdb_server_read_mem(void *data, intmax_t addr,
|
||||
uint8_t *buffer, int size) {
|
||||
struct debugger *dbg = data;
|
||||
dbg->dev->debug_if->read_mem(dbg->dev, (uint32_t)addr, buffer, size);
|
||||
dbg->dev->dbgif.read_mem(dbg->dev, (uint32_t)addr, buffer, size);
|
||||
}
|
||||
|
||||
static void debugger_gdb_server_read_reg(void *data, int n, intmax_t *value,
|
||||
int *size) {
|
||||
struct debugger *dbg = data;
|
||||
uint64_t v = 0;
|
||||
dbg->dev->debug_if->read_reg(dbg->dev, n, &v, size);
|
||||
dbg->dev->dbgif.read_reg(dbg->dev, n, &v, size);
|
||||
*value = v;
|
||||
}
|
||||
#endif
|
||||
|
@ -64,7 +64,7 @@ int debugger_init(struct debugger *dbg) {
|
|||
#ifdef HAVE_GDBSERVER
|
||||
/* use the first device found with a debug interface */
|
||||
list_for_each_entry(dev, &dbg->dc->devices, struct device, it) {
|
||||
if (dev->debug_if) {
|
||||
if (dev->dbgif.enabled) {
|
||||
dbg->dev = dev;
|
||||
break;
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ int debugger_init(struct debugger *dbg) {
|
|||
gdb_target_t target;
|
||||
target.ctx = dbg;
|
||||
target.endian = GDB_LITTLE_ENDIAN;
|
||||
target.num_regs = dbg->dev->debug_if->num_regs(dbg->dev);
|
||||
target.num_regs = dbg->dev->dbgif.num_regs(dbg->dev);
|
||||
target.detach = &debugger_gdb_server_detach;
|
||||
target.stop = &debugger_gdb_server_stop;
|
||||
target.resume = &debugger_gdb_server_resume;
|
||||
|
|
|
@ -63,6 +63,35 @@ void dc_push_audio(struct dreamcast *dc, const int16_t *data, int frames) {
|
|||
dc->push_audio(dc->userdata, data, frames);
|
||||
}
|
||||
|
||||
void dc_destroy_device(struct device *dev) {
|
||||
list_remove(&dev->dc->devices, &dev->it);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
struct device *dc_get_device(struct dreamcast *dc, const char *name) {
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
if (!strcmp(dev->name, name)) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init, device_post_init_cb post_init) {
|
||||
struct device *dev = calloc(1, size);
|
||||
|
||||
dev->dc = dc;
|
||||
dev->name = name;
|
||||
dev->init = init;
|
||||
dev->post_init = post_init;
|
||||
|
||||
list_add(&dc->devices, &dev->it);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void dc_input(struct dreamcast *dc, int port, int button, uint16_t value) {
|
||||
maple_handle_input(dc->maple, port, button, value);
|
||||
}
|
||||
|
@ -73,7 +102,7 @@ void dc_tick(struct dreamcast *dc, int64_t ns) {
|
|||
}
|
||||
|
||||
if (dc->running) {
|
||||
scheduler_tick(dc->scheduler, ns);
|
||||
sched_tick(dc->sched, ns);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,25 +186,6 @@ int dc_init(struct dreamcast *dc) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* cache references to other devices */
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
dev->debugger = dc->debugger;
|
||||
dev->mem = dc->mem;
|
||||
dev->scheduler = dc->scheduler;
|
||||
dev->bios = dc->bios;
|
||||
dev->sh4 = dc->sh4;
|
||||
dev->arm7 = dc->arm7;
|
||||
dev->aica = dc->aica;
|
||||
dev->bios = dc->bios;
|
||||
dev->boot = dc->boot;
|
||||
dev->flash = dc->flash;
|
||||
dev->gdrom = dc->gdrom;
|
||||
dev->holly = dc->holly;
|
||||
dev->maple = dc->maple;
|
||||
dev->pvr = dc->pvr;
|
||||
dev->ta = dc->ta;
|
||||
}
|
||||
|
||||
/* initialize each device */
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
if (dev->init && !dev->init(dev)) {
|
||||
|
@ -194,68 +204,6 @@ int dc_init(struct dreamcast *dc) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void dc_destroy_execute_interface(struct execute_interface *execute) {
|
||||
free(execute);
|
||||
}
|
||||
|
||||
struct execute_interface *dc_create_execute_interface(device_run_cb run,
|
||||
int running) {
|
||||
struct execute_interface *execute =
|
||||
calloc(1, sizeof(struct execute_interface));
|
||||
execute->run = run;
|
||||
execute->running = running;
|
||||
return execute;
|
||||
}
|
||||
|
||||
void dc_destroy_debug_interface(struct debug_interface *dbg) {
|
||||
free(dbg);
|
||||
}
|
||||
|
||||
struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs,
|
||||
device_step_cb step,
|
||||
device_add_bp_cb add_bp,
|
||||
device_rem_bp_cb rem_bp,
|
||||
device_read_mem_cb read_mem,
|
||||
device_read_reg_cb read_reg) {
|
||||
struct debug_interface *dbg = calloc(1, sizeof(struct debug_interface));
|
||||
dbg->num_regs = num_regs;
|
||||
dbg->step = step;
|
||||
dbg->add_bp = add_bp;
|
||||
dbg->rem_bp = rem_bp;
|
||||
dbg->read_mem = read_mem;
|
||||
dbg->read_reg = read_reg;
|
||||
return dbg;
|
||||
}
|
||||
|
||||
void dc_destroy_device(struct device *dev) {
|
||||
list_remove(&dev->dc->devices, &dev->it);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
struct device *dc_get_device(struct dreamcast *dc, const char *name) {
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
if (!strcmp(dev->name, name)) {
|
||||
return dev;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init, device_post_init_cb post_init) {
|
||||
struct device *dev = calloc(1, size);
|
||||
|
||||
dev->dc = dc;
|
||||
dev->name = name;
|
||||
dev->init = init;
|
||||
dev->post_init = post_init;
|
||||
|
||||
list_add(&dc->devices, &dev->it);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void dc_destroy(struct dreamcast *dc) {
|
||||
ta_destroy(dc->ta);
|
||||
pvr_destroy(dc->pvr);
|
||||
|
@ -268,7 +216,7 @@ void dc_destroy(struct dreamcast *dc) {
|
|||
arm7_destroy(dc->arm7);
|
||||
sh4_destroy(dc->sh4);
|
||||
bios_destroy(dc->bios);
|
||||
scheduler_destroy(dc->scheduler);
|
||||
sched_destroy(dc->sched);
|
||||
mem_destroy(dc->mem);
|
||||
if (dc->debugger) {
|
||||
debugger_destroy(dc->debugger);
|
||||
|
@ -284,7 +232,7 @@ struct dreamcast *dc_create() {
|
|||
dc->debugger = debugger_create(dc);
|
||||
#endif
|
||||
dc->mem = mem_create(dc);
|
||||
dc->scheduler = scheduler_create(dc);
|
||||
dc->sched = sched_create(dc);
|
||||
dc->bios = bios_create(dc);
|
||||
dc->sh4 = sh4_create(dc);
|
||||
dc->arm7 = arm7_create(dc);
|
||||
|
|
|
@ -62,7 +62,8 @@ typedef void (*device_rem_bp_cb)(struct device *, int, uint32_t);
|
|||
typedef void (*device_read_mem_cb)(struct device *, uint32_t, uint8_t *, int);
|
||||
typedef void (*device_read_reg_cb)(struct device *, int, uint64_t *, int *);
|
||||
|
||||
struct debug_interface {
|
||||
struct dbgif {
|
||||
int enabled;
|
||||
device_num_regs_cb num_regs;
|
||||
device_step_cb step;
|
||||
device_add_bp_cb add_bp;
|
||||
|
@ -71,12 +72,13 @@ struct debug_interface {
|
|||
device_read_reg_cb read_reg;
|
||||
};
|
||||
|
||||
/* execute interface */
|
||||
/* run interface */
|
||||
typedef void (*device_run_cb)(struct device *, int64_t);
|
||||
|
||||
struct execute_interface {
|
||||
device_run_cb run;
|
||||
struct runif {
|
||||
int enabled;
|
||||
int running;
|
||||
device_run_cb run;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -99,24 +101,8 @@ struct device {
|
|||
device_post_init_cb post_init;
|
||||
|
||||
/* optional interfaces */
|
||||
struct debug_interface *debug_if;
|
||||
struct execute_interface *execute_if;
|
||||
|
||||
/* cached references to other devices */
|
||||
struct debugger *debugger;
|
||||
struct memory *mem;
|
||||
struct scheduler *scheduler;
|
||||
struct bios *bios;
|
||||
struct sh4 *sh4;
|
||||
struct arm7 *arm7;
|
||||
struct aica *aica;
|
||||
struct boot *boot;
|
||||
struct flash *flash;
|
||||
struct gdrom *gdrom;
|
||||
struct holly *holly;
|
||||
struct maple *maple;
|
||||
struct pvr *pvr;
|
||||
struct ta *ta;
|
||||
struct dbgif dbgif;
|
||||
struct runif runif;
|
||||
|
||||
struct list_node it;
|
||||
};
|
||||
|
@ -137,7 +123,7 @@ struct dreamcast {
|
|||
/* systems */
|
||||
struct debugger *debugger;
|
||||
struct memory *mem;
|
||||
struct scheduler *scheduler;
|
||||
struct scheduler *sched;
|
||||
|
||||
/* devices */
|
||||
struct bios *bios;
|
||||
|
@ -166,23 +152,6 @@ struct dreamcast {
|
|||
struct dreamcast *dc_create();
|
||||
void dc_destroy(struct dreamcast *dc);
|
||||
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init, device_post_init_cb post_init);
|
||||
struct device *dc_get_device(struct dreamcast *dc, const char *name);
|
||||
void dc_destroy_device(struct device *dev);
|
||||
|
||||
struct debug_interface *dc_create_debug_interface(device_num_regs_cb num_regs,
|
||||
device_step_cb step,
|
||||
device_add_bp_cb add_bp,
|
||||
device_rem_bp_cb rem_bp,
|
||||
device_read_mem_cb read_mem,
|
||||
device_read_reg_cb read_reg);
|
||||
void dc_destroy_debug_interface(struct debug_interface *dbg);
|
||||
|
||||
struct execute_interface *dc_create_execute_interface(device_run_cb run,
|
||||
int running);
|
||||
void dc_destroy_execute_interface(struct execute_interface *execute);
|
||||
|
||||
int dc_init(struct dreamcast *dc);
|
||||
int dc_load(struct dreamcast *dc, const char *path);
|
||||
int dc_running(struct dreamcast *dc);
|
||||
|
@ -191,7 +160,13 @@ void dc_resume(struct dreamcast *dc);
|
|||
void dc_tick(struct dreamcast *dc, int64_t ns);
|
||||
void dc_input(struct dreamcast *dc, int port, int button, uint16_t value);
|
||||
|
||||
/* client functionality */
|
||||
/* device registration */
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init, device_post_init_cb post_init);
|
||||
struct device *dc_get_device(struct dreamcast *dc, const char *name);
|
||||
void dc_destroy_device(struct device *dev);
|
||||
|
||||
/* client interface */
|
||||
void dc_push_audio(struct dreamcast *dc, const int16_t *data, int frames);
|
||||
void dc_push_pixels(struct dreamcast *dc, const uint8_t *data, int w, int h);
|
||||
void dc_start_render(struct dreamcast *dc, struct ta_context *ctx);
|
||||
|
|
|
@ -101,18 +101,22 @@ static int gdrom_get_fad(uint8_t a, uint8_t b, uint8_t c, int msf) {
|
|||
}
|
||||
|
||||
static void gdrom_spi_end(struct gdrom *gd) {
|
||||
struct holly *hl = gd->dc->holly;
|
||||
|
||||
gd->ireason.IO = 1;
|
||||
gd->ireason.CoD = 1;
|
||||
gd->status.DRDY = 1;
|
||||
gd->status.BSY = 0;
|
||||
gd->status.DRQ = 0;
|
||||
|
||||
holly_raise_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
|
||||
gd->state = STATE_READ_ATA_CMD;
|
||||
}
|
||||
|
||||
static void gdrom_spi_cdread(struct gdrom *gd) {
|
||||
struct holly *hl = gd->dc->holly;
|
||||
|
||||
if (gd->cdr_dma) {
|
||||
int max_dma_sectors = sizeof(gd->dma_buffer) / DISC_MAX_SECTOR_SIZE;
|
||||
|
||||
|
@ -150,13 +154,15 @@ static void gdrom_spi_cdread(struct gdrom *gd) {
|
|||
gd->status.DRQ = 1;
|
||||
gd->status.BSY = 0;
|
||||
|
||||
holly_raise_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
|
||||
gd->state = STATE_WRITE_SPI_DATA;
|
||||
}
|
||||
}
|
||||
|
||||
static void gdrom_spi_read(struct gdrom *gd, int offset, int size) {
|
||||
struct holly *hl = gd->dc->holly;
|
||||
|
||||
gd->cdr_num_sectors = 0;
|
||||
|
||||
gd->pio_head = 0;
|
||||
|
@ -169,12 +175,14 @@ static void gdrom_spi_read(struct gdrom *gd, int offset, int size) {
|
|||
gd->status.DRQ = 1;
|
||||
gd->status.BSY = 0;
|
||||
|
||||
holly_raise_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
|
||||
gd->state = STATE_READ_SPI_DATA;
|
||||
}
|
||||
|
||||
static void gdrom_spi_write(struct gdrom *gd, void *data, int size) {
|
||||
struct holly *hl = gd->dc->holly;
|
||||
|
||||
gd->cdr_num_sectors = 0;
|
||||
|
||||
CHECK(size < (int)sizeof(gd->pio_buffer));
|
||||
|
@ -188,16 +196,18 @@ static void gdrom_spi_write(struct gdrom *gd, void *data, int size) {
|
|||
gd->status.DRQ = 1;
|
||||
gd->status.BSY = 0;
|
||||
|
||||
holly_raise_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
|
||||
gd->state = STATE_WRITE_SPI_DATA;
|
||||
}
|
||||
|
||||
static void gdrom_ata_end(struct gdrom *gd) {
|
||||
struct holly *hl = gd->dc->holly;
|
||||
|
||||
gd->status.DRDY = 1;
|
||||
gd->status.BSY = 0;
|
||||
|
||||
holly_raise_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
|
||||
gd->state = STATE_READ_ATA_CMD;
|
||||
}
|
||||
|
@ -833,9 +843,10 @@ REG_W32(holly_cb, GD_DRVSEL) {
|
|||
|
||||
REG_R32(holly_cb, GD_STATUS_COMMAND) {
|
||||
struct gdrom *gd = dc->gdrom;
|
||||
struct holly *hl = dc->holly;
|
||||
uint16_t value = gd->status.full;
|
||||
LOG_GDROM("read GD_STATUS 0x%x", value);
|
||||
holly_clear_interrupt(gd->holly, HOLLY_INT_G1GDINT);
|
||||
holly_clear_interrupt(hl, HOLLY_INT_G1GDINT);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,11 +23,13 @@ static void holly_ch2_dma_stop(struct holly *hl) {
|
|||
}
|
||||
|
||||
static void holly_ch2_dma(struct holly *hl) {
|
||||
struct sh4 *sh4 = hl->dc->sh4;
|
||||
|
||||
struct sh4_dtr dtr = {0};
|
||||
dtr.channel = 2;
|
||||
dtr.dir = SH4_DMA_TO_ADDR;
|
||||
dtr.addr = *hl->SB_C2DSTAT;
|
||||
sh4_dmac_ddt(hl->sh4, &dtr);
|
||||
sh4_dmac_ddt(sh4, &dtr);
|
||||
|
||||
*hl->SB_C2DLEN = 0;
|
||||
*hl->SB_C2DST = 0;
|
||||
|
@ -43,8 +45,8 @@ static void holly_gdrom_dma(struct holly *hl) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct gdrom *gd = hl->gdrom;
|
||||
struct sh4 *sh4 = hl->sh4;
|
||||
struct gdrom *gd = hl->dc->gdrom;
|
||||
struct sh4 *sh4 = hl->dc->sh4;
|
||||
|
||||
/* only gdrom -> sh4 supported for now */
|
||||
CHECK_EQ(*hl->SB_GDDIR, 1);
|
||||
|
@ -92,26 +94,27 @@ static void holly_maple_dma(struct holly *hl) {
|
|||
return;
|
||||
}
|
||||
|
||||
struct maple *mp = hl->maple;
|
||||
struct memory *mem = hl->dc->mem;
|
||||
struct maple *mp = hl->dc->maple;
|
||||
uint32_t addr = *hl->SB_MDSTAR;
|
||||
|
||||
while (1) {
|
||||
union maple_transfer desc;
|
||||
desc.full = sh4_read32(hl->mem, addr);
|
||||
desc.full = sh4_read32(mem, addr);
|
||||
addr += 4;
|
||||
|
||||
switch (desc.pattern) {
|
||||
case MAPLE_PATTERN_NORMAL: {
|
||||
uint32_t result_addr = sh4_read32(hl->mem, addr);
|
||||
uint32_t result_addr = sh4_read32(mem, addr);
|
||||
addr += 4;
|
||||
|
||||
/* read message */
|
||||
struct maple_frame frame, res;
|
||||
frame.header.full = sh4_read32(hl->mem, addr);
|
||||
frame.header.full = sh4_read32(mem, addr);
|
||||
addr += 4;
|
||||
|
||||
for (uint32_t i = 0; i < frame.header.num_words; i++) {
|
||||
frame.params[i] = sh4_read32(hl->mem, addr);
|
||||
frame.params[i] = sh4_read32(mem, addr);
|
||||
addr += 4;
|
||||
}
|
||||
|
||||
|
@ -120,15 +123,15 @@ static void holly_maple_dma(struct holly *hl) {
|
|||
|
||||
/* write response */
|
||||
if (handled) {
|
||||
sh4_write32(hl->mem, result_addr, res.header.full);
|
||||
sh4_write32(mem, result_addr, res.header.full);
|
||||
result_addr += 4;
|
||||
|
||||
for (uint32_t i = 0; i < res.header.num_words; i++) {
|
||||
sh4_write32(hl->mem, result_addr, res.params[i]);
|
||||
sh4_write32(mem, result_addr, res.params[i]);
|
||||
result_addr += 4;
|
||||
}
|
||||
} else {
|
||||
sh4_write32(hl->mem, result_addr, 0xffffffff);
|
||||
sh4_write32(mem, result_addr, 0xffffffff);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -168,10 +171,12 @@ static void (*g2_timers[4])(void *);
|
|||
#define DEFINE_G2_DMA_TIMER(ch) \
|
||||
static void holly_g2_dma_timer_channel##ch(void *data) { \
|
||||
struct holly *hl = data; \
|
||||
struct memory *mem = hl->dc->mem; \
|
||||
struct scheduler *sched = hl->dc->sched; \
|
||||
struct holly_g2_dma *dma = &hl->dma[ch]; \
|
||||
int chunk_size = 0x1000; \
|
||||
int n = MIN(dma->len, chunk_size); \
|
||||
sh4_memcpy(hl->mem, dma->dst, dma->src, n); \
|
||||
sh4_memcpy(mem, dma->dst, dma->src, n); \
|
||||
dma->dst += n; \
|
||||
dma->src += n; \
|
||||
dma->len -= n; \
|
||||
|
@ -183,7 +188,7 @@ static void (*g2_timers[4])(void *);
|
|||
} \
|
||||
/* g2 bus runs at 16-bits x 25mhz, loosely simulate this */ \
|
||||
int64_t end = CYCLES_TO_NANO(chunk_size / 2, UINT64_C(25000000)); \
|
||||
scheduler_start_timer(hl->scheduler, g2_timers[ch], hl, end); \
|
||||
sched_start_timer(sched, g2_timers[ch], hl, end); \
|
||||
}
|
||||
|
||||
DEFINE_G2_DMA_TIMER(0);
|
||||
|
@ -231,15 +236,17 @@ static void holly_g2_dma(struct holly *hl, int ch) {
|
|||
}
|
||||
|
||||
static void holly_update_interrupts(struct holly *hl) {
|
||||
struct sh4 *sh4 = hl->dc->sh4;
|
||||
|
||||
/* trigger the respective level-encoded interrupt on the sh4 interrupt
|
||||
controller */
|
||||
{
|
||||
if ((*hl->SB_ISTNRM & *hl->SB_IML6NRM) ||
|
||||
(*hl->SB_ISTERR & *hl->SB_IML6ERR) ||
|
||||
(*hl->SB_ISTEXT & *hl->SB_IML6EXT)) {
|
||||
sh4_raise_interrupt(hl->sh4, SH4_INT_IRL_9);
|
||||
sh4_raise_interrupt(sh4, SH4_INT_IRL_9);
|
||||
} else {
|
||||
sh4_clear_interrupt(hl->sh4, SH4_INT_IRL_9);
|
||||
sh4_clear_interrupt(sh4, SH4_INT_IRL_9);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,9 +254,9 @@ static void holly_update_interrupts(struct holly *hl) {
|
|||
if ((*hl->SB_ISTNRM & *hl->SB_IML4NRM) ||
|
||||
(*hl->SB_ISTERR & *hl->SB_IML4ERR) ||
|
||||
(*hl->SB_ISTEXT & *hl->SB_IML4EXT)) {
|
||||
sh4_raise_interrupt(hl->sh4, SH4_INT_IRL_11);
|
||||
sh4_raise_interrupt(sh4, SH4_INT_IRL_11);
|
||||
} else {
|
||||
sh4_clear_interrupt(hl->sh4, SH4_INT_IRL_11);
|
||||
sh4_clear_interrupt(sh4, SH4_INT_IRL_11);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,9 +264,9 @@ static void holly_update_interrupts(struct holly *hl) {
|
|||
if ((*hl->SB_ISTNRM & *hl->SB_IML2NRM) ||
|
||||
(*hl->SB_ISTERR & *hl->SB_IML2ERR) ||
|
||||
(*hl->SB_ISTEXT & *hl->SB_IML2EXT)) {
|
||||
sh4_raise_interrupt(hl->sh4, SH4_INT_IRL_13);
|
||||
sh4_raise_interrupt(sh4, SH4_INT_IRL_13);
|
||||
} else {
|
||||
sh4_clear_interrupt(hl->sh4, SH4_INT_IRL_13);
|
||||
sh4_clear_interrupt(sh4, SH4_INT_IRL_13);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,6 +199,8 @@ static void pvr_vblank_in(struct pvr *pvr) {
|
|||
|
||||
static void pvr_next_scanline(void *data) {
|
||||
struct pvr *pvr = data;
|
||||
struct holly *hl = pvr->dc->holly;
|
||||
struct scheduler *sched = pvr->dc->sched;
|
||||
|
||||
uint32_t num_lines = pvr->SPG_LOAD->vcount + 1;
|
||||
pvr->current_line = (pvr->current_line + 1) % num_lines;
|
||||
|
@ -207,11 +209,11 @@ static void pvr_next_scanline(void *data) {
|
|||
switch (pvr->SPG_HBLANK_INT->hblank_int_mode) {
|
||||
case 0x0:
|
||||
if (pvr->current_line == pvr->SPG_HBLANK_INT->line_comp_val) {
|
||||
holly_raise_interrupt(pvr->holly, HOLLY_INT_PCHIINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCHIINT);
|
||||
}
|
||||
break;
|
||||
case 0x2:
|
||||
holly_raise_interrupt(pvr->holly, HOLLY_INT_PCHIINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCHIINT);
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("unsupported hblank interrupt mode");
|
||||
|
@ -220,12 +222,12 @@ static void pvr_next_scanline(void *data) {
|
|||
|
||||
/* vblank in */
|
||||
if (pvr->current_line == pvr->SPG_VBLANK_INT->vblank_in_line_number) {
|
||||
holly_raise_interrupt(pvr->holly, HOLLY_INT_PCVIINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCVIINT);
|
||||
}
|
||||
|
||||
/* vblank out */
|
||||
if (pvr->current_line == pvr->SPG_VBLANK_INT->vblank_out_line_number) {
|
||||
holly_raise_interrupt(pvr->holly, HOLLY_INT_PCVOINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCVOINT);
|
||||
}
|
||||
|
||||
int was_vsync = pvr->SPG_STATUS->vsync;
|
||||
|
@ -245,11 +247,13 @@ static void pvr_next_scanline(void *data) {
|
|||
}
|
||||
|
||||
/* reschedule */
|
||||
pvr->line_timer = scheduler_start_timer(pvr->scheduler, &pvr_next_scanline,
|
||||
pvr, HZ_TO_NANO(pvr->line_clock));
|
||||
pvr->line_timer = sched_start_timer(sched, &pvr_next_scanline, pvr,
|
||||
HZ_TO_NANO(pvr->line_clock));
|
||||
}
|
||||
|
||||
static void pvr_reconfigure_spg(struct pvr *pvr) {
|
||||
struct scheduler *sched = pvr->dc->sched;
|
||||
|
||||
/* scale pixel clock frequency */
|
||||
int pixel_clock = 13500000;
|
||||
if (pvr->FB_R_CTRL->vclk_div) {
|
||||
|
@ -277,12 +281,12 @@ static void pvr_reconfigure_spg(struct pvr *pvr) {
|
|||
pvr->SPG_VBLANK->vbstart, pvr->SPG_VBLANK->vbend);
|
||||
|
||||
if (pvr->line_timer) {
|
||||
scheduler_cancel_timer(pvr->scheduler, pvr->line_timer);
|
||||
sched_cancel_timer(sched, pvr->line_timer);
|
||||
pvr->line_timer = NULL;
|
||||
}
|
||||
|
||||
pvr->line_timer = scheduler_start_timer(pvr->scheduler, &pvr_next_scanline,
|
||||
pvr, HZ_TO_NANO(pvr->line_clock));
|
||||
pvr->line_timer = sched_start_timer(sched, &pvr_next_scanline, pvr,
|
||||
HZ_TO_NANO(pvr->line_clock));
|
||||
}
|
||||
|
||||
static int pvr_init(struct device *dev) {
|
||||
|
@ -404,19 +408,24 @@ struct pvr *pvr_create(struct dreamcast *dc) {
|
|||
|
||||
REG_W32(pvr_cb, SOFTRESET) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
if (!(value & 0x1)) {
|
||||
return;
|
||||
}
|
||||
ta_soft_reset(pvr->ta);
|
||||
|
||||
ta_soft_reset(ta);
|
||||
}
|
||||
|
||||
REG_W32(pvr_cb, STARTRENDER) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
ta_start_render(pvr->ta);
|
||||
ta_start_render(ta);
|
||||
|
||||
pvr_mark_framebuffer(pvr, *pvr->FB_W_SOF1);
|
||||
pvr_mark_framebuffer(pvr, *pvr->FB_W_SOF2);
|
||||
|
@ -425,34 +434,47 @@ REG_W32(pvr_cb, STARTRENDER) {
|
|||
|
||||
REG_W32(pvr_cb, TA_LIST_INIT) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
if (!(value & 0x80000000)) {
|
||||
return;
|
||||
}
|
||||
ta_list_init(pvr->ta);
|
||||
|
||||
ta_list_init(ta);
|
||||
}
|
||||
|
||||
REG_W32(pvr_cb, TA_LIST_CONT) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
if (!(value & 0x80000000)) {
|
||||
return;
|
||||
}
|
||||
ta_list_cont(pvr->ta);
|
||||
|
||||
ta_list_cont(ta);
|
||||
}
|
||||
|
||||
REG_W32(pvr_cb, TA_YUV_TEX_BASE) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
struct ta *ta = dc->ta;
|
||||
|
||||
pvr->TA_YUV_TEX_BASE->full = value;
|
||||
ta_yuv_init(pvr->ta);
|
||||
|
||||
ta_yuv_init(ta);
|
||||
}
|
||||
|
||||
REG_W32(pvr_cb, SPG_LOAD) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
|
||||
pvr->SPG_LOAD->full = value;
|
||||
|
||||
pvr_reconfigure_spg(pvr);
|
||||
}
|
||||
|
||||
REG_W32(pvr_cb, FB_R_CTRL) {
|
||||
struct pvr *pvr = dc->pvr;
|
||||
|
||||
pvr->FB_R_CTRL->full = value;
|
||||
|
||||
pvr_reconfigure_spg(pvr);
|
||||
}
|
||||
|
|
|
@ -407,6 +407,8 @@ static void ta_init_context(struct ta *ta, struct ta_context *ctx) {
|
|||
|
||||
static void ta_write_context(struct ta *ta, struct ta_context *ctx,
|
||||
const void *ptr, int size) {
|
||||
struct holly *hl = ta->dc->holly;
|
||||
|
||||
CHECK_LT(ctx->size + size, (int)sizeof(ctx->params));
|
||||
memcpy(&ctx->params[ctx->size], ptr, size);
|
||||
ctx->size += size;
|
||||
|
@ -436,7 +438,7 @@ static void ta_write_context(struct ta *ta, struct ta_context *ctx,
|
|||
/* it's common that a TA_PARAM_END_OF_LIST is sent before a valid list
|
||||
type has been set */
|
||||
if (ctx->list_type != TA_NUM_LISTS) {
|
||||
holly_raise_interrupt(ta->holly, list_interrupts[ctx->list_type]);
|
||||
holly_raise_interrupt(hl, list_interrupts[ctx->list_type]);
|
||||
}
|
||||
ctx->list_type = TA_NUM_LISTS;
|
||||
ctx->vert_type = TA_NUM_VERTS;
|
||||
|
@ -481,12 +483,13 @@ static void ta_write_context(struct ta *ta, struct ta_context *ctx,
|
|||
* level in order to squeeze out extra free performance
|
||||
*/
|
||||
static void ta_save_state(struct ta *ta, struct ta_context *ctx) {
|
||||
struct pvr *pvr = ta->pvr;
|
||||
struct memory *mem = ta->dc->mem;
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
|
||||
/* autosort */
|
||||
if (pvr->FPU_PARAM_CFG->region_header_type) {
|
||||
/* region array data type 2 */
|
||||
uint32_t region_data = sh4_read32(ta->mem, 0x05000000 + *pvr->REGION_BASE);
|
||||
uint32_t region_data = sh4_read32(mem, 0x05000000 + *pvr->REGION_BASE);
|
||||
ctx->autosort = !(region_data & 0x20000000);
|
||||
} else {
|
||||
/* region array data type 1 */
|
||||
|
@ -516,9 +519,9 @@ static void ta_save_state(struct ta *ta, struct ta_context *ctx) {
|
|||
((ctx->addr + pvr->ISP_BACKGND_T->tag_address * 4) & 0x7fffff);
|
||||
|
||||
/* get surface parameters */
|
||||
ctx->bg_isp.full = sh4_read32(ta->mem, vram_offset);
|
||||
ctx->bg_tsp.full = sh4_read32(ta->mem, vram_offset + 4);
|
||||
ctx->bg_tcw.full = sh4_read32(ta->mem, vram_offset + 8);
|
||||
ctx->bg_isp.full = sh4_read32(mem, vram_offset);
|
||||
ctx->bg_tsp.full = sh4_read32(mem, vram_offset + 4);
|
||||
ctx->bg_tcw.full = sh4_read32(mem, vram_offset + 8);
|
||||
vram_offset += 12;
|
||||
|
||||
/* get the background depth */
|
||||
|
@ -542,7 +545,7 @@ static void ta_save_state(struct ta *ta, struct ta_context *ctx) {
|
|||
for (int i = 0, bg_offset = 0; i < 3; i++) {
|
||||
CHECK_LE(bg_offset + vertex_size, (int)sizeof(ctx->bg_vertices));
|
||||
|
||||
sh4_memcpy_to_host(ta->mem, &ctx->bg_vertices[bg_offset], vram_offset,
|
||||
sh4_memcpy_to_host(mem, &ctx->bg_vertices[bg_offset], vram_offset,
|
||||
vertex_size);
|
||||
|
||||
bg_offset += vertex_size;
|
||||
|
@ -553,6 +556,7 @@ static void ta_save_state(struct ta *ta, struct ta_context *ctx) {
|
|||
static void ta_render_context_end(void *data) {
|
||||
struct ta_context *ctx = data;
|
||||
struct ta *ta = ctx->userdata;
|
||||
struct holly *hl = ta->dc->holly;
|
||||
|
||||
/* ensure the client has finished rendering */
|
||||
dc_finish_render(ta->dc);
|
||||
|
@ -561,12 +565,14 @@ static void ta_render_context_end(void *data) {
|
|||
ta_free_context(ta, ctx);
|
||||
|
||||
/* let the game know rendering is complete */
|
||||
holly_raise_interrupt(ta->holly, HOLLY_INT_PCEOVINT);
|
||||
holly_raise_interrupt(ta->holly, HOLLY_INT_PCEOIINT);
|
||||
holly_raise_interrupt(ta->holly, HOLLY_INT_PCEOTINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCEOVINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCEOIINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_PCEOTINT);
|
||||
}
|
||||
|
||||
static void ta_render_context(struct ta *ta, struct ta_context *ctx) {
|
||||
struct scheduler *sched = ta->dc->sched;
|
||||
|
||||
prof_counter_add(COUNTER_ta_renders, 1);
|
||||
|
||||
/* remove context from pool */
|
||||
|
@ -583,7 +589,7 @@ static void ta_render_context(struct ta *ta, struct ta_context *ctx) {
|
|||
TODO figure out a heuristic involving the number of polygons rendered */
|
||||
int64_t end = INT64_C(10000000);
|
||||
ctx->userdata = ta;
|
||||
scheduler_start_timer(ta->scheduler, &ta_render_context_end, ctx, end);
|
||||
sched_start_timer(sched, &ta_render_context_end, ctx, end);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -595,7 +601,7 @@ static void ta_render_context(struct ta *ta, struct ta_context *ctx) {
|
|||
MAX(TA_YUV420_MACROBLOCK_SIZE, TA_YUV422_MACROBLOCK_SIZE)
|
||||
|
||||
static void ta_yuv_reset(struct ta *ta) {
|
||||
struct pvr *pvr = ta->pvr;
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
|
||||
/* FIXME only YUV420 -> YUV422 supported for now */
|
||||
CHECK_EQ(pvr->TA_YUV_TEX_CTRL->format, 0);
|
||||
|
@ -657,7 +663,8 @@ static void ta_yuv_process_block(struct ta *ta, const uint8_t *in_uv,
|
|||
}
|
||||
|
||||
static void ta_yuv_process_macroblock(struct ta *ta, const void *data) {
|
||||
struct pvr *pvr = ta->pvr;
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
struct holly *hl = ta->dc->holly;
|
||||
|
||||
/* YUV420 data comes in as a series 16x16 macroblocks that need to be
|
||||
converted into a single UYVY422 texture */
|
||||
|
@ -685,7 +692,7 @@ static void ta_yuv_process_macroblock(struct ta *ta, const void *data) {
|
|||
ta_yuv_reset(ta);
|
||||
|
||||
/* raise DMA end interrupt */
|
||||
holly_raise_interrupt(ta->holly, HOLLY_INT_TAYUVINT);
|
||||
holly_raise_interrupt(hl, HOLLY_INT_TAYUVINT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -756,19 +763,19 @@ void ta_init_tables() {
|
|||
*/
|
||||
void ta_texture_write(struct ta *ta, uint32_t dst, const uint8_t *src,
|
||||
int size) {
|
||||
struct holly *holly = ta->holly;
|
||||
struct holly *hl = ta->dc->holly;
|
||||
|
||||
CHECK(*holly->SB_LMMODE0 == 0);
|
||||
CHECK(*hl->SB_LMMODE0 == 0);
|
||||
|
||||
dst &= 0xeeffffff;
|
||||
memcpy(&ta->vram[dst], src, size);
|
||||
}
|
||||
|
||||
void ta_yuv_write(struct ta *ta, uint32_t dst, const uint8_t *src, int size) {
|
||||
struct holly *holly = ta->holly;
|
||||
struct pvr *pvr = ta->pvr;
|
||||
struct holly *hl = ta->dc->holly;
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
|
||||
CHECK(*holly->SB_LMMODE0 == 0);
|
||||
CHECK(*hl->SB_LMMODE0 == 0);
|
||||
CHECK(size % ta->yuv_macroblock_size == 0);
|
||||
|
||||
const uint8_t *end = src + size;
|
||||
|
@ -779,9 +786,9 @@ void ta_yuv_write(struct ta *ta, uint32_t dst, const uint8_t *src, int size) {
|
|||
}
|
||||
|
||||
void ta_poly_write(struct ta *ta, uint32_t dst, const uint8_t *src, int size) {
|
||||
struct holly *holly = ta->holly;
|
||||
struct holly *hl = ta->dc->holly;
|
||||
|
||||
CHECK(*holly->SB_LMMODE0 == 0);
|
||||
CHECK(*hl->SB_LMMODE0 == 0);
|
||||
CHECK(size % 32 == 0);
|
||||
|
||||
const uint8_t *end = src + size;
|
||||
|
@ -794,11 +801,13 @@ void ta_poly_write(struct ta *ta, uint32_t dst, const uint8_t *src, int size) {
|
|||
void ta_texture_info(struct ta *ta, union tsp tsp, union tcw tcw,
|
||||
const uint8_t **texture, int *texture_size,
|
||||
const uint8_t **palette, int *palette_size) {
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
|
||||
uint32_t texture_addr = ta_texture_addr(tsp, tcw, texture_size);
|
||||
*texture = &ta->vram[texture_addr];
|
||||
|
||||
uint32_t palette_addr = ta_palette_addr(tcw, palette_size);
|
||||
uint8_t *palette_ram = (uint8_t *)ta->pvr->PALETTE_RAM000 + palette_addr;
|
||||
uint8_t *palette_ram = (uint8_t *)pvr->PALETTE_RAM000 + palette_addr;
|
||||
*palette = *palette_size ? palette_ram : NULL;
|
||||
}
|
||||
|
||||
|
@ -807,23 +816,24 @@ void ta_yuv_init(struct ta *ta) {
|
|||
}
|
||||
|
||||
void ta_list_cont(struct ta *ta) {
|
||||
struct ta_context *ctx =
|
||||
ta_get_context(ta, ta->pvr->TA_ISP_BASE->base_address);
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
struct ta_context *ctx = ta_get_context(ta, pvr->TA_ISP_BASE->base_address);
|
||||
CHECK_NOTNULL(ctx);
|
||||
ta_cont_context(ta, ctx);
|
||||
ta->curr_context = ctx;
|
||||
}
|
||||
|
||||
void ta_list_init(struct ta *ta) {
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
struct ta_context *ctx =
|
||||
ta_demand_context(ta, ta->pvr->TA_ISP_BASE->base_address);
|
||||
ta_demand_context(ta, pvr->TA_ISP_BASE->base_address);
|
||||
ta_init_context(ta, ctx);
|
||||
ta->curr_context = ctx;
|
||||
}
|
||||
|
||||
void ta_start_render(struct ta *ta) {
|
||||
struct ta_context *ctx =
|
||||
ta_get_context(ta, ta->pvr->PARAM_BASE->base_address);
|
||||
struct pvr *pvr = ta->dc->pvr;
|
||||
struct ta_context *ctx = ta_get_context(ta, pvr->PARAM_BASE->base_address);
|
||||
CHECK_NOTNULL(ctx);
|
||||
ta_render_context(ta, ctx);
|
||||
}
|
||||
|
|
|
@ -22,36 +22,36 @@ struct scheduler {
|
|||
int64_t base_time;
|
||||
};
|
||||
|
||||
void scheduler_cancel_timer(struct scheduler *sch, struct timer *timer) {
|
||||
void sched_cancel_timer(struct scheduler *sched, struct timer *timer) {
|
||||
if (!timer->active) {
|
||||
return;
|
||||
}
|
||||
|
||||
timer->active = 0;
|
||||
list_remove(&sch->live_timers, &timer->it);
|
||||
list_add(&sch->free_timers, &timer->it);
|
||||
list_remove(&sched->live_timers, &timer->it);
|
||||
list_add(&sched->free_timers, &timer->it);
|
||||
}
|
||||
|
||||
int64_t scheduler_remaining_time(struct scheduler *sch, struct timer *timer) {
|
||||
return timer->expire - sch->base_time;
|
||||
int64_t sched_remaining_time(struct scheduler *sched, struct timer *timer) {
|
||||
return timer->expire - sched->base_time;
|
||||
}
|
||||
|
||||
struct timer *scheduler_start_timer(struct scheduler *sch, timer_cb cb,
|
||||
void *data, int64_t ns) {
|
||||
struct timer *timer = list_first_entry(&sch->free_timers, struct timer, it);
|
||||
struct timer *sched_start_timer(struct scheduler *sched, timer_cb cb,
|
||||
void *data, int64_t ns) {
|
||||
struct timer *timer = list_first_entry(&sched->free_timers, struct timer, it);
|
||||
CHECK_NOTNULL(timer);
|
||||
timer->active = 1;
|
||||
timer->expire = sch->base_time + ns;
|
||||
timer->expire = sched->base_time + ns;
|
||||
timer->cb = cb;
|
||||
timer->data = data;
|
||||
|
||||
/* remove from free list */
|
||||
list_remove(&sch->free_timers, &timer->it);
|
||||
list_remove(&sched->free_timers, &timer->it);
|
||||
|
||||
/* add to sorted live list */
|
||||
struct list_node *after = NULL;
|
||||
|
||||
list_for_each(&sch->live_timers, it) {
|
||||
list_for_each(&sched->live_timers, it) {
|
||||
struct timer *entry = list_entry(it, struct timer, it);
|
||||
|
||||
if (entry->expire > timer->expire) {
|
||||
|
@ -61,19 +61,19 @@ struct timer *scheduler_start_timer(struct scheduler *sch, timer_cb cb,
|
|||
after = it;
|
||||
}
|
||||
|
||||
list_add_after(&sch->live_timers, after, &timer->it);
|
||||
list_add_after(&sched->live_timers, after, &timer->it);
|
||||
|
||||
return timer;
|
||||
}
|
||||
|
||||
void scheduler_tick(struct scheduler *sch, int64_t ns) {
|
||||
int64_t target_time = sch->base_time + ns;
|
||||
void sched_tick(struct scheduler *sched, int64_t ns) {
|
||||
int64_t target_time = sched->base_time + ns;
|
||||
|
||||
while (sch->dc->running && sch->base_time < target_time) {
|
||||
while (sched->dc->running && sched->base_time < target_time) {
|
||||
/* run devices up to the next timer */
|
||||
int64_t next_time = target_time;
|
||||
struct timer *next_timer =
|
||||
list_first_entry(&sch->live_timers, struct timer, it);
|
||||
list_first_entry(&sched->live_timers, struct timer, it);
|
||||
|
||||
if (next_timer && next_timer->expire < next_time) {
|
||||
next_time = next_timer->expire;
|
||||
|
@ -81,26 +81,26 @@ void scheduler_tick(struct scheduler *sch, int64_t ns) {
|
|||
|
||||
/* update base time before running devices and expiring timers in case one
|
||||
of them schedules a new timer */
|
||||
int64_t slice = next_time - sch->base_time;
|
||||
sch->base_time += slice;
|
||||
int64_t slice = next_time - sched->base_time;
|
||||
sched->base_time += slice;
|
||||
|
||||
/* execute each device */
|
||||
list_for_each_entry(dev, &sch->dc->devices, struct device, it) {
|
||||
if (dev->execute_if && dev->execute_if->running) {
|
||||
dev->execute_if->run(dev, slice);
|
||||
list_for_each_entry(dev, &sched->dc->devices, struct device, it) {
|
||||
if (dev->runif.enabled && dev->runif.running) {
|
||||
dev->runif.run(dev, slice);
|
||||
}
|
||||
}
|
||||
|
||||
/* execute expired timers */
|
||||
while (1) {
|
||||
struct timer *timer =
|
||||
list_first_entry(&sch->live_timers, struct timer, it);
|
||||
list_first_entry(&sched->live_timers, struct timer, it);
|
||||
|
||||
if (!timer || timer->expire > sch->base_time) {
|
||||
if (!timer || timer->expire > sched->base_time) {
|
||||
break;
|
||||
}
|
||||
|
||||
scheduler_cancel_timer(sch, timer);
|
||||
sched_cancel_timer(sched, timer);
|
||||
|
||||
/* run the timer */
|
||||
timer->cb(timer->data);
|
||||
|
@ -108,21 +108,20 @@ void scheduler_tick(struct scheduler *sch, int64_t ns) {
|
|||
}
|
||||
}
|
||||
|
||||
void scheduler_destroy(struct scheduler *sch) {
|
||||
void sched_destroy(struct scheduler *sch) {
|
||||
free(sch);
|
||||
}
|
||||
|
||||
struct scheduler *scheduler_create(struct dreamcast *dc) {
|
||||
struct scheduler *sch = calloc(1, sizeof(struct scheduler));
|
||||
struct scheduler *sched_create(struct dreamcast *dc) {
|
||||
struct scheduler *sched = calloc(1, sizeof(struct scheduler));
|
||||
|
||||
sch->dc = dc;
|
||||
sched->dc = dc;
|
||||
|
||||
/* add all timers to the free list initially */
|
||||
for (int i = 0; i < MAX_TIMERS; i++) {
|
||||
struct timer *timer = &sch->timers[i];
|
||||
|
||||
list_add(&sch->free_timers, &timer->it);
|
||||
struct timer *timer = &sched->timers[i];
|
||||
list_add(&sched->free_timers, &timer->it);
|
||||
}
|
||||
|
||||
return sch;
|
||||
return sched;
|
||||
}
|
||||
|
|
|
@ -15,14 +15,14 @@ struct scheduler;
|
|||
|
||||
typedef void (*timer_cb)(void *);
|
||||
|
||||
struct scheduler *scheduler_create(struct dreamcast *dc);
|
||||
void scheduler_destroy(struct scheduler *sch);
|
||||
struct scheduler *sched_create(struct dreamcast *dc);
|
||||
void sched_destroy(struct scheduler *sch);
|
||||
|
||||
void scheduler_tick(struct scheduler *sch, int64_t ns);
|
||||
void sched_tick(struct scheduler *sch, int64_t ns);
|
||||
|
||||
struct timer *scheduler_start_timer(struct scheduler *sch, timer_cb cb,
|
||||
void *data, int64_t ns);
|
||||
int64_t scheduler_remaining_time(struct scheduler *sch, struct timer *);
|
||||
void scheduler_cancel_timer(struct scheduler *sch, struct timer *);
|
||||
struct timer *sched_start_timer(struct scheduler *sch, timer_cb cb, void *data,
|
||||
int64_t ns);
|
||||
int64_t sched_remaining_time(struct scheduler *sch, struct timer *);
|
||||
void sched_cancel_timer(struct scheduler *sch, struct timer *);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,9 @@ static void sh4_compile_code(struct sh4 *sh4, uint32_t addr) {
|
|||
}
|
||||
|
||||
static void sh4_invalid_instr(struct sh4 *sh4) {
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
struct bios *bios = sh4->dc->bios;
|
||||
|
||||
/* TODO write tests to confirm if any other instructions generate illegal
|
||||
instruction exceptions */
|
||||
const uint16_t SH4_INVALID_INSTR = 0xfffd;
|
||||
|
@ -125,7 +128,7 @@ static void sh4_invalid_instr(struct sh4 *sh4) {
|
|||
/* let internal systems have a first chance at illegal instructions. note,
|
||||
they will write out invalid instructions other than SH4_INVALID_INSTR
|
||||
in order to trap */
|
||||
if (bios_invalid_instr(sh4->bios)) {
|
||||
if (bios_invalid_instr(bios)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -134,13 +137,13 @@ static void sh4_invalid_instr(struct sh4 *sh4) {
|
|||
}
|
||||
|
||||
uint32_t pc = sh4->ctx.pc;
|
||||
uint16_t data = sh4_read16(sh4->mem, pc);
|
||||
uint16_t data = sh4_read16(mem, pc);
|
||||
struct jit_opdef *def = sh4_get_opdef(data);
|
||||
enum sh4_exception exc = SH4_EXC_ILLINSTR;
|
||||
|
||||
/* op may be valid if the delay slot raised this */
|
||||
if (def->op != SH4_OP_INVALID) {
|
||||
data = sh4_read16(sh4->mem, pc + 2);
|
||||
data = sh4_read16(mem, pc + 2);
|
||||
def = sh4_get_opdef(data);
|
||||
exc = SH4_EXC_ILLSLOT;
|
||||
}
|
||||
|
@ -179,8 +182,8 @@ static struct jit_guest *sh4_guest_create(struct sh4 *sh4) {
|
|||
|
||||
/* memory interface */
|
||||
guest->ctx = &sh4->ctx;
|
||||
guest->membase = sh4_base(sh4->mem);
|
||||
guest->mem = sh4->mem;
|
||||
guest->membase = sh4_base(sh4->dc->mem);
|
||||
guest->mem = sh4->dc->mem;
|
||||
guest->lookup = &sh4_lookup;
|
||||
guest->r8 = &sh4_read8;
|
||||
guest->r16 = &sh4_read16;
|
||||
|
@ -268,7 +271,7 @@ void sh4_reset(struct sh4 *sh4, uint32_t pc) {
|
|||
/* reset interrupts */
|
||||
sh4_intc_reprioritize(sh4);
|
||||
|
||||
sh4->execute_if->running = 1;
|
||||
sh4->runif.running = 1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_IMGUI
|
||||
|
@ -309,19 +312,25 @@ void sh4_destroy(struct sh4 *sh4) {
|
|||
sh4_guest_destroy(sh4->guest);
|
||||
sh4->frontend->destroy(sh4->frontend);
|
||||
sh4->backend->destroy(sh4->backend);
|
||||
|
||||
dc_destroy_execute_interface(sh4->execute_if);
|
||||
dc_destroy_debug_interface(sh4->debug_if);
|
||||
dc_destroy_device((struct device *)sh4);
|
||||
}
|
||||
|
||||
struct sh4 *sh4_create(struct dreamcast *dc) {
|
||||
struct sh4 *sh4 =
|
||||
dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init, NULL);
|
||||
sh4->debug_if = dc_create_debug_interface(
|
||||
&sh4_dbg_num_registers, &sh4_dbg_step, &sh4_dbg_add_breakpoint,
|
||||
&sh4_dbg_remove_breakpoint, &sh4_dbg_read_memory, &sh4_dbg_read_register);
|
||||
sh4->execute_if = dc_create_execute_interface(&sh4_run, 0);
|
||||
|
||||
/* setup debug interface */
|
||||
sh4->dbgif.enabled = 1;
|
||||
sh4->dbgif.num_regs = &sh4_dbg_num_registers;
|
||||
sh4->dbgif.step = &sh4_dbg_step;
|
||||
sh4->dbgif.add_bp = &sh4_dbg_add_breakpoint;
|
||||
sh4->dbgif.rem_bp = &sh4_dbg_remove_breakpoint;
|
||||
sh4->dbgif.read_mem = &sh4_dbg_read_memory;
|
||||
sh4->dbgif.read_reg = &sh4_dbg_read_register;
|
||||
|
||||
/* setup run interface */
|
||||
sh4->runif.enabled = 1;
|
||||
sh4->runif.run = &sh4_run;
|
||||
|
||||
return sh4;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ static void sh4_ccn_reset(struct sh4 *sh4) {
|
|||
}
|
||||
|
||||
void sh4_ccn_pref(struct sh4 *sh4, uint32_t addr) {
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
/* make sure this is a sq related prefetch */
|
||||
DCHECK(addr >= 0xe0000000 && addr <= 0xe3ffffff);
|
||||
|
||||
|
@ -55,7 +57,7 @@ void sh4_ccn_pref(struct sh4 *sh4, uint32_t addr) {
|
|||
dst |= addr & 0x3ffffe0;
|
||||
}
|
||||
|
||||
sh4_memcpy_to_guest(sh4->mem, dst, sh4->ctx.sq[sqi], 32);
|
||||
sh4_memcpy_to_guest(mem, dst, sh4->ctx.sq[sqi], 32);
|
||||
}
|
||||
|
||||
uint32_t sh4_ccn_cache_read(struct sh4 *sh4, uint32_t addr, uint32_t mask) {
|
||||
|
|
|
@ -96,20 +96,22 @@ void sh4_dbg_read_register(struct device *dev, int n, uint64_t *value,
|
|||
void sh4_dbg_read_memory(struct device *dev, uint32_t addr, uint8_t *buffer,
|
||||
int size) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
while (size--) {
|
||||
*(buffer++) = sh4_read8(sh4->mem, addr++);
|
||||
*(buffer++) = sh4_read8(mem, addr++);
|
||||
}
|
||||
}
|
||||
|
||||
void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
struct breakpoint *bp = lookup_breakpoint(sh4, addr);
|
||||
CHECK_NOTNULL(bp);
|
||||
|
||||
/* restore the original instruction */
|
||||
sh4_write16(sh4->mem, addr, bp->instr);
|
||||
sh4_write16(mem, addr, bp->instr);
|
||||
|
||||
/* free code cache to remove block containing the invalid instruction */
|
||||
jit_free_code(sh4->jit);
|
||||
|
@ -119,12 +121,13 @@ void sh4_dbg_remove_breakpoint(struct device *dev, int type, uint32_t addr) {
|
|||
|
||||
void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
uint16_t instr = sh4_read16(sh4->mem, addr);
|
||||
uint16_t instr = sh4_read16(mem, addr);
|
||||
struct breakpoint *bp = create_breakpoint(sh4, addr, instr);
|
||||
|
||||
/* write out an invalid instruction */
|
||||
sh4_write16(sh4->mem, addr, 0);
|
||||
sh4_write16(mem, addr, 0);
|
||||
|
||||
/* free code cache to remove block containing the original instruction */
|
||||
jit_free_code(sh4->jit);
|
||||
|
@ -132,9 +135,10 @@ void sh4_dbg_add_breakpoint(struct device *dev, int type, uint32_t addr) {
|
|||
|
||||
void sh4_dbg_step(struct device *dev) {
|
||||
struct sh4 *sh4 = (struct sh4 *)dev;
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
/* run the fallback handler for the current pc */
|
||||
uint16_t data = sh4_read16(sh4->mem, sh4->ctx.pc);
|
||||
uint16_t data = sh4_read16(mem, sh4->ctx.pc);
|
||||
struct jit_opdef *def = sh4_get_opdef(data);
|
||||
def->fallback((struct jit_guest *)sh4->guest, sh4->ctx.pc, data);
|
||||
|
||||
|
|
|
@ -27,15 +27,17 @@ static void sh4_dmac_check(struct sh4 *sh4, int channel) {
|
|||
}
|
||||
|
||||
void sh4_dmac_ddt(struct sh4 *sh4, struct sh4_dtr *dtr) {
|
||||
struct memory *mem = sh4->dc->mem;
|
||||
|
||||
/* FIXME this should be made asynchronous, at which point the significance
|
||||
of the registers / interrupts should be more obvious */
|
||||
|
||||
if (dtr->data) {
|
||||
/* single address mode transfer */
|
||||
if (dtr->dir == SH4_DMA_FROM_ADDR) {
|
||||
sh4_memcpy_to_host(sh4->mem, dtr->data, dtr->addr, dtr->size);
|
||||
sh4_memcpy_to_host(mem, dtr->data, dtr->addr, dtr->size);
|
||||
} else {
|
||||
sh4_memcpy_to_guest(sh4->mem, dtr->addr, dtr->data, dtr->size);
|
||||
sh4_memcpy_to_guest(mem, dtr->addr, dtr->data, dtr->size);
|
||||
}
|
||||
} else {
|
||||
/* dual address mode transfer */
|
||||
|
@ -82,7 +84,7 @@ void sh4_dmac_ddt(struct sh4 *sh4, struct sh4_dtr *dtr) {
|
|||
uint32_t src = dtr->dir == SH4_DMA_FROM_ADDR ? dtr->addr : *sar;
|
||||
uint32_t dst = dtr->dir == SH4_DMA_FROM_ADDR ? *dar : dtr->addr;
|
||||
int size = *dmatcr * 32;
|
||||
sh4_memcpy(sh4->mem, dst, src, size);
|
||||
sh4_memcpy(mem, dst, src, size);
|
||||
|
||||
/* update src / addresses as well as remaining count */
|
||||
*sar = src + size;
|
||||
|
|
|
@ -113,17 +113,19 @@ uint32_t sh4_area7_read(struct sh4 *sh4, uint32_t addr, uint32_t mask) {
|
|||
|
||||
void sh4_area4_write(struct sh4 *sh4, uint32_t addr, const uint8_t *ptr,
|
||||
int size) {
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
addr &= SH4_ADDR_MASK;
|
||||
|
||||
/* create the two area4 mirrors */
|
||||
addr &= SH4_AREA4_ADDR_MASK;
|
||||
|
||||
if (addr >= SH4_TA_POLY_BEGIN && addr <= SH4_TA_POLY_END) {
|
||||
ta_poly_write(sh4->ta, addr, ptr, size);
|
||||
ta_poly_write(dc->ta, addr, ptr, size);
|
||||
} else if (addr >= SH4_TA_YUV_BEGIN && addr <= SH4_TA_YUV_END) {
|
||||
ta_yuv_write(sh4->ta, addr, ptr, size);
|
||||
ta_yuv_write(dc->ta, addr, ptr, size);
|
||||
} else if (addr >= SH4_TA_TEXTURE_BEGIN && addr <= SH4_TA_TEXTURE_END) {
|
||||
ta_texture_write(sh4->ta, addr, ptr, size);
|
||||
ta_texture_write(dc->ta, addr, ptr, size);
|
||||
} else {
|
||||
LOG_FATAL("sh4_area4_write unexpected addr 0x%08x", addr);
|
||||
}
|
||||
|
@ -131,30 +133,34 @@ void sh4_area4_write(struct sh4 *sh4, uint32_t addr, const uint8_t *ptr,
|
|||
|
||||
void sh4_area1_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
||||
uint32_t mask) {
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
addr &= SH4_ADDR_MASK;
|
||||
|
||||
/* create the two area1 mirrors */
|
||||
addr &= SH4_AREA1_ADDR_MASK;
|
||||
|
||||
if (addr >= SH4_PVR_VRAM64_BEGIN && addr <= SH4_PVR_VRAM64_END) {
|
||||
pvr_vram64_write(sh4->pvr, addr - SH4_PVR_VRAM64_BEGIN, data, mask);
|
||||
pvr_vram64_write(dc->pvr, addr - SH4_PVR_VRAM64_BEGIN, data, mask);
|
||||
} else if (addr >= SH4_PVR_VRAM32_BEGIN && addr <= SH4_PVR_VRAM32_END) {
|
||||
pvr_vram32_write(sh4->pvr, addr - SH4_PVR_VRAM32_BEGIN, data, mask);
|
||||
pvr_vram32_write(dc->pvr, addr - SH4_PVR_VRAM32_BEGIN, data, mask);
|
||||
} else {
|
||||
LOG_FATAL("sh4_area1_write unexpected addr 0x%08x", addr);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t sh4_area1_read(struct sh4 *sh4, uint32_t addr, uint32_t mask) {
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
addr &= SH4_ADDR_MASK;
|
||||
|
||||
/* create the two area1 mirrors */
|
||||
addr &= SH4_AREA1_ADDR_MASK;
|
||||
|
||||
if (addr >= SH4_PVR_VRAM64_BEGIN && addr <= SH4_PVR_VRAM64_END) {
|
||||
return pvr_vram64_read(sh4->pvr, addr - SH4_PVR_VRAM64_BEGIN, mask);
|
||||
return pvr_vram64_read(dc->pvr, addr - SH4_PVR_VRAM64_BEGIN, mask);
|
||||
} else if (addr >= SH4_PVR_VRAM32_BEGIN && addr <= SH4_PVR_VRAM32_END) {
|
||||
return pvr_vram32_read(sh4->pvr, addr - SH4_PVR_VRAM32_BEGIN, mask);
|
||||
return pvr_vram32_read(dc->pvr, addr - SH4_PVR_VRAM32_BEGIN, mask);
|
||||
} else {
|
||||
LOG_FATAL("sh4_area1_read unexpected addr 0x%08x", addr);
|
||||
}
|
||||
|
@ -162,26 +168,28 @@ uint32_t sh4_area1_read(struct sh4 *sh4, uint32_t addr, uint32_t mask) {
|
|||
|
||||
void sh4_area0_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
||||
uint32_t mask) {
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
/* mask off upper bits creating p0-p4 mirrors */
|
||||
addr &= SH4_ADDR_MASK;
|
||||
|
||||
/* flash rom is not accessible in the area0 mirror */
|
||||
if (addr >= SH4_FLASH_ROM_BEGIN && addr <= SH4_FLASH_ROM_END) {
|
||||
flash_rom_write(sh4->flash, addr - SH4_FLASH_ROM_BEGIN, data, mask);
|
||||
flash_rom_write(dc->flash, addr - SH4_FLASH_ROM_BEGIN, data, mask);
|
||||
} else {
|
||||
/* create the two area0 mirrors */
|
||||
addr &= SH4_AREA0_ADDR_MASK;
|
||||
|
||||
if (addr >= SH4_HOLLY_REG_BEGIN && addr <= SH4_HOLLY_REG_END) {
|
||||
holly_reg_write(sh4->holly, addr - SH4_HOLLY_REG_BEGIN, data, mask);
|
||||
holly_reg_write(dc->holly, addr - SH4_HOLLY_REG_BEGIN, data, mask);
|
||||
} else if (addr >= SH4_PVR_REG_BEGIN && addr <= SH4_PVR_REG_END) {
|
||||
pvr_reg_write(sh4->pvr, addr - SH4_PVR_REG_BEGIN, data, mask);
|
||||
pvr_reg_write(dc->pvr, addr - SH4_PVR_REG_BEGIN, data, mask);
|
||||
} else if (addr >= SH4_MODEM_BEGIN && addr <= SH4_MODEM_END) {
|
||||
/* nop */
|
||||
} else if (addr >= SH4_AICA_REG_BEGIN && addr <= SH4_AICA_REG_END) {
|
||||
aica_reg_write(sh4->aica, addr - SH4_AICA_REG_BEGIN, data, mask);
|
||||
aica_reg_write(dc->aica, addr - SH4_AICA_REG_BEGIN, data, mask);
|
||||
} else if (addr >= SH4_AICA_MEM_BEGIN && addr <= SH4_AICA_MEM_END) {
|
||||
aica_mem_write(sh4->aica, addr - SH4_AICA_MEM_BEGIN, data, mask);
|
||||
aica_mem_write(dc->aica, addr - SH4_AICA_MEM_BEGIN, data, mask);
|
||||
} else if (addr >= SH4_HOLLY_EXT_BEGIN && addr <= SH4_HOLLY_EXT_END) {
|
||||
/* nop */
|
||||
} else {
|
||||
|
@ -191,29 +199,31 @@ void sh4_area0_write(struct sh4 *sh4, uint32_t addr, uint32_t data,
|
|||
}
|
||||
|
||||
uint32_t sh4_area0_read(struct sh4 *sh4, uint32_t addr, uint32_t mask) {
|
||||
struct dreamcast *dc = sh4->dc;
|
||||
|
||||
/* mask off upper bits creating p0-p4 mirrors */
|
||||
addr &= SH4_ADDR_MASK;
|
||||
|
||||
/* boot / flash rom are not accessible in the area0 mirror */
|
||||
if (/*addr >= SH4_BOOT_ROM_BEGIN &&*/ addr <= SH4_BOOT_ROM_END) {
|
||||
return boot_rom_read(sh4->boot, addr - SH4_BOOT_ROM_BEGIN, mask);
|
||||
return boot_rom_read(dc->boot, addr - SH4_BOOT_ROM_BEGIN, mask);
|
||||
} else if (addr >= SH4_FLASH_ROM_BEGIN && addr <= SH4_FLASH_ROM_END) {
|
||||
return flash_rom_read(sh4->flash, addr - SH4_FLASH_ROM_BEGIN, mask);
|
||||
return flash_rom_read(dc->flash, addr - SH4_FLASH_ROM_BEGIN, mask);
|
||||
}
|
||||
|
||||
/* create the two area0 mirrors */
|
||||
addr &= SH4_AREA0_ADDR_MASK;
|
||||
|
||||
if (addr >= SH4_HOLLY_REG_BEGIN && addr <= SH4_HOLLY_REG_END) {
|
||||
return holly_reg_read(sh4->holly, addr - SH4_HOLLY_REG_BEGIN, mask);
|
||||
return holly_reg_read(dc->holly, addr - SH4_HOLLY_REG_BEGIN, mask);
|
||||
} else if (addr >= SH4_PVR_REG_BEGIN && addr <= SH4_PVR_REG_END) {
|
||||
return pvr_reg_read(sh4->pvr, addr - SH4_PVR_REG_BEGIN, mask);
|
||||
return pvr_reg_read(dc->pvr, addr - SH4_PVR_REG_BEGIN, mask);
|
||||
} else if (addr >= SH4_MODEM_BEGIN && addr <= SH4_MODEM_END) {
|
||||
return 0;
|
||||
} else if (addr >= SH4_AICA_REG_BEGIN && addr <= SH4_AICA_REG_END) {
|
||||
return aica_reg_read(sh4->aica, addr - SH4_AICA_REG_BEGIN, mask);
|
||||
return aica_reg_read(dc->aica, addr - SH4_AICA_REG_BEGIN, mask);
|
||||
} else if (addr >= SH4_AICA_MEM_BEGIN && addr <= SH4_AICA_MEM_END) {
|
||||
return aica_mem_read(sh4->aica, addr - SH4_AICA_MEM_BEGIN, mask);
|
||||
return aica_mem_read(dc->aica, addr - SH4_AICA_MEM_BEGIN, mask);
|
||||
} else if (addr >= SH4_HOLLY_EXT_BEGIN && addr <= SH4_HOLLY_EXT_END) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,8 @@ static void sh4_tmu_reschedule(struct sh4 *sh4, int n, uint32_t tcnt,
|
|||
uint32_t tcr);
|
||||
|
||||
static uint32_t sh4_tmu_tcnt(struct sh4 *sh4, int n) {
|
||||
struct scheduler *sched = sh4->dc->sched;
|
||||
|
||||
/* TCNT values aren't updated in real time. if a timer is enabled, query
|
||||
the scheduler to figure out how many cycles are remaining for the given
|
||||
timer */
|
||||
|
@ -28,7 +30,7 @@ static uint32_t sh4_tmu_tcnt(struct sh4 *sh4, int n) {
|
|||
this to change */
|
||||
uint32_t tcr = *TCR(n);
|
||||
int64_t freq = PERIPHERAL_CLOCK_FREQ >> PERIPHERAL_SCALE[tcr & 7];
|
||||
int64_t remaining = scheduler_remaining_time(sh4->scheduler, timer);
|
||||
int64_t remaining = sched_remaining_time(sched, timer);
|
||||
int64_t cycles = NANO_TO_CYCLES(remaining, freq);
|
||||
|
||||
return (uint32_t)cycles;
|
||||
|
@ -73,6 +75,7 @@ static void sh4_tmu_expire_2(void *data) {
|
|||
|
||||
static void sh4_tmu_reschedule(struct sh4 *sh4, int n, uint32_t tcnt,
|
||||
uint32_t tcr) {
|
||||
struct scheduler *sched = sh4->dc->sched;
|
||||
struct timer **timer = &sh4->tmu_timers[n];
|
||||
|
||||
int64_t freq = PERIPHERAL_CLOCK_FREQ >> PERIPHERAL_SCALE[tcr & 7];
|
||||
|
@ -80,16 +83,18 @@ static void sh4_tmu_reschedule(struct sh4 *sh4, int n, uint32_t tcnt,
|
|||
int64_t remaining = CYCLES_TO_NANO(cycles, freq);
|
||||
|
||||
if (*timer) {
|
||||
scheduler_cancel_timer(sh4->scheduler, *timer);
|
||||
sched_cancel_timer(sched, *timer);
|
||||
*timer = NULL;
|
||||
}
|
||||
|
||||
timer_cb cb = (n == 0 ? &sh4_tmu_expire_0
|
||||
: n == 1 ? &sh4_tmu_expire_1 : &sh4_tmu_expire_2);
|
||||
*timer = scheduler_start_timer(sh4->scheduler, cb, sh4, remaining);
|
||||
*timer = sched_start_timer(sched, cb, sh4, remaining);
|
||||
}
|
||||
|
||||
static void sh4_tmu_update_tstr(struct sh4 *sh4) {
|
||||
struct scheduler *sched = sh4->dc->sched;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
struct timer **timer = &sh4->tmu_timers[i];
|
||||
|
||||
|
@ -103,7 +108,7 @@ static void sh4_tmu_update_tstr(struct sh4 *sh4) {
|
|||
*TCNT(i) = sh4_tmu_tcnt(sh4, i);
|
||||
|
||||
/* disable the timer */
|
||||
scheduler_cancel_timer(sh4->scheduler, *timer);
|
||||
sched_cancel_timer(sched, *timer);
|
||||
*timer = NULL;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue