diff --git a/doc/nes_architecture b/doc/nes_architecture new file mode 100644 index 0000000..0da7a16 --- /dev/null +++ b/doc/nes_architecture @@ -0,0 +1 @@ +7VvbcqM4EP0aqmYeMgXiYvzoS7JTtfFuKs5sdh4Vo9hMMPIK2bHn61eAxE2YYGOMJ5OnWE1LQPfp090SUfTRcvsHgavFBDvIU4DqbBV9rACgaT2d/Qklu1jSA1YsmBPX4UqpYOr+RFyocunadVCQU6QYe9Rd5YUz7PtoRnMySAh+zas9Yy9/1xWcI0kwnUFPlj66Dl2I97L66YWvyJ0v+K1t0IsvLKFQ5m8SLKCDXzMi/VrRRwRjGv9abkfIC40n7BLPu9lzNXkwgnxaZ4L3aNkb76/5K/J3wx9TePsyxFfhhOjh6E68MXKYAfgQE7rAc+xD7zqVDgle+w4Kl1XZKNW5xXjFhBoT/kCU7rg34ZpiJlrQpcevoq1L/w2nfwEmH37nq4W/x9vsYCcGPiW77Kxw/D17MZ0XjcTEgEJCByEWmMDHPhKyG9fzEh2CXxIPM98MY7uExthrby4K8JrMUIWRBW4hmSNa5YwEFSycEF4i9hZsHkEepO4m/xyQ43qe6PGp7EXhLqOwwq5Pg8zKd6GAKfAQtTk8eXxaBRAVtI1+lTr7Ed9ejDLvkYoiXB6CUf0DoxeDUe0XAKmtnh+kuhHfcgO9NTcCdBxSitxb+MSyZA5t0HPnPvs9Y45DhAk2iFCXpaEBv7B0HScGNgrcn/ApWi9EBTcdW9wcKuY4QUW4ANrm3MFzJJ+cZqYsXioiUHY6X56B3TCsnMkFng6DRepJoYKfnwOGx7z7TuOwj8x3OaxiXj6pgL55dlLRJE4Z3X2TYBu8uksPRs7dG/qS8/YGs563iia49DWtfoGQLTKFb2LOMv/kgvfgSJWsMKi2QgRxHoKMumqaZb8H9trKKNjKkG2lgRJbJcKT2woY3bLaUaR2PKfNPBgE7qxAa9ppSQzULY26IDGzgEG7msU0vUq9pfrd6hKTWhaRadZ9C5Q5SGbS7qVm2togbVq/N6Mn+wMKFwMFuwu+sgpVl2ZWE1ZR39B7lfo9UKnfUvNnSSXKO2r+9uAkaf408/KbPbXUF53wznG0cxDr7C+L8sTTUaHUDfFYeWIQTcxe4inoG2b/DETSk4jEgRS+DyLR1XK/J0Si2ma+xwaXzitActdd6w26Uew6a3foaltdpzisy9jhig2ZLUYP97cKsDz2CMMnlhCtOY2sEEscd1MUBSvoCxlfYzKY/ikus8fLamTEJWvVW376MHj4Nm3xBuPBw6DF5Qfj8f2ByxfwybBIy4nEQ8+0GY2EWTGIE2Saf0bYwyStjp9ZfiqIasXJIYdoYpV87Ohy6PRLIqe9rS1NcsbvuV3Tal1i1qxLmm7gNIKCKVHo4/1gwiSfwMvnllMKsN5OKcnmZjYwrLYCw5as8c/ZrCG1kJohW8MqsUa/tfwqHwTkckTGFtZ/6/CDkmHI6Vecxln2USMmT65WpRUfsocOOT04Pmmd9IEgpcR9WlMUxfAFPdgKeoxnD36c2tn3FGX82fNv9W5Bvr4vSb9aWeVqtnZcYn7k31NnW+1c5yXNKi85376fThvsOU/ny1+pX3SRUkSOUy690+51GqnKETt4mvLL7eDVjt2mp0in2cLjQVx3C6+w5dfSFp78ucIs6DbL5D410uqBt0maqXXo1RVym24+Nyvk5Q3DETMScUMTnLerKevx9LKPVUCvtbZG/mbyjuA5gUsmvP970tgiB52Ai1640PzV/KSnvd5PPltkkIEzKmx0wxtj+wSN8QkMlnTG3XXL8iFKez0gdb2wL41rx4voSkHkGqAC04pgsbU/K/H/qXw0qnJgNdgpLuUBvTVUy1ti2cBXP+EVdcMCoRsW0IrHpTV3EFtjAeGcjL0mcLViMO2EJLW3WbLs5OEI87Bh+k9lcVWb/muefv0/ \ No newline at end of file diff --git a/src/bus.rs b/src/bus.rs index 36722e6..1d06327 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,15 +1,24 @@ -use std::fmt; +use std::{ + fmt, + rc::Rc, + cell::RefCell, +}; -use crate::peripherals::{Peripheral, Ram}; +use crate::peripherals::{ + Peripheral, + Ram, + Mapper, + Ppu, +}; -pub struct Bus { +pub struct Bus { ram: Ram<0x800>, - ppu: Ram<0x8>, - apu: Ram<0x1F>, - cartridge: Ram<0xBFE0>, + ppu: Ppu, + apu: Ram<0x1F>,//TODO + cartridge: Rc>, } -impl fmt::Debug for Bus { +impl fmt::Debug for Bus { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Bus") @@ -18,7 +27,7 @@ impl fmt::Debug for Bus { } } -impl Peripheral for Bus { +impl Peripheral for Bus { fn read_addr(&self, addr: u16) -> u8 { @@ -26,7 +35,7 @@ impl Peripheral for Bus { 0x0000..=0x1FFF => self.ram.read_addr(addr % 0x0800), //RAM is mirrored 3 times 0x2000..=0x3FFF => self.ppu.read_addr(addr % 0x8), //PPU is mirrored every 8 bytes 0x4000..=0x401F => self.apu.read_addr(addr), - 0x4020..=0xFFFF => self.cartridge.read_addr(addr), + 0x4020..=0xFFFF => self.cartridge.borrow().read_addr(addr), } } @@ -36,14 +45,14 @@ impl Peripheral for Bus { 0x0000..=0x1FFF => self.ram.write_addr(addr % 0x0800, data), 0x2000..=0x3FFF => self.ppu.write_addr(addr % 0x8, data), 0x4000..=0x401F => self.apu.write_addr(addr, data), - 0x4020..=0xFFFF => self.cartridge.write_addr(addr, data), + 0x4020..=0xFFFF => self.cartridge.borrow_mut().write_addr(addr, data), }; } } -impl Bus { +impl Bus { - pub fn new() -> Self { + pub fn new(mapper: Rc>) -> Self { let mut ram = Ram::<0x800>::new(); @@ -106,9 +115,9 @@ impl Bus { Bus { ram, - ppu: Ram::<0x8>::new(), + ppu: Ppu::new(mapper.clone()), apu: Ram::<0x1F>::new(), - cartridge: Ram::<0xBFE0>::new(), + cartridge: mapper, } } } diff --git a/src/cpu.rs b/src/cpu.rs index 648d1be..e2ef460 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,14 +1,18 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; +use std::{ + fmt, + rc::Rc, + cell::RefCell, +}; use bitflags::bitflags; use crate::{ - bus::FileBus, - peripherals::Peripheral, + bus::Bus, + peripherals::{Peripheral, Mapper}, }; -use std::fmt; //-------------------------------------------------------------------------------------------------- @@ -138,17 +142,17 @@ bitflags! { } } -pub struct Cpu { +pub struct Cpu { a: u8, x: u8, y: u8, pc: u16, s: u8, p: StatusReg, - bus: FileBus, + bus: Bus, } -impl fmt::Debug for Cpu { +impl fmt::Debug for Cpu { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_struct("Cpu") @@ -164,12 +168,12 @@ impl fmt::Debug for Cpu { } -impl Cpu { +impl Cpu { - pub fn new() -> Self { + pub fn new(mapper: Rc>) -> Self { // read initial PC value from reset vector - let bus = FileBus::new(); + let bus = Bus::new(mapper); let pc_lo = bus.read_addr(0xFFFC) as u16; let pc_hi = bus.read_addr(0xFFFD) as u16; diff --git a/src/main.rs b/src/main.rs index df9fb12..3dde190 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use cpu::Cpu; mod bus; mod peripherals; +use peripherals::mapper::Nrom; mod utils; fn main() -> Result<(), &'static str> { @@ -15,7 +16,11 @@ fn main() -> Result<(), &'static str> { dpi::LogicalSize, }; use mini_gl_fb::config; - use std::fmt::Write; + use std::{ + fmt::Write, + rc::Rc, + cell::RefCell, + }; // setup setup_logger().map_err(|_| "Failed to setup logger")?; @@ -31,7 +36,8 @@ fn main() -> Result<(), &'static str> { let mut renderer = FontRenderer::new(20.0, [0u8, 0, 0]); // first image - let mut cpu = Cpu::new(); + let mapper = Rc::new(RefCell::new(Nrom::new())); + let mut cpu = Cpu::new(mapper); let mut debug_str = String::new(); write!(debug_str, "{:#?}", cpu).unwrap(); buffer.fill([20, 20], [760, 560], Pixel::rgba(255, 255, 255, 255)); diff --git a/src/peripherals.rs b/src/peripherals.rs index ed1e0e9..83db315 100644 --- a/src/peripherals.rs +++ b/src/peripherals.rs @@ -1,4 +1,11 @@ -use std::fmt; + +mod ram; +mod ppu; +pub mod mapper; + +pub use ram::Ram; +pub use ppu::Ppu; +pub use mapper::Mapper; //-------------------------------------------------------------------------------------------------- pub trait Peripheral { @@ -8,57 +15,3 @@ pub trait Peripheral { fn write_addr(&mut self, addr: u16, data: u8); } -//-------------------------------------------------------------------------------------------------- -pub struct Ram { - pub buffer: [u8; SIZE], -} - -impl fmt::Debug for Ram { - - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - for i in 0x100..=0x1FF { - if i%0x10 == 0 { - f.write_fmt(format_args!("\n {:0>4X}", i))?; - } - f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))? - } - - Ok(()) - } -} - -impl Peripheral for Ram { - - fn read_addr(&self, addr: u16) -> u8 { - self.buffer[addr as usize] - } - - fn write_addr(&mut self, addr: u16, data: u8) { - self.buffer[addr as usize] = data; - } -} - -impl Ram { - - pub fn new() -> Self { - - Ram { - buffer: [0u8; SIZE], - } - } - - pub fn from_file(file: &str) -> Self { - use std::{ - fs::File, - io::Read, - }; - - let mut f = File::open(file).unwrap(); - let mut buffer = [0u8; SIZE]; - f.read_exact(&mut buffer).unwrap(); - - Ram { - buffer, - } - } -} diff --git a/src/peripherals/mapper.rs b/src/peripherals/mapper.rs new file mode 100644 index 0000000..a25a5a2 --- /dev/null +++ b/src/peripherals/mapper.rs @@ -0,0 +1,42 @@ +use super::Peripheral; + +//--Mapper struct----------------------------------------------------------------------------------- +///A trait used as API for the different implementations of mappers in cartridges +/// +///A Mapper is a special `Peripheral` that can also be read by the `Ppu`. The exact memory layout +///is defined by the implementation +pub trait Mapper: Peripheral { + + ///read the specified 16 bits address using the ppu bus + fn ppu_read_addr(&self, addr: u16) -> u8; +} + +pub struct Nrom { + +} + +impl Peripheral for Nrom { + + fn read_addr(&self, _addr: u16) -> u8 { + unimplemented!(); + } + + fn write_addr(&mut self, _addr: u16, _data: u8) { + unimplemented!(); + } +} + +impl Mapper for Nrom { + + fn ppu_read_addr(&self, _addr: u16) -> u8 { + unimplemented!(); + } +} + +impl Nrom { + + pub fn new() -> Self { + unimplemented!(); + } +} + diff --git a/src/peripherals/ppu.rs b/src/peripherals/ppu.rs new file mode 100644 index 0000000..306d4c9 --- /dev/null +++ b/src/peripherals/ppu.rs @@ -0,0 +1,78 @@ +use std::{ + rc::Rc, + cell::RefCell, +}; + +use bitflags::bitflags; + +use crate::{ + peripherals::{Peripheral, Ram, Mapper}, +}; + +//-------------------------------------------------------------------------------------------------- +bitflags! { + struct Ctrl: u8 { + const Nl = 0x1 << 0; + const Nh = 0x1 << 1; + const I = 0x1 << 2; + const S = 0x1 << 3; + const B = 0x1 << 4; + const H = 0x1 << 5; + const P = 0x1 << 6; + const V = 0x1 << 7; + } +} + +bitflags! { + struct Mask: u8 { + const Gr = 0x1 << 0; + const m = 0x1 << 1; + const M = 0x1 << 2; + const b = 0x1 << 3; + const s = 0x1 << 4; + const R = 0x1 << 5; + const G = 0x1 << 6; + const B = 0x1 << 7; + } +} + +bitflags! { + struct Status: u8 { + const O = 0x1 << 5; + const S = 0x1 << 6; + const V = 0x1 << 7; + } +} + +pub struct Ppu { + vbus: Rc>, + ctrl: Ctrl, + mask: Mask, + status: Status, + scroll: u8, + addr: u8, + data: u8, + oam_addr: u8, + oam_data: u8, + oam_dma: u8, + oam: Ram<0x100>, + blanking: bool, +} + +impl Peripheral for Ppu { + + fn read_addr(&self, _addr: u16) -> u8 { + unimplemented!(); + } + + fn write_addr(&mut self, _addr: u16, _data: u8) { + unimplemented!(); + } +} + +impl Ppu { + + pub fn new(_mapper: Rc>) -> Self { + unimplemented!(); + } +} diff --git a/src/peripherals/ram.rs b/src/peripherals/ram.rs new file mode 100644 index 0000000..e56e975 --- /dev/null +++ b/src/peripherals/ram.rs @@ -0,0 +1,59 @@ +use std::fmt; + +use super::Peripheral; + +//-------------------------------------------------------------------------------------------------- +pub struct Ram { + pub buffer: [u8; SIZE], +} + +impl fmt::Debug for Ram { + + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for i in 0x100..=0x1FF { + if i%0x10 == 0 { + f.write_fmt(format_args!("\n {:0>4X}", i))?; + } + f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))? + } + + Ok(()) + } +} + +impl Peripheral for Ram { + + fn read_addr(&self, addr: u16) -> u8 { + self.buffer[addr as usize] + } + + fn write_addr(&mut self, addr: u16, data: u8) { + self.buffer[addr as usize] = data; + } +} + +impl Ram { + + pub fn new() -> Self { + + Ram { + buffer: [0u8; SIZE], + } + } + + pub fn from_file(file: &str) -> Self { + use std::{ + fs::File, + io::Read, + }; + + let mut f = File::open(file).unwrap(); + let mut buffer = [0u8; SIZE]; + f.read_exact(&mut buffer).unwrap(); + + Ram { + buffer, + } + } +} +