Skip to content

Commit

Permalink
Implement Address register
Browse files Browse the repository at this point in the history
  • Loading branch information
lyrakisk committed Nov 25, 2024
1 parent cd2c34b commit c94f6cf
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 30 deletions.
4 changes: 2 additions & 2 deletions src/cpu/mappers/basic_mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Memory for BasicMapper {
0x2003 => todo!("OAMADDR register is not implemented yet!"),
0x2004 => todo!("OAMDATA register is not implemented yet!"),
0x2005 => panic!("Scroll register is write-only!"),
0x2006 => panic!("Address register is not implemented yet!"),
0x2006 => panic!("Address register is write-only!"),
0x2007 => panic!("Data register is not implemented yet!"),
ROM_START..=ROM_END => self.rom.prg_rom[self.calculate_rom_address(address) as usize],
_ => panic!("Can't read address {}", address),
Expand All @@ -66,7 +66,7 @@ impl Memory for BasicMapper {
0x2003 => todo!("OAMADDR register is not implemented yet!"),
0x2004 => todo!("OAMDATA register is not implemented yet!"),
0x2005 => panic!("Scroll register is not implemented yet!"),
0x2006 => panic!("Address register is not implemented yet!"),
0x2006 => self.ppu.borrow_mut().write_address(data),
0x2007 => panic!("Data register is not implemented yet!"),

0x4016..=0x4017 => {
Expand Down
67 changes: 54 additions & 13 deletions src/ppu/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
mod frame;
mod registers;
use registers::Register;
use registers::write_toggle::WriteToggle;
use registers::{Register16, Register8};

use crate::ppu::frame::Frame;
use crate::ppu::registers::address::Address;
use crate::ppu::registers::control::Control;
use crate::ppu::registers::mask::Mask;
use crate::ppu::registers::status::Status;
Expand All @@ -14,10 +16,11 @@ pub struct PPU {
oamaddr: u16,
oamdata: u16,
ppuscroll: u16,
ppuaddr: u16,
address: Address,
ppudata: u16,
pub frame: Frame,
pub vram: [u8; 2048],
w: WriteToggle,
}

impl PPU {
Expand All @@ -29,41 +32,79 @@ impl PPU {
oamaddr: 0b0000_0000,
oamdata: 0b0000_0000,
ppuscroll: 0b0000_0000,
ppuaddr: 0b0000_0000,
address: Address::new(0x0000),
ppudata: 0b0000_0000,
frame: Frame::new(),
vram: [0; 2048]
vram: [0; 2048],
w: WriteToggle::FirstWrite,
}
}

pub fn write_control(&mut self, data: u8) {
self.control.write(data);
self.control.write_u8(data);
}

pub fn read_status(&self) -> u8 {
self.status.read()
self.status.read_u8()
}

pub fn write_mask(&mut self, data: u8) {
self.mask.write(data)
self.mask.write_u8(data)
}

pub fn write_address(&mut self, data: u8) {
match self.w {
WriteToggle::FirstWrite => {
self.address.write_u16((data as u16) << 8);
}
WriteToggle::SecondWrite => {
self.address
.write_u16((self.address.read_u16() & 0xFF00) | (data as u16));
}
}
self.w.toggle();
}

pub fn tick(&mut self) {
todo!()
}
}

#[cfg(test)]
mod test_ppu {
use super::*;
use crate::ppu::registers::Register;
use crate::ppu::registers::Register8;

#[test]
fn test_power_up_state() {
// Test Power-up state as documented in https://www.nesdev.org/wiki/PPU_power_up_state
let ppu = PPU::new();
assert_eq!(0b0000_0000, ppu.control.read());
assert_eq!(0b0000_0000, ppu.mask.read());
assert_eq!(0b1010_0000, ppu.status.read());
assert_eq!(0b0000_0000, ppu.control.read_u8());
assert_eq!(0b0000_0000, ppu.mask.read_u8());
assert_eq!(0b1010_0000, ppu.status.read_u8());
assert_eq!(0b0000_0000, ppu.ppuscroll);
assert_eq!(0b0000_0000, ppu.ppuaddr);
assert_eq!(0b0000_0000, ppu.oamaddr);
assert_eq!(0x0000, ppu.address.read_u16());
assert_eq!(0b0000_0000, ppu.ppudata);
assert_eq!([0; 2048], ppu.vram)
}
}
}

#[test]
fn test_address_register_first_write() {
let mut ppu = PPU::new();

ppu.write_address(0xAA);
assert_eq!(0xAA00, ppu.address.read_u16());
assert_eq!(WriteToggle::SecondWrite, ppu.w);
}

#[test]
fn test_address_register_second_write() {
let mut ppu = PPU::new();
ppu.w = WriteToggle::SecondWrite;

ppu.write_address(0xAA);
assert_eq!(0x00AA, ppu.address.read_u16());
assert_eq!(WriteToggle::FirstWrite, ppu.w);
}
21 changes: 21 additions & 0 deletions src/ppu/registers/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::ppu::registers::Register16;

pub struct Address {
pub value: u16,
}

impl Address {
pub fn new(value: u16) -> Self {
Address { value: value }
}
}

impl Register16 for Address {
fn read_u16(&self) -> u16 {
return self.value;
}

fn write_u16(&mut self, data: u16) {
self.value = data;
}
}
8 changes: 4 additions & 4 deletions src/ppu/registers/control.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ppu::registers::Register;
use crate::ppu::registers::Register8;

pub struct Control {
value: u8,
Expand All @@ -10,12 +10,12 @@ impl Control {
}
}

impl Register for Control {
fn read(&self) -> u8 {
impl Register8 for Control {
fn read_u8(&self) -> u8 {
return self.value;
}

fn write(&mut self, data: u8) {
fn write_u8(&mut self, data: u8) {
self.value = data;
}
}
8 changes: 4 additions & 4 deletions src/ppu/registers/mask.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ppu::registers::Register;
use crate::ppu::registers::Register8;

pub struct Mask {
value: u8,
Expand All @@ -10,12 +10,12 @@ impl Mask {
}
}

impl Register for Mask {
fn read(&self) -> u8 {
impl Register8 for Mask {
fn read_u8(&self) -> u8 {
return self.value;
}

fn write(&mut self, data: u8) {
fn write_u8(&mut self, data: u8) {
self.value = data;
}
}
16 changes: 13 additions & 3 deletions src/ppu/registers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
pub mod address;
pub mod control;
pub mod mask;
pub mod status;
pub trait Register {
fn read(&self) -> u8;
fn write(&mut self, data: u8);
pub mod write_toggle;

pub trait Register8 {
fn read_u8(&self) -> u8;
fn write_u8(&mut self, data: u8);
}

pub trait Register16 {
fn read_u16(&self) -> u16;

// we leave it to the PPU to decide if it's going to write the high or low order byte, based on the value of its internal w register
fn write_u16(&mut self, data: u16);
}
8 changes: 4 additions & 4 deletions src/ppu/registers/status.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ppu::registers::Register;
use crate::ppu::registers::Register8;

pub struct Status {
value: u8,
Expand All @@ -10,12 +10,12 @@ impl Status {
}
}

impl Register for Status {
fn read(&self) -> u8 {
impl Register8 for Status {
fn read_u8(&self) -> u8 {
return self.value;
}

fn write(&mut self, data: u8) {
fn write_u8(&mut self, data: u8) {
self.value = data;
}
}
30 changes: 30 additions & 0 deletions src/ppu/registers/write_toggle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#[derive(PartialEq, Debug)]
pub enum WriteToggle {
FirstWrite,
SecondWrite,
}

impl WriteToggle {
pub fn toggle(&mut self) {
match self {
Self::FirstWrite => *self = Self::SecondWrite,
Self::SecondWrite => *self = Self::FirstWrite,
}
}
}

#[cfg(test)]
mod test_write_toggle {
use super::*;

#[test]
fn test_toggle() {
let mut w = WriteToggle::FirstWrite;

w.toggle();
assert_eq!(WriteToggle::SecondWrite, w);

w.toggle();
assert_eq!(WriteToggle::FirstWrite, w)
}
}

0 comments on commit c94f6cf

Please sign in to comment.