mirror of
https://github.com/italicsjenga/gba.git
synced 2024-12-24 03:11:29 +11:00
Add timer support
This commit is contained in:
parent
72bbe412b6
commit
cc8d4376f8
|
@ -230,7 +230,7 @@ fixed_point_unsigned_division! {u32}
|
||||||
pub type fx8_8 = Fx<i16, U8>;
|
pub type fx8_8 = Fx<i16, U8>;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod fixed_tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
pub mod background;
|
||||||
pub mod display;
|
pub mod display;
|
||||||
pub mod dma;
|
pub mod dma;
|
||||||
pub mod keypad;
|
pub mod keypad;
|
||||||
pub mod background;
|
pub mod timers;
|
||||||
|
|
|
@ -115,6 +115,7 @@ pub const BG3VOFS: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_00
|
||||||
// pub const WININ: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0048) };
|
// pub const WININ: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0048) };
|
||||||
// pub const WINOUT: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_004A) };
|
// pub const WINOUT: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_004A) };
|
||||||
|
|
||||||
|
// TODO: blending
|
||||||
// pub const BLDCNT: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0050) };
|
// pub const BLDCNT: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0050) };
|
||||||
// pub const BLDALPHA: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0052) };
|
// pub const BLDALPHA: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0052) };
|
||||||
// pub const BLDY: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0054) };
|
// pub const BLDY: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0054) };
|
||||||
|
|
85
src/io/timers.rs
Normal file
85
src/io/timers.rs
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
//! Module for timers.
|
||||||
|
//!
|
||||||
|
//! The timers are slightly funny in that reading and writing from them works
|
||||||
|
//! somewhat differently than with basically any other part of memory.
|
||||||
|
//!
|
||||||
|
//! When you read a timer's counter you read the current value.
|
||||||
|
//!
|
||||||
|
//! When you write a timer's counter you write _the counter's reload value_.
|
||||||
|
//! This is used whenever you enable the timer or any time the timer overflows.
|
||||||
|
//! You cannot set a timer to a given counter value, but you can set a timer to
|
||||||
|
//! start at some particular value every time it reloads.
|
||||||
|
//!
|
||||||
|
//! The timer counters are `u16`, so if you want to set them to run for a
|
||||||
|
//! certain number of ticks before overflow you would write something like
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! let init_val: u16 = u32::wrapping_sub(0x1_0000, ticks) as u16;
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! A timer reloads any time it overflows _or_ goes from disabled to enabled. If
|
||||||
|
//! you want to "pause" a timer _without_ making it reload when resumed then you
|
||||||
|
//! should not disable it. Instead, you should set its `TimerTickRate` to
|
||||||
|
//! `Cascade` and disable _the next lower timer_ so that it won't overflow into
|
||||||
|
//! the timer you have on hold.
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
/// Timer 0 Counter/Reload. Special (see module).
|
||||||
|
pub const TM0CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0100) };
|
||||||
|
|
||||||
|
/// Timer 1 Counter/Reload. Special (see module).
|
||||||
|
pub const TM1CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0104) };
|
||||||
|
|
||||||
|
/// Timer 2 Counter/Reload. Special (see module).
|
||||||
|
pub const TM2CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_0108) };
|
||||||
|
|
||||||
|
/// Timer 3 Counter/Reload. Special (see module).
|
||||||
|
pub const TM3CNT_L: VolAddress<u16> = unsafe { VolAddress::new_unchecked(0x400_010C) };
|
||||||
|
|
||||||
|
/// Timer 0 Control. Read/Write.
|
||||||
|
pub const TM0CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new_unchecked(0x400_0102) };
|
||||||
|
|
||||||
|
/// Timer 1 Control. Read/Write.
|
||||||
|
pub const TM1CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new_unchecked(0x400_0106) };
|
||||||
|
|
||||||
|
/// Timer 2 Control. Read/Write.
|
||||||
|
pub const TM2CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new_unchecked(0x400_010A) };
|
||||||
|
|
||||||
|
/// Timer 3 Control. Read/Write.
|
||||||
|
pub const TM3CNT_H: VolAddress<TimerControlSetting> = unsafe { VolAddress::new_unchecked(0x400_010E) };
|
||||||
|
|
||||||
|
newtype! {
|
||||||
|
/// Allows control of a timer unit.
|
||||||
|
///
|
||||||
|
/// * Bits 0-2: How often the timer should tick up one unit. You can either
|
||||||
|
/// specify a number of CPU cycles or "cascade" mode, where there's a single
|
||||||
|
/// tick per overflow of the next lower timer. For example, Timer 1 would
|
||||||
|
/// tick up once per overflow of Timer 0 if it were in cascade mode. Cascade
|
||||||
|
/// mode naturally does nothing when used with Timer 0.
|
||||||
|
/// * Bit 6: Raise a timer interrupt upon overflow.
|
||||||
|
/// * Bit 7: Enable the timer.
|
||||||
|
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||||
|
TimerControlSetting, u16
|
||||||
|
}
|
||||||
|
impl TimerControlSetting {
|
||||||
|
bool_bits!(u16, [(6, overflow_irq), (7, enabled)]);
|
||||||
|
|
||||||
|
multi_bits!(u16, [(0, 3, tick_rate, TimerTickRate, CPU1, CPU64, CPU256, CPU1024, Cascade),]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Controls how often an enabled timer ticks upward.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u16)]
|
||||||
|
pub enum TimerTickRate {
|
||||||
|
/// Once every CPU cycle
|
||||||
|
CPU1 = 0,
|
||||||
|
/// Once per 64 CPU cycles
|
||||||
|
CPU64 = 1,
|
||||||
|
/// Once per 256 CPU cycles
|
||||||
|
CPU256 = 2,
|
||||||
|
/// Once per 1,024 CPU cycles
|
||||||
|
CPU1024 = 3,
|
||||||
|
/// Once per overflow of the next lower timer. (Useless with Timer 0)
|
||||||
|
Cascade = 4,
|
||||||
|
}
|
Loading…
Reference in a new issue