@tmustier/pi-nes 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -118,14 +118,14 @@ impl Mapper for MMC1Mapper {
118
118
  fn map(&self, address: u32) -> u32 {
119
119
  let bank: u32;
120
120
  let mut offset = address & 0x3FFF;
121
- let bank_num = self.prg_bank_register.load() as u32 & 0x0F;
121
+ let bank_num = self.prg_bank_register.load() as u32 & 0x1F;
122
122
 
123
123
  match self.control_register.load_bits(2, 2) {
124
124
  0 | 1 => {
125
125
  // switch 32KB at 0x8000, ignoring low bit of bank number
126
126
  // TODO: Fix me
127
127
  offset = offset | (address & 0x4000);
128
- bank = bank_num & 0x0E;
128
+ bank = bank_num & 0x1E;
129
129
  },
130
130
  2 => {
131
131
  // fix first bank at 0x8000 and switch 16KB bank at 0xC000
@@ -438,22 +438,22 @@ impl Ppu {
438
438
  // 0x0000 - 0x1FFF is mapped with cartridge's CHR-ROM if exists.
439
439
  // Otherwise load from VRAM.
440
440
 
441
- match address < 0x2000 && rom.has_chr_rom() {
442
- true => rom.load(address as u32),
443
- false => self.vram.load(self.convert_vram_address(address, rom) as u32)
441
+ if address < 0x2000 {
442
+ return rom.load_chr(address as u32);
444
443
  }
444
+ self.vram.load(self.convert_vram_address(address, rom) as u32)
445
445
  }
446
446
 
447
447
  fn store(&mut self, mut address: u16, value: u8, rom: &mut Rom) {
448
448
  address = address & 0x3FFF; // just in case
449
449
 
450
- // 0x0000 - 0x1FFF is mapped with cartridge's CHR-ROM if exists.
451
- // Otherwise store to VRAM.
450
+ // 0x0000 - 0x1FFF is mapped with cartridge CHR (ROM or RAM).
452
451
 
453
- match address < 0x2000 && rom.has_chr_rom() {
454
- true => rom.store(address as u32, value),
455
- false => self.vram.store(self.convert_vram_address(address, rom) as u32, value)
456
- };
452
+ if address < 0x2000 {
453
+ rom.store_chr(address as u32, value);
454
+ return;
455
+ }
456
+ self.vram.store(self.convert_vram_address(address, rom) as u32, value);
457
457
  }
458
458
 
459
459
  fn convert_vram_address(&self, address: u16, rom: &Rom) -> u16 {
@@ -1365,14 +1365,18 @@ impl Sprite {
1365
1365
  }
1366
1366
 
1367
1367
  fn on(&self, y: u8, height: u8) -> bool {
1368
- (y >= self.get_y()) && (y < self.get_y() + height)
1368
+ let sprite_y = self.get_y() as u16 + 1;
1369
+ let y = y as u16;
1370
+ y >= sprite_y && y < sprite_y + height as u16
1369
1371
  }
1370
1372
 
1371
1373
  fn get_y_in_sprite(&self, y: u8, height: u8) -> u8 {
1372
1374
  // Assumes self.on(y, height) is true
1375
+ let sprite_y = self.get_y() as u16 + 1;
1376
+ let delta = (y as u16 - sprite_y) as u8;
1373
1377
  match self.vertical_flip() {
1374
- true => height - 1 - (y - self.get_y()),
1375
- false => y - self.get_y()
1378
+ true => height - 1 - delta,
1379
+ false => delta
1376
1380
  }
1377
1381
  }
1378
1382
  }
@@ -4,6 +4,7 @@ use mapper::{Mapper, MapperFactory};
4
4
  pub struct Rom {
5
5
  header: RomHeader,
6
6
  memory: Memory,
7
+ chr_ram: Option<Memory>,
7
8
  mapper: Box<dyn Mapper>
8
9
  }
9
10
 
@@ -20,9 +21,20 @@ impl Rom {
20
21
  pub fn new(data: Vec<u8>) -> Self {
21
22
  let header = RomHeader::new(data[0..HEADER_SIZE].to_vec());
22
23
  let mapper = MapperFactory::create(&header);
24
+ let data_start = HEADER_SIZE + if header.has_trainer() { 512 } else { 0 };
25
+ let rom_data = if data.len() > data_start {
26
+ data[data_start..].to_vec()
27
+ } else {
28
+ Vec::new()
29
+ };
30
+ let chr_ram = match header.chr_ram_size_bytes() {
31
+ 0 => None,
32
+ size => Some(Memory::new(vec![0; size])),
33
+ };
23
34
  Rom {
24
35
  header: header,
25
- memory: Memory::new(data[HEADER_SIZE..].to_vec()),
36
+ memory: Memory::new(rom_data),
37
+ chr_ram,
26
38
  mapper: mapper
27
39
  }
28
40
  }
@@ -37,21 +49,63 @@ impl Rom {
37
49
  * In general writing control registers in Mapper via .store() switches bank.
38
50
  */
39
51
  pub fn load(&self, address: u32) -> u8 {
40
- let mut address_in_rom = 0 as u32;
41
52
  if address < 0x2000 {
42
- // load from character rom
43
- address_in_rom += self.header.prg_rom_bank_num() as u32 * 0x4000;
44
- address_in_rom += self.mapper.map_for_chr_rom(address);
45
- } else {
46
- address_in_rom += self.mapper.map(address);
53
+ return self.load_chr(address);
54
+ }
55
+ self.memory.load(self.mapper.map(address))
56
+ }
57
+
58
+ pub fn load_chr(&self, address: u32) -> u8 {
59
+ let mapped = self.map_chr_address(address);
60
+ if let Some(chr_ram) = &self.chr_ram {
61
+ return chr_ram.load(mapped);
62
+ }
63
+ let offset = self.prg_rom_size() + mapped;
64
+ self.memory.load(offset)
65
+ }
66
+
67
+ pub fn store_chr(&mut self, address: u32, value: u8) {
68
+ let size = match self.chr_ram.as_ref() {
69
+ Some(ram) => ram.capacity(),
70
+ None => return,
71
+ };
72
+ if size == 0 {
73
+ return;
74
+ }
75
+ let mapped = self.mapper.map_for_chr_rom(address) % size;
76
+ if let Some(chr_ram) = self.chr_ram.as_mut() {
77
+ chr_ram.store(mapped, value);
47
78
  }
48
- self.memory.load(address_in_rom)
49
79
  }
50
80
 
51
81
  pub fn load_without_mapping(&self, address: u32) -> u8 {
52
82
  self.memory.load(address)
53
83
  }
54
84
 
85
+ fn prg_rom_size(&self) -> u32 {
86
+ self.header.prg_rom_bank_num() as u32 * 0x4000
87
+ }
88
+
89
+ fn chr_rom_size(&self) -> u32 {
90
+ self.header.chr_rom_bank_num() as u32 * 0x2000
91
+ }
92
+
93
+ fn chr_ram_size(&self) -> u32 {
94
+ self.chr_ram.as_ref().map_or(0, |ram| ram.capacity())
95
+ }
96
+
97
+ fn map_chr_address(&self, address: u32) -> u32 {
98
+ let size = if self.chr_ram.is_some() {
99
+ self.chr_ram_size()
100
+ } else {
101
+ self.chr_rom_size()
102
+ };
103
+ if size == 0 {
104
+ return 0;
105
+ }
106
+ self.mapper.map_for_chr_rom(address) % size
107
+ }
108
+
55
109
  /**
56
110
  * In general writing with ROM address space updates control registers in Mapper.
57
111
  */
@@ -135,6 +189,13 @@ impl RomHeader {
135
189
  self.chr_rom_bank_num() > 0
136
190
  }
137
191
 
192
+ fn chr_ram_size_bytes(&self) -> usize {
193
+ if self.has_chr_rom() {
194
+ return 0;
195
+ }
196
+ 0x2000
197
+ }
198
+
138
199
  fn control_byte1(&self) -> u8 {
139
200
  self.load(6)
140
201
  }
@@ -180,8 +241,8 @@ impl RomHeader {
180
241
  self.extract_bits(self.control_byte1(), 1, 1) == 1
181
242
  }
182
243
 
183
- fn _trainer_512_bytes(&self) -> u8 {
184
- self.extract_bits(self.control_byte1(), 2, 1)
244
+ pub fn has_trainer(&self) -> bool {
245
+ self.extract_bits(self.control_byte1(), 2, 1) == 1
185
246
  }
186
247
 
187
248
  fn four_screen_mirroring(&self) -> bool {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmustier/pi-nes",
3
- "version": "0.2.13",
3
+ "version": "0.2.15",
4
4
  "description": "NES emulator extension for pi",
5
5
  "keywords": [
6
6
  "pi-package",