1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
use super::*;

/// "Display Status"
///
/// This is a mix of some read-only bits that give you info about the display,
/// and also some bits that affect display related interrupts.
#[cfg(feature = "unsafe_addresses")]
pub const DISPSTAT: DangerWriteVolAddr<DisplayStatusValue> =
  unsafe { DangerWriteVolAddr::new(0x0400_0004) };

/// Relates to the status of the display.
///
/// When writing this value to [`DISPSTAT`], the `vblank`, `hblank`, and
/// `vcounter` settings aren't actually written. They can still be modified on
/// this type if you want to set up a specific value and then check for equality
/// or something.
///
/// Setting the interrupt related flags is dangerous if your interrupt handler
/// isn't set up to handle the appropriate types of interrupts. Even if you set
/// for interrupt types to occur here they won't fire unless you also enable
/// them in the `IME` register, and of course you must have interrupts enabled
/// overall using the `IE` register.
///
/// * `vblank`: Set during [`VCOUNT`] lines 160 to 226, but not 227.
/// * `hblank`: Set when you're in hblank, after the current line has
///   completed drawing. It takes 960 cycles to draw a line, but
///   [GBATEK says](https://problemkaputt.de/gbatek.htm#lcdiointerruptsandstatus)
///   that this is off for 1006 cycles per line.
/// * `vcounter`: Set if the current `VCOUNT` value matches the `vcount_trigger`
///   value.
/// * `vblank_irq`: If an interrupt should be triggered at start of vblank.
/// * `hblank_irq`: If an interrupt should be triggered at start of hblank.
/// * `vcounter_irq`: If an interrupt should be triggered when `VCOUNT` matches
///   the `vcount_trigger` value.
/// * `vcount_trigger`: The scanline that you want to use for vcount interrupts
///   and the `vcounter` flag.
#[repr(transparent)]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct DisplayStatusValue(u16);

#[rustfmt::skip]
#[allow(missing_docs)]
impl DisplayStatusValue {
  pub_const_fn_new_zero!();
  bool_bit_u16!(0, vblank, with_vblank, set_vblank);
  bool_bit_u16!(1, hblank, with_hblank, set_hblank);
  bool_bit_u16!(2, vcounter, with_vcounter, set_vcounter);
  bool_bit_u16!(3, vblank_irq, with_vblank_irq, set_vblank_irq);
  bool_bit_u16!(4, hblank_irq, with_hblank_irq, set_hblank_irq);
  bool_bit_u16!(5, vcounter_irq, with_vcounter_irq, set_vcounter_irq);
  unsigned_bits_u16!(8..=15, vcount_trigger, with_vcount_trigger, set_vcount_trigger);
}