This repository has been archived on 2024-06-01. You can view files and clone it, but cannot push or open issues or pull requests.
rustboyadvance-ng/src/core/timer.rs
Michel Heily c72bbb96fd [WIP] Timers
Seems to work, but the cycle's are not accurate so they run slowly


Former-commit-id: a0b80acb4b68ed64caa535a0ec9f75a081d3aed4
2019-08-05 09:53:41 +03:00

126 lines
3 KiB
Rust

use super::interrupt::{Interrupt, IrqBitmask};
use super::sysbus::SysBus;
use super::SyncedIoDevice;
use num::FromPrimitive;
#[derive(Debug, Default)]
pub struct Timer {
// registers
pub timer_ctl: TimerCtl,
pub timer_data: u16,
timer_id: usize,
reg: u32,
target: u32,
fired: bool,
pub initial_data: u16,
pub cycles: usize,
}
pub enum TimerAction {
Overflow,
Increment,
}
impl Timer {
pub fn new(timer_id: usize) -> Timer {
if timer_id > 3 {
panic!("invalid timer id {}", timer_id);
}
Timer {
timer_id: timer_id,
..Timer::default()
}
}
fn get_irq(&self) -> Interrupt {
Interrupt::from_usize(self.timer_id + 8).unwrap()
}
fn frequency(&self) -> usize {
match self.timer_ctl.prescalar() {
0 => 1,
1 => 64,
2 => 256,
3 => 1024,
_ => unreachable!(),
}
}
pub fn add_cycles(&mut self, cycles: usize, irqs: &mut IrqBitmask) -> TimerAction {
self.cycles += cycles;
let frequency = self.frequency();
while self.cycles >= frequency {
self.cycles -= frequency;
self.timer_data = self.timer_data.wrapping_add(1);
if self.timer_data == 0 {
if self.timer_ctl.irq_enabled() {
irqs.add_irq(self.get_irq());
}
println!("timer{} overflow", self.timer_id);
return TimerAction::Overflow;
}
}
return TimerAction::Increment;
}
}
#[derive(Debug)]
pub struct Timers([Timer; 4]);
impl std::ops::Index<usize> for Timers {
type Output = Timer;
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl std::ops::IndexMut<usize> for Timers {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl Timers {
pub fn new() -> Timers {
Timers([Timer::new(0), Timer::new(1), Timer::new(2), Timer::new(3)])
}
}
impl SyncedIoDevice for Timers {
fn step(&mut self, cycles: usize, _sb: &mut SysBus, irqs: &mut IrqBitmask) {
for i in 0..4 {
if self[i].timer_ctl.enabled() && !self[i].timer_ctl.cascade() {
match self[i].add_cycles(cycles, irqs) {
TimerAction::Overflow => match i {
3 => {}
_ => {
let next_i = i +1;
if self[next_i].timer_ctl.cascade() {
println!("{:?} is cascade!", self[next_i]);
self[next_i].add_cycles(1, irqs);
}
}
},
_ => {}
}
}
}
}
}
bitfield! {
#[derive(Default)]
pub struct TimerCtl(u16);
impl Debug;
u16;
prescalar, _ : 1, 0;
cascade, _ : 2;
irq_enabled, _ : 6;
enabled, set_enabled : 7;
}