Skip to content

Commit

Permalink
Greatly improve the emulator's speed when the GBA is halted.
Browse files Browse the repository at this point in the history
This also moves the `cycles` field of `struct core` to `struct scheduler`.
  • Loading branch information
Arignir committed Dec 14, 2023
1 parent bd55c95 commit 55649c9
Show file tree
Hide file tree
Showing 10 changed files with 28 additions and 27 deletions.
2 changes: 0 additions & 2 deletions include/gba/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ struct core {

enum core_states state; // 0=Run, 1=Halt, 2=Stop

uint64_t cycles; // Amount of cycles spent by the CPU since initialization

bool is_dma_running; // Set to `true` when waiting for a DMA to complete.
struct dma_channel *current_dma; // The DMA the core is currently waiting for. Can be NULL.

Expand Down
1 change: 0 additions & 1 deletion source/common/game.c
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,6 @@ app_game_configure(
free(app->file.qsaves[i].mtime);

app->file.qsaves[i].mtime = NULL;

app->file.qsaves[i].path = hs_format(
"%.*s.%zu.hds",
(int)basename_len,
Expand Down
2 changes: 1 addition & 1 deletion source/dbg/cmd/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ debugger_dump_context_compact(

printf(
"%016" PRIu64 " ",
core->cycles
app->emulation.gba->scheduler.cycles
);

for (i = 0; i < 16; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion source/dbg/cmd/registers.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ debugger_cmd_registers(
g_light_green,
g_reset,
g_light_magenta,
core->cycles,
app->emulation.gba->scheduler.cycles,
g_reset,
g_light_green,
g_reset,
Expand Down
2 changes: 1 addition & 1 deletion source/gba/apu/wave.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ apu_wave_reset(
gba->apu.wave.step_handler = sched_add_event(
gba,
NEW_REPEAT_EVENT(
gba->core.cycles, // TODO: Is there a delay before the sound is started?
gba->scheduler.cycles, // TODO: Is there a delay before the sound is started?
period,
apu_wave_step
)
Expand Down
10 changes: 7 additions & 3 deletions source/gba/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ core_next(
arm_lut[idx](gba, op);
}
} else if (core->state == CORE_HALT) {
core_idle(gba);
if (gba->scheduler.next_event > gba->scheduler.cycles) {
core_idle_for(gba, gba->scheduler.next_event - gba->scheduler.cycles);
} else {
core_idle(gba);
}
}

end:
Expand Down Expand Up @@ -139,7 +143,7 @@ core_idle_for(
mem_dma_do_all_pending_transfers(gba);
}

gba->core.cycles += cycles;
gba->scheduler.cycles += cycles;

/*
** Disable prefetchng during DMA.
Expand All @@ -151,7 +155,7 @@ core_idle_for(
mem_prefetch_buffer_step(gba, cycles);
}

if (unlikely(gba->core.cycles >= gba->scheduler.next_event)) {
if (unlikely(gba->scheduler.cycles >= gba->scheduler.next_event)) {
sched_process_events(gba);
}
}
Expand Down
2 changes: 1 addition & 1 deletion source/gba/memory/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ mem_schedule_dma_transfers_for(
channel->enable_event_handle = sched_add_event(
gba,
NEW_FIX_EVENT_ARGS(
gba->core.cycles + 2,
gba->scheduler.cycles + 2,
mem_dma_add_to_pending,
EVENT_ARG(u32, channel_idx)
)
Expand Down
2 changes: 2 additions & 0 deletions source/gba/quicksave.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ quicksave(
quicksave_write(&buffer, (uint8_t *)&gba->apu.fifos, sizeof(gba->apu.fifos));
quicksave_write(&buffer, (uint8_t *)&gba->apu.wave, sizeof(gba->apu.wave));
quicksave_write(&buffer, (uint8_t *)&gba->apu.latch, sizeof(gba->apu.latch));
quicksave_write(&buffer, (uint8_t *)&gba->scheduler.cycles, sizeof(uint64_t));
quicksave_write(&buffer, (uint8_t *)&gba->scheduler.next_event, sizeof(uint64_t));

// Serialize the scheduler's event list
Expand Down Expand Up @@ -140,6 +141,7 @@ quickload(
|| quicksave_read(&buffer, (uint8_t *)&gba->apu.fifos, sizeof(gba->apu.fifos))
|| quicksave_read(&buffer, (uint8_t *)&gba->apu.wave, sizeof(gba->apu.wave))
|| quicksave_read(&buffer, (uint8_t *)&gba->apu.latch, sizeof(gba->apu.latch))
|| quicksave_read(&buffer, (uint8_t *)&gba->scheduler.cycles, sizeof(uint64_t))
|| quicksave_read(&buffer, (uint8_t *)&gba->scheduler.next_event, sizeof(uint64_t))
) {
return (true);
Expand Down
26 changes: 12 additions & 14 deletions source/gba/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@ void
sched_process_events(
struct gba *gba
) {
struct core *core;
struct scheduler *scheduler;

core = &gba->core;
scheduler = &gba->scheduler;
while (true) {
struct scheduler_event *event;
Expand All @@ -38,7 +36,7 @@ sched_process_events(

// Keep only the event that are active and should occure now
if (scheduler->events[i].active) {
if (scheduler->events[i].at <= core->cycles) {
if (scheduler->events[i].at <= scheduler->cycles) {
if (!event || scheduler->events[i].at < event->at) {
event = scheduler->events + i;
}
Expand All @@ -55,8 +53,8 @@ sched_process_events(
}

// We 'rollback' the cycle counter for the duration of the callback
delay = core->cycles - event->at;
core->cycles -= delay;
delay = scheduler->cycles - event->at;
scheduler->cycles -= delay;

if (event->repeat) {
event->at += event->period;
Expand All @@ -70,7 +68,7 @@ sched_process_events(
}

event->callback(gba, event->args);
core->cycles += delay;
scheduler->cycles += delay;
}
}

Expand Down Expand Up @@ -132,28 +130,28 @@ sched_run_for(
struct gba *gba,
uint64_t cycles
) {
struct core *core;
struct scheduler *scheduler;
uint64_t target;

core = &gba->core;
target = core->cycles + cycles;
scheduler = &gba->scheduler;
target = scheduler->cycles + cycles;

#ifdef WITH_DEBUGGER
gba->debugger.interrupted = false;

while (core->cycles < target && !gba->debugger.interrupted) {
while (scheduler->cycles < target && !gba->debugger.interrupted) {
#else
while (core->cycles < target) {
while (scheduler->cycles < target) {
#endif
uint64_t elapsed;
uint64_t old_cycles;

old_cycles = core->cycles;
old_cycles = scheduler->cycles;
core_next(gba);
elapsed = core->cycles - old_cycles;
elapsed = scheduler->cycles - old_cycles;

if (!elapsed) {
if (core->state != CORE_STOP) {
if (gba->core.state != CORE_STOP) {
logln(HS_WARNING, "No cycles elapsed during `core_next()`.");
}
break;
Expand Down
6 changes: 3 additions & 3 deletions source/gba/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ timer_schedule_start(
timer->handler = sched_add_event(
gba,
NEW_REPEAT_EVENT_ARGS(
gba->core.cycles + ((0x10000 - timer->counter.raw) << scalers[timer->control.prescaler]) + 2, // Timer starts with a 2 cycles delay
gba->scheduler.cycles + ((0x10000 - timer->counter.raw) << scalers[timer->control.prescaler]) + 2, // Timer starts with a 2 cycles delay
((0x10000 - timer->counter.raw) << scalers[timer->control.prescaler]),
timer_overflow,
EVENT_ARG(u32, timer_idx)
Expand All @@ -68,7 +68,7 @@ timer_schedule_stop(
sched_add_event(
gba,
NEW_FIX_EVENT_ARGS(
gba->core.cycles + 1, // One cycle delay when stopping a timer
gba->scheduler.cycles + 1, // One cycle delay when stopping a timer
timer_stop,
EVENT_ARG(u32, timer_idx)
)
Expand Down Expand Up @@ -126,7 +126,7 @@ timer_update_counter(
uint64_t elapsed;

timer = &gba->io.timers[timer_idx];
elapsed = gba->core.cycles - gba->scheduler.events[timer->handler].at;
elapsed = gba->scheduler.cycles - gba->scheduler.events[timer->handler].at;
return (elapsed >> scalers[timer->control.prescaler]);
}

Expand Down

0 comments on commit 55649c9

Please sign in to comment.