1use crate::common::{Reset, ResetKind};
6use bitflags::bitflags;
7use serde::{Deserialize, Serialize};
8
9const NAMETABLE1: u16 = 0x2000;
10const NAMETABLE2: u16 = 0x2400;
11const NAMETABLE3: u16 = 0x2800;
12const NAMETABLE4: u16 = 0x2C00;
13
14#[derive(Default, Serialize, Deserialize, Debug, Copy, Clone)]
18#[must_use]
19pub struct Ctrl {
20 pub spr_select: u16,
21 pub bg_select: u16,
22 pub spr_height: u32,
23 pub master_slave: u8,
24 pub nmi_enabled: bool,
25 pub nametable_addr: u16,
26 pub vram_increment: u16,
27 bits: Bits,
28}
29
30bitflags! {
31 #[derive(Default, Serialize, Deserialize, Debug, Copy, Clone)]
46 #[must_use]
47 pub struct Bits: u8 {
48 const NAMETABLE1 = 0x01;
49 const NAMETABLE2 = 0x02;
50 const VRAM_INCREMENT = 0x04;
51 const SPR_SELECT = 0x08;
52 const BG_SELECT = 0x10;
53 const SPR_HEIGHT = 0x20;
54 const MASTER_SLAVE = 0x40;
55 const NMI_ENABLE = 0x80;
56 }
57}
58
59impl Ctrl {
60 pub fn new() -> Self {
61 let mut ctrl = Self::default();
62 ctrl.write(0);
63 ctrl
64 }
65
66 pub fn write(&mut self, val: u8) {
67 self.bits = Bits::from_bits_truncate(val);
68 self.spr_select = self.bits.contains(Bits::SPR_SELECT) as u16 * 0x1000;
70 self.bg_select = self.bits.contains(Bits::BG_SELECT) as u16 * 0x1000;
72 self.spr_height = self.bits.contains(Bits::SPR_HEIGHT) as u32 * 8 + 8;
74 self.master_slave = self.bits.contains(Bits::MASTER_SLAVE) as u8;
76 self.nmi_enabled = self.bits.contains(Bits::NMI_ENABLE);
77 self.nametable_addr = match self.bits.bits() & 0b11 {
78 0b00 => NAMETABLE1,
79 0b01 => NAMETABLE2,
80 0b10 => NAMETABLE3,
81 0b11 => NAMETABLE4,
82 _ => unreachable!("impossible nametable_addr"),
83 };
84 self.vram_increment = self.bits.contains(Bits::VRAM_INCREMENT) as u16 * 31 + 1
86 }
87
88 pub const fn nametable_select(&self) -> u8 {
89 self.bits.bits() & 0b11
90 }
91}
92
93impl Reset for Ctrl {
94 fn reset(&mut self, _kind: ResetKind) {
96 self.write(0);
97 }
98}