tetanes_core/mapper/
vrc_irq.rs

1//! `VrcIrq`
2//!
3//! <https://www.nesdev.org/wiki/VRC_IRQ>
4
5use crate::{
6    common::{Clock, Reset, ResetKind},
7    cpu::{Cpu, Irq},
8};
9use serde::{Deserialize, Serialize};
10
11#[derive(Default, Debug, Copy, Clone, Serialize, Deserialize)]
12#[must_use]
13pub struct VrcIrq {
14    pub reload: u8,
15    pub counter: u8,
16    pub prescalar_counter: i16,
17    pub enabled: bool,
18    pub enabled_after_ack: bool,
19    pub cycle_mode: bool,
20}
21
22impl VrcIrq {
23    pub const fn write_reload(&mut self, val: u8) {
24        self.reload = val;
25    }
26
27    pub fn write_control(&mut self, val: u8) {
28        self.enabled_after_ack = val & 0x01 == 0x01;
29        self.enabled = val & 0x02 == 0x02;
30        self.cycle_mode = val & 0x04 == 0x04;
31
32        if self.enabled {
33            self.counter = self.reload;
34            self.prescalar_counter = 341;
35        }
36
37        Cpu::clear_irq(Irq::MAPPER);
38    }
39
40    pub fn acknowledge(&mut self) {
41        self.enabled = self.enabled_after_ack;
42        Cpu::clear_irq(Irq::MAPPER);
43    }
44}
45
46impl Clock for VrcIrq {
47    fn clock(&mut self) -> u64 {
48        if self.enabled {
49            self.prescalar_counter -= 3;
50            if self.cycle_mode || self.prescalar_counter <= 0 {
51                if self.counter == 0xFF {
52                    self.counter = self.reload;
53                    Cpu::set_irq(Irq::MAPPER);
54                } else {
55                    self.counter += 1;
56                }
57                self.prescalar_counter += 341;
58            }
59            1
60        } else {
61            0
62        }
63    }
64}
65
66impl Reset for VrcIrq {
67    fn reset(&mut self, _kind: ResetKind) {
68        self.reload = 0;
69        self.counter = 0;
70        self.prescalar_counter = 0;
71        self.enabled = false;
72        self.enabled_after_ack = false;
73        self.cycle_mode = false;
74    }
75}