mizu_core/memory/
interrupts.rs

1use bitflags::bitflags;
2use save_state::Savable;
3use std::convert::{From, TryFrom};
4
5#[derive(Copy, Clone, PartialEq, Debug)]
6pub enum InterruptType {
7    Vblank,
8    LcdStat,
9    Timer,
10    Serial,
11    Joypad,
12}
13
14impl TryFrom<u8> for InterruptType {
15    type Error = ();
16
17    fn try_from(value: u8) -> Result<Self, Self::Error> {
18        match value {
19            0 => Ok(Self::Vblank),
20            1 => Ok(Self::LcdStat),
21            2 => Ok(Self::Timer),
22            3 => Ok(Self::Serial),
23            4 => Ok(Self::Joypad),
24            _ => Err(()),
25        }
26    }
27}
28
29pub trait InterruptManager {
30    fn request_interrupt(&mut self, interrupt: InterruptType);
31}
32
33bitflags! {
34    #[derive(Savable)]
35    #[savable(bitflags)]
36    struct InterruptsFlags: u8 {
37        /// This is only used when reading `interrupt_enable` only
38        const UNUSED   = 0b111 << 5;
39        const VBLANK   = 1 << 0;
40        const LCD_STAT = 1 << 1;
41        const TIMER    = 1 << 2;
42        const SERIAL   = 1 << 3;
43        const JOYPAD   = 1 << 4;
44    }
45}
46
47impl From<InterruptType> for InterruptsFlags {
48    fn from(interrupt: InterruptType) -> Self {
49        match interrupt {
50            InterruptType::Vblank => Self::VBLANK,
51            InterruptType::LcdStat => Self::LCD_STAT,
52            InterruptType::Timer => Self::TIMER,
53            InterruptType::Serial => Self::SERIAL,
54            InterruptType::Joypad => Self::JOYPAD,
55        }
56    }
57}
58
59#[derive(Savable)]
60pub struct Interrupts {
61    enabled: InterruptsFlags,
62    requested: InterruptsFlags,
63}
64
65impl Default for Interrupts {
66    fn default() -> Self {
67        Self {
68            enabled: InterruptsFlags::from_bits_truncate(0),
69            requested: InterruptsFlags::from_bits_truncate(1),
70        }
71    }
72}
73
74impl Interrupts {
75    pub fn write_interrupt_enable(&mut self, data: u8) {
76        self.enabled = InterruptsFlags::from_bits_truncate(data);
77    }
78
79    pub fn read_interrupt_enable(&self) -> u8 {
80        self.enabled.bits()
81    }
82
83    pub fn write_interrupt_flags(&mut self, data: u8) {
84        self.requested = InterruptsFlags::from_bits_truncate(data);
85    }
86
87    pub fn read_interrupt_flags(&self) -> u8 {
88        0xE0 | self.requested.bits()
89    }
90
91    pub fn acknowledge_interrupt(&mut self, interrupt: InterruptType) {
92        assert!(self.requested.contains(interrupt.into()));
93
94        self.requested.remove(interrupt.into());
95    }
96
97    pub fn get_highest_interrupt(&mut self) -> Option<InterruptType> {
98        let interrupts_to_take_bits = self.requested.bits() & self.enabled.bits() & 0x1F;
99
100        if interrupts_to_take_bits == 0 {
101            None
102        } else {
103            let mut bits = interrupts_to_take_bits;
104            let mut counter = 0;
105            while bits != 0 && counter < 5 {
106                if bits & 1 == 1 {
107                    return Some(InterruptType::try_from(counter).unwrap());
108                }
109                counter += 1;
110                bits >>= 1;
111            }
112            unreachable!();
113        }
114    }
115}
116
117impl InterruptManager for Interrupts {
118    fn request_interrupt(&mut self, interrupt: InterruptType) {
119        let interrupt = interrupt.into();
120
121        self.requested.insert(interrupt);
122    }
123}