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}