139 lines
2.8 KiB
C
139 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;
|
|
}
|
|
|
|
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;
|
|
} |