diff --git a/src/bus.rs b/src/bus.rs index 40b751d..d8acc29 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,164 +1,165 @@ use std::{ - fmt, - rc::Rc, - cell::RefCell, + fmt, + rc::Rc, + cell::RefCell, }; use crate::{ - utils::DisplayBuffer, - peripherals::{Peripheral, Ram, Mapper, Ppu}, + utils::DisplayBuffer, + peripherals::{Peripheral, Ram, Mapper, Ppu}, }; pub struct Bus { - ram: Ram<0x800>, - ppu: Ppu, - apu: Ram<0x1F>,//TODO - cartridge: Rc>, + ram: Ram<0x800>, + ppu: Ppu, + apu: Ram<0x1F>,//TODO + cartridge: Rc>, } impl fmt::Debug for Bus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Bus") - .field("ram", &self.ram) - .finish_non_exhaustive() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Bus") + .field("ram", &self.ram) + .finish_non_exhaustive() + } } impl Peripheral for Bus { - fn read_addr(&self, addr: u16) -> u8 { + fn read_addr(&self, addr: u16) -> u8 { - match addr { - 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.borrow().read_addr(addr), - } - } + match addr { + 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.borrow().read_addr(addr), + } + } - fn write_addr(&mut self, addr: u16, data: u8) { + fn write_addr(&mut self, addr: u16, data: u8) { - match addr { - 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.borrow_mut().write_addr(addr, data), - }; - } + match addr { + 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.borrow_mut().write_addr(addr, data), + }; + } } impl Bus { - pub fn new(mapper: Rc>, - screen: Rc>, - pattern_table: Rc>) - -> Self { + pub fn new(mapper: Rc>, + screen: Rc>, + pattern_table: Rc>) + -> Self { - let mut ram = Ram::<0x800>::new(); + let mut ram = Ram::<0x800>::new(); - //TODO temporary for instruction tests - ram.buffer[0x01] = 0xE9; //sbc - ram.buffer[0x02] = (-3 as i8) as u8; - ram.buffer[0x03] = 0x09; - ram.buffer[0x04] = 0x00; - ram.buffer[0x05] = 0xA9; //lda - ram.buffer[0x06] = 0x01; - ram.buffer[0x07] = 0x4C; //jmp - ram.buffer[0x08] = 0x00; - ram.buffer[0x09] = 0x00; - ram.buffer[0x0A] = 0x2A; //fn rol - ram.buffer[0x0B] = 0x90; //bcc - ram.buffer[0x0C] = (-3 as i8) as u8; - ram.buffer[0x0D] = 0x60; //rts - ram.buffer[0x0E] = 0xFD; - ram.buffer[0x0F] = 0x01; - ram.buffer[0x10] = 0x21; - ram.buffer[0x11] = 0x9F; - ram.buffer[0x12] = 0x31; - ram.buffer[0x13] = 0xB0; + //TODO temporary for instruction tests + ram.buffer[0x01] = 0xE9; //sbc + ram.buffer[0x02] = (-3 as i8) as u8; + ram.buffer[0x03] = 0x09; + ram.buffer[0x04] = 0x00; + ram.buffer[0x05] = 0xA9; //lda + ram.buffer[0x06] = 0x01; + ram.buffer[0x07] = 0x4C; //jmp + ram.buffer[0x08] = 0x00; + ram.buffer[0x09] = 0x00; + ram.buffer[0x0A] = 0x2A; //fn rol + ram.buffer[0x0B] = 0x90; //bcc + ram.buffer[0x0C] = (-3 as i8) as u8; + ram.buffer[0x0D] = 0x60; //rts + ram.buffer[0x0E] = 0xFD; + ram.buffer[0x0F] = 0x01; + ram.buffer[0x10] = 0x21; + ram.buffer[0x11] = 0x9F; + ram.buffer[0x12] = 0x31; + ram.buffer[0x13] = 0xB0; - // boundary - ram.buffer[0x14] = 0x3D; - ram.buffer[0x15] = 0xFF; - ram.buffer[0x16] = 0x02; - ram.buffer[0x17] = 0x39; - ram.buffer[0x18] = 0xFE; - ram.buffer[0x19] = 0x02; - ram.buffer[0x1A] = 0x31; - ram.buffer[0x1B] = 0xB2; + // boundary + ram.buffer[0x14] = 0x3D; + ram.buffer[0x15] = 0xFF; + ram.buffer[0x16] = 0x02; + ram.buffer[0x17] = 0x39; + ram.buffer[0x18] = 0xFE; + ram.buffer[0x19] = 0x02; + ram.buffer[0x1A] = 0x31; + ram.buffer[0x1B] = 0xB2; - // ptr to val - ram.buffer[0xA0] = 0xFF; - ram.buffer[0xA1] = 0x01; + // ptr to val + ram.buffer[0xA0] = 0xFF; + ram.buffer[0xA1] = 0x01; - // ptr to val as table - ram.buffer[0xB0] = 0xFD; - ram.buffer[0xB1] = 0x01; - ram.buffer[0xB2] = 0xFE; //boundary - ram.buffer[0xB3] = 0x02; + // ptr to val as table + ram.buffer[0xB0] = 0xFD; + ram.buffer[0xB1] = 0x01; + ram.buffer[0xB2] = 0xFE; //boundary + ram.buffer[0xB3] = 0x02; - // zero page val - ram.buffer[0xFF] = 0x01; + // zero page val + ram.buffer[0xFF] = 0x01; - // val - ram.buffer[0x01FF] = 0x01; - ram.buffer[0x02FF] = 0xFF; //boundary - ram.buffer[0x0300] = 0x03; + // val + ram.buffer[0x01FF] = 0x01; + ram.buffer[0x02FF] = 0xFF; //boundary + ram.buffer[0x0300] = 0x03; - // ptr to test - ram.buffer[0x030F] = 0xFF; - ram.buffer[0x0310] = 0x03; + // ptr to test + ram.buffer[0x030F] = 0xFF; + ram.buffer[0x0310] = 0x03; - // jmp test - ram.buffer[0x0400] = 0xE6; + // jmp test + ram.buffer[0x0400] = 0xE6; - Bus { - ram, - ppu: Ppu::new(mapper.clone(), screen, pattern_table), - apu: Ram::<0x1F>::new(), - cartridge: mapper, - } - } + Bus { + ram, + ppu: Ppu::new(mapper.clone(), screen, pattern_table), + apu: Ram::<0x1F>::new(), + cartridge: mapper, + } + } - pub fn tick(&mut self) { - self.ppu.tick(); - } + pub fn tick(&mut self) { + self.ppu.tick(); + } } /// special Bus only used for testing the emulator pub struct FileBus { - mem: Ram<0x10000>, + mem: Ram<0x10000>, } impl fmt::Debug for FileBus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Bus") - .field("mem", &self.mem) - .finish() - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Bus") + .field("mem", &self.mem) + .finish() + } } impl Peripheral for FileBus { - fn read_addr(&self, addr: u16) -> u8 { - self.mem.read_addr(addr) //RAM is mirrored 3 times - } + fn read_addr(&self, addr: u16) -> u8 { + self.mem.read_addr(addr) //RAM is mirrored 3 times + } - fn write_addr(&mut self, addr: u16, data: u8) { - self.mem.write_addr(addr % 0x0800, data) - } + fn write_addr(&mut self, addr: u16, data: u8) { + self.mem.write_addr(addr % 0x0800, data) + } } impl FileBus { - pub fn new() -> Self { - FileBus { - mem: Ram::from_file("6502_functional_test.bin"), - } - } + #[allow(dead_code)] + pub fn new() -> Self { + FileBus { + mem: Ram::from_file("6502_functional_test.bin"), + } + } } diff --git a/src/cpu.rs b/src/cpu.rs index b57ac60..940b251 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -208,7 +208,7 @@ impl Cpu { // println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode); // } - let cycles = parse_opcode!(self, opcode, + let _cycles = parse_opcode!(self, opcode, 0x69 => adc(mode_immediate), 0x65 => adc(mode_zero_page), 0x75 => adc(mode_zero_page_x), diff --git a/src/main.rs b/src/main.rs index 844413f..60cdb78 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,8 +18,8 @@ use peripherals::mapper::Nrom128; mod utils; use canvas::{ - Application, - Canvas, + Application, + Canvas, sprite::{Sprite, TextureSprite, TextSprite, Center}, utils::{Size, Color, Position}, }; @@ -29,6 +29,7 @@ struct EmulatorState { pub screen: Rc>, pub screen_sprite: TextureSprite, + #[allow(dead_code)] pub pattern_table: Rc>, pub pattern_sprite: TextureSprite, @@ -66,13 +67,13 @@ impl Application for NesEmulator { pattern_sprite.set_position(Position {x: 100, y: 50}); let pattern_table = Rc::new(RefCell::new(DisplayBuffer::from_texture(pattern_texture))); - let mut fps_text = canvas.create_text_sprite("00", Size {w: 20, h: 20}, 20.0); + let mut fps_text = canvas.create_text_sprite("00", Size {w: 30, h: 20}, 20.0); fps_text.set_center(Center::TopLeft); - fps_text.set_position(Position {x:0, y:720}); + fps_text.set_position(Position {x:0, y:720}); let mut debug_text = canvas.create_text_sprite("00", Size {w: 300, h: 600}, 20.0); debug_text.set_center(Center::BotLeft); - debug_text.set_position(Position {x:700, y:50}); + debug_text.set_position(Position {x:700, y:50}); let mapper = Rc::new(RefCell::new(Nrom128::new(false))); let cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone()); @@ -124,9 +125,9 @@ impl Application for NesEmulator { fn main() -> Result<(), &'static str> { - setup_logger() - .map_err(|_| "Failed to setup logger")?; - canvas::run_canvas("NES emulator", Size {w: 1280, h: 720}, NesEmulator {}); + setup_logger() + .map_err(|_| "Failed to setup logger")?; + canvas::run_canvas("NES emulator", Size {w: 1280, h: 720}, NesEmulator {}); } // use utils::{Pixel, PixelBuffer, FontRenderer, DisplayBuffer}; @@ -239,22 +240,22 @@ fn main() -> Result<(), &'static str> { fn setup_logger() -> Result<(), fern::InitError> { - fern::Dispatch::new() - .format(|out, message, record| { - out.finish(format_args!( - "{}[{}][{}] {}", - chrono::Local::now().format("[%H:%M:%S]"), - record.target(), - //record.file(), - record.level(), - message - )) - }) - .level(log::LevelFilter::Error) - .chain(std::io::stdout()) - .chain(fern::log_file("output.log")?) - .apply()?; + fern::Dispatch::new() + .format(|out, message, record| { + out.finish(format_args!( + "{}[{}][{}] {}", + chrono::Local::now().format("[%H:%M:%S]"), + record.target(), + //record.file(), + record.level(), + message + )) + }) + .level(log::LevelFilter::Error) + .chain(std::io::stdout()) + .chain(fern::log_file("output.log")?) + .apply()?; - Ok(()) + Ok(()) } diff --git a/src/peripherals/mapper.rs b/src/peripherals/mapper.rs index c92200b..8f97cc5 100644 --- a/src/peripherals/mapper.rs +++ b/src/peripherals/mapper.rs @@ -9,7 +9,7 @@ pub use nrom::Nrom128; ///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; } diff --git a/src/peripherals/mapper/nrom.rs b/src/peripherals/mapper/nrom.rs index cd95025..7570457 100644 --- a/src/peripherals/mapper/nrom.rs +++ b/src/peripherals/mapper/nrom.rs @@ -20,32 +20,32 @@ impl Peripheral for Nrom128 { match addr { 0x6000..=0x7FFF => self.prg_ram.read_addr(addr - 0x6000), - 0x8000..=0xFFFF => self.prg_rom.read_addr((addr - 0x8000) % 0x4000), + 0x8000..=0xFFFF => self.prg_rom.read_addr((addr - 0x8000) % 0x4000), //mirrored every 16KiB _ => panic!("{}: Invalid address", addr), } } fn write_addr(&mut self, addr: u16, data: u8) { - + match addr { 0x6000..=0x7FFF => self.prg_ram.write_addr(addr - 0x6000, data), _ => (), //writes are ignored for rom or invald addresses } - } + } } impl Mapper for Nrom128 { fn ppu_read_addr(&self, addr: u16) -> u8 { - + match addr { 0x0000..=0x1FFF => self.chr_rom.read_addr(addr), 0x2000..=0x3EFF => { match self.vertical { false => match (addr - 0x2000) % 0x0FFF { 0x0000..=0x07FF => self.v_ram.read_addr(addr % 0x0400), - 0x0800..=0x0FFF => self.v_ram.read_addr((addr % 0x0400) + 0x0800), + 0x0800..=0x0FFF => self.v_ram.read_addr((addr % 0x0400) + 0x0800), _ => panic!("Unexpected behaviour"), }, true => self.v_ram.read_addr(addr % 0x0800), @@ -58,7 +58,7 @@ impl Mapper for Nrom128 { impl Nrom128 { pub fn new(vertical: bool) -> Self { - + Self { prg_rom: Ram::<0x4000>::new(), prg_ram: Ram::<0x2000>::new(), diff --git a/src/peripherals/ppu.rs b/src/peripherals/ppu.rs index 0e9e2a6..0d5e026 100644 --- a/src/peripherals/ppu.rs +++ b/src/peripherals/ppu.rs @@ -48,6 +48,7 @@ bitflags! { } } +#[allow(dead_code)] pub struct Ppu { vbus: Rc>, ppu_ctrl: PpuCtrl, @@ -76,7 +77,7 @@ impl Peripheral for Ppu { unimplemented!(); } - fn write_addr(&mut self, addr: u16, data: u8) { + fn write_addr(&mut self, _addr: u16, _data: u8) { unimplemented!(); } } diff --git a/src/peripherals/ram.rs b/src/peripherals/ram.rs index e56e975..091f622 100644 --- a/src/peripherals/ram.rs +++ b/src/peripherals/ram.rs @@ -8,7 +8,7 @@ pub struct Ram { } impl fmt::Debug for Ram { - + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for i in 0x100..=0x1FF { if i%0x10 == 0 { @@ -16,7 +16,7 @@ impl fmt::Debug for Ram { } f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))? } - + Ok(()) } } @@ -35,7 +35,7 @@ impl Peripheral for Ram { impl Ram { pub fn new() -> Self { - + Ram { buffer: [0u8; SIZE], } diff --git a/src/utils.rs b/src/utils.rs index add2cb6..78b34da 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,6 @@ #[allow(unused_imports)] use log::{debug, error, info, trace, warn}; -use rusttype::{point, Font, Scale, VMetrics}; - mod display_buffer; pub use display_buffer::DisplayBuffer; @@ -42,7 +40,7 @@ impl std::ops::Add for Pixel { } impl std::ops::AddAssign for Pixel { - + fn add_assign(&mut self, other: Self) { let alpha = other.a as f32 / 255.0; @@ -76,7 +74,7 @@ pub struct PixelBuffer { } impl PixelBuffer { - + pub fn new(w: usize, h: usize) -> Self { PixelBuffer { buffer: vec![Pixel::rgba(255u8, 255u8, 255u8, 255); h * w], @@ -124,76 +122,3 @@ impl From<&PixelBuffer> for Vec<[u8; 4]> { } } -//-------------------------------------------------------------------------------------------------- -/* FontRenderer struct */ - -pub struct FontRenderer { - font: Font<'static>, scale: Scale, v_metrics: VMetrics, color: [u8; 3], -} - -impl FontRenderer { - - pub fn new(size: f32, color: [u8; 3]) -> Self { - - // Load the font - let font = { - let font_data = include_bytes!("../fonts/DejaVuSansMono.ttf"); - // This only succeeds if collection consists of one font - Font::try_from_bytes(font_data as &[u8]).expect("Error constructing Font") - }; - - let scale = Scale::uniform(size); - let v_metrics = font.v_metrics(scale); - - FontRenderer { - font, - scale, - v_metrics, - color, - } - } - - pub fn draw(&mut self, buffer: &mut PixelBuffer, text: &str, origin: [usize; 2], - size: [usize; 2]) { - - let line_offset = (self.v_metrics.line_gap + self.v_metrics.ascent - - self.v_metrics.descent) as usize; - - // split text along '\n' - text.split('\n') - .enumerate() - .for_each(|(id, line)| { - - // layout the glyphs in a line with 20 pixels padding - let glyphs: Vec<_> = self.font - .layout(line, self.scale, point(origin[0] as f32, - origin[1] as f32 + self.v_metrics.ascent)) - .collect(); - - // Loop through the glyphs in the text, positing each one on a line - for glyph in glyphs { - if let Some(bounding_box) = glyph.pixel_bounding_box() { - // Draw the glyph into the image per-pixel by using the draw closure - glyph.draw(|x, y, v| { - let x_pos = (x + bounding_box.min.x as u32) as usize; - let y_pos = (y + bounding_box.min.y as u32) as usize + id * line_offset; - - if x_pos < origin[0] + size[0] && y_pos < origin[1] + size[1] { - buffer.put_pixel( - x_pos, - y_pos, - // Turn the coverage into an alpha value - Pixel::rgba( - self.color[0], - self.color[1], - self.color[2], - (v * 255.0) as u8), - ) - } - }); - } - } - }); - } -} - diff --git a/src/utils/display_buffer.rs b/src/utils/display_buffer.rs index f9045a8..f3ff6e0 100644 --- a/src/utils/display_buffer.rs +++ b/src/utils/display_buffer.rs @@ -4,20 +4,20 @@ use canvas::texture::TextureHandle; //-------------------------------------------------------------------------------------------------- pub struct DisplayBuffer { - pub is_ready: bool, + pub is_ready: bool, - texture: TextureHandle, + texture: TextureHandle, } impl DisplayBuffer { - pub fn from_texture(texture: TextureHandle) -> Self { + pub fn from_texture(texture: TextureHandle) -> Self { - Self { - texture, - is_ready: false, - } - } + Self { + texture, + is_ready: false, + } + } pub fn set_pixel(&mut self, x: usize, y: usize, pixel: Pixel) { self.texture.set_pixel(