use crate::hw::{MemRegister, Register};
use core::mem::variant_count;
pub const NUM_IRQS: usize = variant_count::<IRQ>();
#[repr(u16)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum IRQ {
Vblank = 0,
GPU,
CDROM,
DMA,
Timer0,
Timer1,
Timer2,
ControllerMemoryCard,
SIO,
SPU,
ControllerPIO,
}
pub const ALL_IRQS: [IRQ; 11] = [
IRQ::Vblank,
IRQ::GPU,
IRQ::CDROM,
IRQ::DMA,
IRQ::Timer0,
IRQ::Timer1,
IRQ::Timer2,
IRQ::ControllerMemoryCard,
IRQ::SIO,
IRQ::SPU,
IRQ::ControllerPIO,
];
pub type Status = MemRegister<u16, 0x1F80_1070>;
pub type Mask = MemRegister<u16, 0x1F80_1074>;
#[derive(Clone, Copy, Debug)]
pub struct Requested(u16);
impl Requested {
pub const fn new(value: u16) -> Self {
Self(value)
}
pub fn set(&mut self, irq: IRQ) {
self.0 |= 1 << (irq as u16);
}
pub fn clear(&mut self, irq: IRQ) {
self.0 &= !(1 << (irq as u16));
}
pub fn iter(&self) -> impl Iterator<Item = IRQ> {
IRQIter {
value: *self,
iter_idx: 0,
}
}
pub fn contains(&self, irq: IRQ) -> bool {
self.0 & 1 << (irq as u16) != 0
}
}
pub struct IRQIter {
value: Requested,
iter_idx: usize,
}
impl Iterator for IRQIter {
type Item = IRQ;
fn next(&mut self) -> Option<Self::Item> {
if self.iter_idx == NUM_IRQS {
return None
}
let this_bit = self.iter_idx;
let bit_value = self.value.0 & (1 << this_bit);
self.iter_idx += 1;
if bit_value != 0 {
Some(ALL_IRQS[this_bit])
} else {
None
}
}
}
const ALL_IRQS_BITS: u16 = (1 << NUM_IRQS) - 1;
impl Status {
pub fn requested(&self, irq: IRQ) -> bool {
self.all_set(1 << (irq as u32))
}
pub fn ack(&mut self, irq: IRQ) -> &mut Self {
self.clear_bits(1 << (irq as u32))
}
pub fn ack_all(&mut self) -> &mut Self {
self.clear_bits(ALL_IRQS_BITS)
}
pub fn wait(&mut self, irq: IRQ) -> &mut Self {
while !self.requested(irq) {
self.load();
}
self
}
}
impl Mask {
pub fn irq_enabled(&self, irq: IRQ) -> bool {
self.all_set(1 << (irq as u32))
}
pub fn irq_disabled(&self, irq: IRQ) -> bool {
!self.irq_enabled(irq)
}
pub fn enable_irq(&mut self, irq: IRQ) -> &mut Self {
self.set_bits(1 << (irq as u32))
}
pub fn disable_irq(&mut self, irq: IRQ) -> &mut Self {
self.clear_bits(1 << (irq as u32))
}
pub fn enable_all(&mut self) -> &mut Self {
self.set_bits(ALL_IRQS_BITS)
}
pub fn disable_all(&mut self) -> &mut Self {
self.clear_bits(ALL_IRQS_BITS)
}
pub fn get_requested(&self, stat: &Status) -> Requested {
Requested(self.to_bits() & stat.to_bits())
}
}