use splitbits::splitbits_named;
pub struct VrcIrqState {
enabled: bool,
pending: bool,
enable_upon_acknowledgement: bool,
mode: IrqMode,
counter_reload_low_value: u8,
counter_reload_value: u8,
counter: u8,
prescaler: i16,
}
impl VrcIrqState {
pub fn new() -> Self {
Self {
enabled: false,
pending: false,
enable_upon_acknowledgement: false,
mode: IrqMode::Scanline,
counter_reload_low_value: 0,
counter_reload_value: 0,
counter: 0,
prescaler: 341,
}
}
pub fn step(&mut self) {
if !self.enabled {
return;
}
if self.mode == IrqMode::Scanline {
self.prescaler -= 3;
if self.prescaler <= 0 {
self.prescaler += 341;
} else {
return;
}
}
if self.counter == 0xFF {
self.pending = true;
self.counter = self.counter_reload_value;
} else {
self.counter += 1;
}
}
pub fn set_reload_value_low_bits(&mut self, value: u8) {
self.counter_reload_low_value = value & 0b0000_1111;
}
pub fn set_reload_value_high_bits(&mut self, value: u8) {
self.counter_reload_value = (value & 0b0000_1111) << 4 | self.counter_reload_low_value;
}
pub fn set_mode(&mut self, value: u8) {
self.pending = false;
let mode;
(mode, self.enable_upon_acknowledgement, self.enabled) = splitbits_named!(value, ".....mae");
self.mode = if mode { IrqMode::Cycle } else { IrqMode::Scanline };
if self.enabled {
self.counter = self.counter_reload_value;
}
}
pub fn acknowledge(&mut self) {
self.pending = false;
if self.enable_upon_acknowledgement {
self.enabled = true;
}
}
pub fn pending(&self) -> bool {
self.pending
}
}
#[derive(PartialEq, Debug)]
enum IrqMode {
Scanline,
Cycle,
}