remove cached device references on each device

remove device interface create routines
This commit is contained in:
Anthony Pesch 2017-10-23 17:37:51 -04:00
parent e17a21b1f2
commit e06ce8fa71
17 changed files with 331 additions and 314 deletions

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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;
}
}