Files
gbemu/lib/timer.c

140 lines
2.8 KiB
C

#include <timer.h>
#include <interrupts.h>
#include <audio.h>
static timer_context ctx = {0};
bool selected_bit() {
switch(ctx.tac & 0b11) {
case 0b00:
return (ctx.div & (1 << 9));
break;
case 0b01:
return (ctx.div & (1 << 3));
break;
case 0b10:
return (ctx.div & (1 << 5));
break;
case 0b11:
return (ctx.div & (1 << 7));
break;
}
}
void inc_tima() {
ctx.tima++;
if(ctx.tima == 0x00){
ctx.tima_needs_reset = true;
}
}
void timer_init() {
ctx.div = 0XAC00;
ctx.tac = 0xF8;
}
void timer_tick() {
u16 prev_div = ctx.div;
bool old = selected_bit();
ctx.div++;
bool new = selected_bit();
if((prev_div & (1 << 1)) && (!(ctx.div & (1 << 1)))){
if(ctx.tima_just_reset)
ctx.tima_just_reset = false;
if(ctx.tima_needs_reset){
ctx.tima = ctx.tma;
ctx.tima_needs_reset = false;
ctx.tima_just_reset = true;
cpu_request_interrupt(IT_TIMER);
}
}
if(ctx.tac & 0b100 && old && !new) {
inc_tima();
}
audio_sample_tick();
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
audio_tick();
}
if((prev_div & (1 << 0)) && (!(ctx.div & (1 << 0)))){
audio_period_tick();
}
}
void timer_write(u16 address, u8 value){
switch(address) {
case 0xFF04:
//DIV
if(selected_bit()) {
inc_tima();
}
ctx.div = 0;
break;
case 0xFF05:
//TIMA
if(ctx.tima_just_reset)
return;
ctx.tima_needs_reset = false;
ctx.tima = value;
break;
case 0xFF06:
//TMA
if(ctx.tima_just_reset)
ctx.tima = value;
ctx.tma = value;
break;
case 0xFF07:
//TAC
bool current = selected_bit();
bool old_enable = ctx.tac & 0b100;
ctx.tac = value;
bool new = selected_bit();
if(((current && !new) && (ctx.tac & 0b100)) || (current && old_enable && !(ctx.tac & 0b100))) {
inc_tima();
}
break;
}
}
u8 timer_read(u16 address) {
switch(address) {
case 0xFF04:
//DIV
return ctx.div >> 8;
case 0xFF05:
//TIMA
return ctx.tima;
case 0xFF06:
//TMA
return ctx.tma;
case 0xFF07:
//TAC
return ctx.tac;
}
}
timer_context *timer_get_context() {
return &ctx;
}
void timer_save_state(timer_state* state) {
state->ctx = ctx;
}
void timer_load_state(const timer_state* state) {
ctx = state->ctx;
}