ines/
lib.rs

1const HEADER_BYTES: usize = 16;
2const K: usize = 1024;
3pub const PRG_ROM_BLOCK_BYTES: usize = 16 * K;
4pub const CHR_ROM_BLOCK_BYTES: usize = 4 * K;
5const HEADER_CHECKSUM: [u8; 4] = [78, 69, 83, 26];
6
7#[derive(Debug, Clone, Copy)]
8pub enum Mirroring {
9    Horizontal,
10    Vertical,
11}
12
13#[derive(Debug, Clone, Copy)]
14pub enum Mapper {
15    Nrom,
16    Mmc1,
17}
18
19#[derive(Debug, Clone, Copy)]
20pub enum Error {
21    UnimplementedMapper { code: u8 },
22}
23
24impl Mapper {
25    fn encode(self) -> u8 {
26        match self {
27            Mapper::Nrom => 0,
28            Mapper::Mmc1 => 1,
29        }
30    }
31    fn decode(code: u8) -> Result<Self, Error> {
32        match code {
33            0 => Ok(Mapper::Nrom),
34            1 => Ok(Mapper::Mmc1),
35            other => Err(Error::UnimplementedMapper { code: other }),
36        }
37    }
38}
39
40#[derive(Debug)]
41pub struct Header {
42    pub num_prg_rom_blocks: u8,
43    pub num_chr_rom_blocks: u8,
44    pub mapper: Mapper,
45    pub mirroring: Mirroring,
46    pub four_screen_vram: bool,
47}
48
49impl Header {
50    fn parse(buffer: &[u8]) -> Result<Self, Error> {
51        let checksum = &buffer[0..HEADER_CHECKSUM.len()];
52        if checksum != &HEADER_CHECKSUM {
53            panic!("Invalid checksum");
54        }
55        let four_screen_vram = buffer[6] & (1 << 3) != 0;
56        let mirroring = if buffer[6] & (1 << 0) != 0 {
57            Mirroring::Vertical
58        } else {
59            Mirroring::Horizontal
60        };
61        let num_prg_rom_blocks = buffer[4];
62        let num_chr_rom_blocks = buffer[5];
63        let mapper_number = (buffer[7] & 0xF0) | (buffer[6] >> 4);
64        let mapper = Mapper::decode(mapper_number)?;
65        Ok(Self {
66            num_prg_rom_blocks,
67            num_chr_rom_blocks,
68            mapper,
69            mirroring,
70            four_screen_vram,
71        })
72    }
73    fn prg_rom_bytes(&self) -> usize {
74        self.num_prg_rom_blocks as usize * PRG_ROM_BLOCK_BYTES
75    }
76    fn chr_rom_bytes(&self) -> usize {
77        self.num_chr_rom_blocks as usize * CHR_ROM_BLOCK_BYTES
78    }
79    fn encode(&self, buffer: &mut Vec<u8>) {
80        (&mut buffer[0..HEADER_CHECKSUM.len()]).copy_from_slice(&HEADER_CHECKSUM);
81        buffer[4] = self.num_prg_rom_blocks;
82        buffer[5] = self.num_chr_rom_blocks;
83        let mapper_number = self.mapper.encode();
84        buffer[6] = mapper_number << 4;
85        buffer[7] = mapper_number & 0xF0;
86        match self.mirroring {
87            Mirroring::Vertical => {
88                buffer[6] |= 1 << 0;
89            }
90            Mirroring::Horizontal => {
91                buffer[6] &= !(1 << 0);
92            }
93        }
94        if self.four_screen_vram {
95            buffer[6] |= 1 << 3;
96        } else {
97            buffer[6] &= !(1 << 3);
98        }
99    }
100}
101
102pub struct Ines {
103    pub header: Header,
104    pub prg_rom: Vec<u8>,
105    pub chr_rom: Vec<u8>,
106}
107
108impl Ines {
109    pub fn parse(buffer: &[u8]) -> Result<Self, Error> {
110        let header_raw = &buffer[0..HEADER_BYTES];
111        let data = &buffer[HEADER_BYTES..];
112        let header = Header::parse(header_raw)?;
113        log::info!("INES Header:\n{:#?}", header);
114        log::info!("Size (bytes): 0x{:X} ({})", data.len(), data.len());
115        let prg_rom_bytes = header.prg_rom_bytes();
116        let chr_rom_bytes = header.chr_rom_bytes();
117        let prg_rom = data[0..prg_rom_bytes].to_vec();
118        let chr_rom = data[prg_rom_bytes..(prg_rom_bytes + chr_rom_bytes)].to_vec();
119        Ok(Self {
120            header,
121            prg_rom,
122            chr_rom,
123        })
124    }
125    pub fn encode(&self, buffer: &mut Vec<u8>) {
126        log::info!("INES Header:\n{:#?}", self.header);
127        buffer.resize(
128            HEADER_BYTES + self.header.prg_rom_bytes() + self.header.chr_rom_bytes(),
129            0,
130        );
131        log::info!(
132            "Encoding into buffer of size (bytes): 0x{:X} ({})",
133            buffer.len(),
134            buffer.len()
135        );
136        self.header.encode(buffer);
137        let prg_start = HEADER_BYTES;
138        let chr_start = prg_start + self.header.prg_rom_bytes();
139        (&mut buffer[prg_start..(prg_start + self.prg_rom.len())]).copy_from_slice(&self.prg_rom);
140        (&mut buffer[chr_start..(chr_start + self.chr_rom.len())]).copy_from_slice(&self.chr_rom);
141    }
142}