Skip to content

Commit e5eb82f

Browse files
committed
chore: PPU registers (cont)
1 parent 99d2c6c commit e5eb82f

File tree

7 files changed

+210
-86
lines changed

7 files changed

+210
-86
lines changed

Cargo.lock

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "0.1.0"
44
edition = "2021"
55

66
[dependencies]
7+
bitflags = "2.6.0"
78
env_logger = "0.11.5"
89
log = "0.4.22"
910
rand = "0.8.5"

justfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ run:
44
lint:
55
cargo clippy --all --all-features --tests -- -D warnings
66

7+
lint_watch:
8+
git ls-files | entr just lint
9+
710
lint_fix:
811
cargo clippy --all --all-features --tests --fix
912

@@ -14,7 +17,7 @@ test:
1417
cargo test
1518

1619
test_watch:
17-
git ls-files | entr cargo test
20+
git ls-files | entr just test
1821

1922
nestest:
2023
NESTEST_HACK=1 cargo run roms/nestest.nes > myout.log

src/bus.rs

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ pub struct Bus {
1616
}
1717

1818
impl Bus {
19-
pub fn new(rom: Rom, ppu: Ppu) -> Self {
19+
pub fn new(rom: Rom) -> Self {
20+
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
21+
2022
Bus {
2123
cpu_vram: [0; 0x800],
2224
rom,
@@ -37,15 +39,26 @@ impl Bus {
3739
}
3840

3941
impl Mem for Bus {
40-
fn mem_read(&self, addr: u16) -> u8 {
42+
fn mem_read(&mut self, addr: u16) -> u8 {
4143
if (RAM..RAM_MIRROR_END).contains(&addr) {
4244
let a = addr & 0b1110_0111_1111_1111;
4345
self.cpu_vram[a as usize]
4446
} else if (PPU..PPU_MIRROR_END).contains(&addr) {
4547
// The PPU exposes 8 registers. They are mirrored every 8 bytes in this range.
46-
let addr = (addr % 8) + 0x2000;
47-
48-
todo!("PPU NYI")
48+
let register_idx = addr % 8;
49+
match register_idx {
50+
0 | 1 | 3 | 5 | 6 => panic!(
51+
"attempt to read from write-only PPU register: 0x200{}",
52+
register_idx
53+
),
54+
2 => todo!("NYI: read PPU Status"),
55+
4 => todo!("NYI: read OAM data (sprite data)"),
56+
7 => self.ppu.read_data(),
57+
8..=u16::MAX => panic!("invalid PPU register IDX: {}", register_idx),
58+
}
59+
} else if addr == 0x4016 {
60+
// 2.9 OAMDMA - Sprite DMA ($4014 write)
61+
panic!("attempt to read from write-only PPU register: 0x4016 (OAMDMA - Sprite DMA)");
4962
} else if (PRG_ROM_START..=PRG_ROM_END).contains(&addr) {
5063
self.read_prg_rom(addr)
5164
} else {
@@ -58,7 +71,22 @@ impl Mem for Bus {
5871
let a = addr & 0b1110_0111_1111_1111;
5972
self.cpu_vram[a as usize] = data
6073
} else if (PPU..PPU_MIRROR_END).contains(&addr) {
61-
todo!("PPU NYI")
74+
// The PPU exposes 8 registers. They are mirrored every 8 bytes in this range.
75+
let register_idx = addr % 8;
76+
match register_idx {
77+
0 => self.ppu.write_to_ctrl(data),
78+
1 => todo!("write to PPU Mask"),
79+
2 => panic!("attempt to write to read-only PPU register: 0x2002 (Status)",),
80+
3 => todo!("write to OAM Addr"),
81+
4 => todo!("write to OAM Data"),
82+
5 => todo!("write to PPU Scroll"),
83+
6 => self.ppu.write_to_addr(data),
84+
7 => self.ppu.write_to_data(data),
85+
8..=u16::MAX => panic!("invalid PPU register IDX: {}", register_idx),
86+
}
87+
} else if addr == 0x4016 {
88+
// 2.9 OAMDMA - Sprite DMA ($4014 write)
89+
panic!("attempt to read from write-only PPU register: 0x4016 (OAMDMA - Sprite DMA)");
6290
} else if (PRG_ROM_START..=PRG_ROM_END).contains(&addr) {
6391
panic!("attempt to write to ROM cartridge")
6492
} else {
@@ -74,8 +102,7 @@ mod tests {
74102
#[test]
75103
fn test_read_mirroring() {
76104
let rom = Rom::new_test_rom(vec![]);
77-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
78-
let mut bus = Bus::new(rom, ppu);
105+
let mut bus = Bus::new(rom);
79106
bus.cpu_vram[0] = 123;
80107

81108
assert_eq!(bus.mem_read(0), 123);
@@ -87,8 +114,7 @@ mod tests {
87114
#[test]
88115
fn test_write_mirroring() {
89116
let rom = Rom::new_test_rom(vec![]);
90-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
91-
let mut bus = Bus::new(rom, ppu);
117+
let mut bus = Bus::new(rom);
92118

93119
bus.mem_write(0, 1);
94120
assert_eq!(bus.cpu_vram[0], 1);

src/core.rs

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ use std::env;
33
use crate::{
44
bus::Bus,
55
ops::{is_official, lookup_opcode, OpName},
6-
ppu::Ppu,
76
rom::Rom,
87
utility::addr_from,
98
};
@@ -72,11 +71,11 @@ const DEFAULT_STACK_POINTER: u8 = 0xfd;
7271
const DEFAULT_STATUS: u8 = 0b100100;
7372

7473
pub trait Mem {
75-
fn mem_read(&self, addr: u16) -> u8;
74+
fn mem_read(&mut self, addr: u16) -> u8;
7675

7776
fn mem_write(&mut self, addr: u16, val: u8);
7877

79-
fn mem_read_u16(&self, addr: u16) -> u16 {
78+
fn mem_read_u16(&mut self, addr: u16) -> u16 {
8079
// NES CPU uses Little-Endian addressing
8180
let lo = self.mem_read(addr);
8281
let hi = self.mem_read(addr + 1);
@@ -94,7 +93,7 @@ pub trait Mem {
9493
}
9594

9695
impl Mem for Cpu {
97-
fn mem_read(&self, addr: u16) -> u8 {
96+
fn mem_read(&mut self, addr: u16) -> u8 {
9897
self.bus.mem_read(addr)
9998
}
10099

@@ -106,15 +105,14 @@ impl Mem for Cpu {
106105
impl Cpu {
107106
pub fn new() -> Self {
108107
let rom = Rom::new_test_rom(vec![]);
109-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
110108
Cpu {
111109
pc: 0,
112110
sp: DEFAULT_STACK_POINTER,
113111
a: 0,
114112
x: 0,
115113
y: 0,
116114
status: DEFAULT_STATUS,
117-
bus: Bus::new(rom, ppu),
115+
bus: Bus::new(rom),
118116
}
119117
}
120118

@@ -158,13 +156,13 @@ impl Cpu {
158156
//
159157

160158
/// used for the "index indirect" and "indirect indexed" lookups
161-
fn mem_read_zero_page_wrapping(&self, ptr: u8) -> u16 {
159+
fn mem_read_zero_page_wrapping(&mut self, ptr: u8) -> u16 {
162160
let lo = self.mem_read(ptr as u16);
163161
let hi = self.mem_read(ptr.wrapping_add(1) as u16);
164162
(hi as u16) << 8 | (lo as u16)
165163
}
166164

167-
fn get_operand_address(&self, mode: &AddressingMode) -> u16 {
165+
fn get_operand_address(&mut self, mode: &AddressingMode) -> u16 {
168166
match mode {
169167
AddressingMode::Immediate => self.pc,
170168
AddressingMode::ZeroPage => self.mem_read(self.pc) as u16,
@@ -208,16 +206,15 @@ impl Cpu {
208206
//
209207

210208
pub fn load_rom(&mut self, rom: Rom) {
211-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
212-
self.set_bus(Bus::new(rom, ppu));
209+
self.set_bus(Bus::new(rom));
213210
}
214211

215212
// Test Helpers
216213

217214
fn _load_test_rom(&mut self, program: Vec<u8>) {
218215
let rom = Rom::new_test_rom(program);
219-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
220-
self.set_bus(Bus::new(rom, ppu));
216+
217+
self.set_bus(Bus::new(rom));
221218
}
222219

223220
fn _load_and_run(&mut self, program: Vec<u8>) {
@@ -828,7 +825,7 @@ impl Cpu {
828825
val != 0
829826
}
830827

831-
pub fn trace(&self) -> String {
828+
pub fn trace(&mut self) -> String {
832829
// C000 4C F5 C5 JMP $C5F5 A:00 X:00 Y:00 P:24 SP:FD PPU: 0, 21 CYC:7
833830

834831
let code = self.mem_read(self.pc);
@@ -1625,8 +1622,8 @@ mod tests {
16251622
#[test]
16261623
fn test_format_trace() {
16271624
let rom = Rom::new_test_rom(vec![]);
1628-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
1629-
let mut bus = Bus::new(rom, ppu);
1625+
1626+
let mut bus = Bus::new(rom);
16301627

16311628
bus.mem_write(100, 0xa2);
16321629
bus.mem_write(101, 0x01);
@@ -1661,8 +1658,7 @@ mod tests {
16611658
#[test]
16621659
fn test_format_mem_access() {
16631660
let rom = Rom::new_test_rom(vec![]);
1664-
let ppu = Ppu::new(rom.chr_rom.clone(), rom.mirroring);
1665-
let mut bus = Bus::new(rom, ppu);
1661+
let mut bus = Bus::new(rom);
16661662
// ORA ($33), Y
16671663
bus.mem_write(100, 0x11);
16681664
bus.mem_write(101, 0x33);

src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn color(byte: u8) -> Color {
106106
}
107107
}
108108

109-
fn read_screen_state(cpu: &Cpu, screen: &mut [u8; 32 * 3 * 32]) -> bool {
109+
fn read_screen_state(cpu: &mut Cpu, screen: &mut [u8; 32 * 3 * 32]) -> bool {
110110
let mut screen_idx = 0;
111111
let mut updated = false;
112112
for i in 0x0200..0x0600 {

0 commit comments

Comments
 (0)