mizu_core/memory/
interrupts.rs1use 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 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}