diff --git a/src/base/fixed_point.rs b/src/base/fixed_point.rs index 1e66998..cc1bed6 100644 --- a/src/base/fixed_point.rs +++ b/src/base/fixed_point.rs @@ -230,7 +230,7 @@ fixed_point_unsigned_division! {u32} pub type fx8_8 = Fx; #[cfg(test)] -mod fixed_tests { +mod tests { use super::*; #[test] diff --git a/src/io.rs b/src/io.rs index 86ab5b6..366a2a4 100644 --- a/src/io.rs +++ b/src/io.rs @@ -8,7 +8,8 @@ use super::*; +pub mod background; pub mod display; pub mod dma; pub mod keypad; -pub mod background; +pub mod timers; diff --git a/src/io/background.rs b/src/io/background.rs index d86f033..03de1d7 100644 --- a/src/io/background.rs +++ b/src/io/background.rs @@ -115,6 +115,7 @@ pub const BG3VOFS: VolAddress = unsafe { VolAddress::new_unchecked(0x400_00 // pub const WININ: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0048) }; // pub const WINOUT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_004A) }; +// TODO: blending // pub const BLDCNT: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0050) }; // pub const BLDALPHA: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0052) }; // pub const BLDY: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0054) }; diff --git a/src/io/timers.rs b/src/io/timers.rs new file mode 100644 index 0000000..127f641 --- /dev/null +++ b/src/io/timers.rs @@ -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 = unsafe { VolAddress::new_unchecked(0x400_0100) }; + +/// Timer 1 Counter/Reload. Special (see module). +pub const TM1CNT_L: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0104) }; + +/// Timer 2 Counter/Reload. Special (see module). +pub const TM2CNT_L: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0108) }; + +/// Timer 3 Counter/Reload. Special (see module). +pub const TM3CNT_L: VolAddress = unsafe { VolAddress::new_unchecked(0x400_010C) }; + +/// Timer 0 Control. Read/Write. +pub const TM0CNT_H: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0102) }; + +/// Timer 1 Control. Read/Write. +pub const TM1CNT_H: VolAddress = unsafe { VolAddress::new_unchecked(0x400_0106) }; + +/// Timer 2 Control. Read/Write. +pub const TM2CNT_H: VolAddress = unsafe { VolAddress::new_unchecked(0x400_010A) }; + +/// Timer 3 Control. Read/Write. +pub const TM3CNT_H: VolAddress = 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, +}