Fix warnings and formating

This commit is contained in:
Steins7 2024-03-10 15:07:09 +01:00
parent 27585d6440
commit 3c05bfdcaa
9 changed files with 159 additions and 231 deletions

View File

@ -1,164 +1,165 @@
use std::{ use std::{
fmt, fmt,
rc::Rc, rc::Rc,
cell::RefCell, cell::RefCell,
}; };
use crate::{ use crate::{
utils::DisplayBuffer, utils::DisplayBuffer,
peripherals::{Peripheral, Ram, Mapper, Ppu}, peripherals::{Peripheral, Ram, Mapper, Ppu},
}; };
pub struct Bus<M: Mapper> { pub struct Bus<M: Mapper> {
ram: Ram<0x800>, ram: Ram<0x800>,
ppu: Ppu<M>, ppu: Ppu<M>,
apu: Ram<0x1F>,//TODO apu: Ram<0x1F>,//TODO
cartridge: Rc<RefCell<M>>, cartridge: Rc<RefCell<M>>,
} }
impl<M: Mapper> fmt::Debug for Bus<M> { impl<M: Mapper> fmt::Debug for Bus<M> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Bus") f.debug_struct("Bus")
.field("ram", &self.ram) .field("ram", &self.ram)
.finish_non_exhaustive() .finish_non_exhaustive()
} }
} }
impl<M: Mapper> Peripheral for Bus<M> { impl<M: Mapper> Peripheral for Bus<M> {
fn read_addr(&self, addr: u16) -> u8 { fn read_addr(&self, addr: u16) -> u8 {
match addr { match addr {
0x0000..=0x1FFF => self.ram.read_addr(addr % 0x0800), //RAM is mirrored 3 times 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 0x2000..=0x3FFF => self.ppu.read_addr(addr % 0x8), //PPU is mirrored every 8 bytes
0x4000..=0x401F => self.apu.read_addr(addr), 0x4000..=0x401F => self.apu.read_addr(addr),
0x4020..=0xFFFF => self.cartridge.borrow().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 { match addr {
0x0000..=0x1FFF => self.ram.write_addr(addr % 0x0800, data), 0x0000..=0x1FFF => self.ram.write_addr(addr % 0x0800, data),
0x2000..=0x3FFF => self.ppu.write_addr(addr % 0x8, data), 0x2000..=0x3FFF => self.ppu.write_addr(addr % 0x8, data),
0x4000..=0x401F => self.apu.write_addr(addr, data), 0x4000..=0x401F => self.apu.write_addr(addr, data),
0x4020..=0xFFFF => self.cartridge.borrow_mut().write_addr(addr, data), 0x4020..=0xFFFF => self.cartridge.borrow_mut().write_addr(addr, data),
}; };
} }
} }
impl<M: Mapper> Bus<M> { impl<M: Mapper> Bus<M> {
pub fn new(mapper: Rc<RefCell<M>>, pub fn new(mapper: Rc<RefCell<M>>,
screen: Rc<RefCell<DisplayBuffer>>, screen: Rc<RefCell<DisplayBuffer>>,
pattern_table: Rc<RefCell<DisplayBuffer>>) pattern_table: Rc<RefCell<DisplayBuffer>>)
-> Self { -> Self {
let mut ram = Ram::<0x800>::new(); let mut ram = Ram::<0x800>::new();
//TODO temporary for instruction tests //TODO temporary for instruction tests
ram.buffer[0x01] = 0xE9; //sbc ram.buffer[0x01] = 0xE9; //sbc
ram.buffer[0x02] = (-3 as i8) as u8; ram.buffer[0x02] = (-3 as i8) as u8;
ram.buffer[0x03] = 0x09; ram.buffer[0x03] = 0x09;
ram.buffer[0x04] = 0x00; ram.buffer[0x04] = 0x00;
ram.buffer[0x05] = 0xA9; //lda ram.buffer[0x05] = 0xA9; //lda
ram.buffer[0x06] = 0x01; ram.buffer[0x06] = 0x01;
ram.buffer[0x07] = 0x4C; //jmp ram.buffer[0x07] = 0x4C; //jmp
ram.buffer[0x08] = 0x00; ram.buffer[0x08] = 0x00;
ram.buffer[0x09] = 0x00; ram.buffer[0x09] = 0x00;
ram.buffer[0x0A] = 0x2A; //fn rol ram.buffer[0x0A] = 0x2A; //fn rol
ram.buffer[0x0B] = 0x90; //bcc ram.buffer[0x0B] = 0x90; //bcc
ram.buffer[0x0C] = (-3 as i8) as u8; ram.buffer[0x0C] = (-3 as i8) as u8;
ram.buffer[0x0D] = 0x60; //rts ram.buffer[0x0D] = 0x60; //rts
ram.buffer[0x0E] = 0xFD; ram.buffer[0x0E] = 0xFD;
ram.buffer[0x0F] = 0x01; ram.buffer[0x0F] = 0x01;
ram.buffer[0x10] = 0x21; ram.buffer[0x10] = 0x21;
ram.buffer[0x11] = 0x9F; ram.buffer[0x11] = 0x9F;
ram.buffer[0x12] = 0x31; ram.buffer[0x12] = 0x31;
ram.buffer[0x13] = 0xB0; ram.buffer[0x13] = 0xB0;
// boundary // boundary
ram.buffer[0x14] = 0x3D; ram.buffer[0x14] = 0x3D;
ram.buffer[0x15] = 0xFF; ram.buffer[0x15] = 0xFF;
ram.buffer[0x16] = 0x02; ram.buffer[0x16] = 0x02;
ram.buffer[0x17] = 0x39; ram.buffer[0x17] = 0x39;
ram.buffer[0x18] = 0xFE; ram.buffer[0x18] = 0xFE;
ram.buffer[0x19] = 0x02; ram.buffer[0x19] = 0x02;
ram.buffer[0x1A] = 0x31; ram.buffer[0x1A] = 0x31;
ram.buffer[0x1B] = 0xB2; ram.buffer[0x1B] = 0xB2;
// ptr to val // ptr to val
ram.buffer[0xA0] = 0xFF; ram.buffer[0xA0] = 0xFF;
ram.buffer[0xA1] = 0x01; ram.buffer[0xA1] = 0x01;
// ptr to val as table // ptr to val as table
ram.buffer[0xB0] = 0xFD; ram.buffer[0xB0] = 0xFD;
ram.buffer[0xB1] = 0x01; ram.buffer[0xB1] = 0x01;
ram.buffer[0xB2] = 0xFE; //boundary ram.buffer[0xB2] = 0xFE; //boundary
ram.buffer[0xB3] = 0x02; ram.buffer[0xB3] = 0x02;
// zero page val // zero page val
ram.buffer[0xFF] = 0x01; ram.buffer[0xFF] = 0x01;
// val // val
ram.buffer[0x01FF] = 0x01; ram.buffer[0x01FF] = 0x01;
ram.buffer[0x02FF] = 0xFF; //boundary ram.buffer[0x02FF] = 0xFF; //boundary
ram.buffer[0x0300] = 0x03; ram.buffer[0x0300] = 0x03;
// ptr to test // ptr to test
ram.buffer[0x030F] = 0xFF; ram.buffer[0x030F] = 0xFF;
ram.buffer[0x0310] = 0x03; ram.buffer[0x0310] = 0x03;
// jmp test // jmp test
ram.buffer[0x0400] = 0xE6; ram.buffer[0x0400] = 0xE6;
Bus { Bus {
ram, ram,
ppu: Ppu::new(mapper.clone(), screen, pattern_table), ppu: Ppu::new(mapper.clone(), screen, pattern_table),
apu: Ram::<0x1F>::new(), apu: Ram::<0x1F>::new(),
cartridge: mapper, cartridge: mapper,
} }
} }
pub fn tick(&mut self) { pub fn tick(&mut self) {
self.ppu.tick(); self.ppu.tick();
} }
} }
/// special Bus only used for testing the emulator /// special Bus only used for testing the emulator
pub struct FileBus { pub struct FileBus {
mem: Ram<0x10000>, mem: Ram<0x10000>,
} }
impl fmt::Debug for FileBus { impl fmt::Debug for FileBus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Bus") f.debug_struct("Bus")
.field("mem", &self.mem) .field("mem", &self.mem)
.finish() .finish()
} }
} }
impl Peripheral for FileBus { impl Peripheral for FileBus {
fn read_addr(&self, addr: u16) -> u8 { fn read_addr(&self, addr: u16) -> u8 {
self.mem.read_addr(addr) //RAM is mirrored 3 times self.mem.read_addr(addr) //RAM is mirrored 3 times
} }
fn write_addr(&mut self, addr: u16, data: u8) { fn write_addr(&mut self, addr: u16, data: u8) {
self.mem.write_addr(addr % 0x0800, data) self.mem.write_addr(addr % 0x0800, data)
} }
} }
impl FileBus { impl FileBus {
pub fn new() -> Self { #[allow(dead_code)]
FileBus { pub fn new() -> Self {
mem: Ram::from_file("6502_functional_test.bin"), FileBus {
} mem: Ram::from_file("6502_functional_test.bin"),
} }
}
} }

View File

@ -208,7 +208,7 @@ impl<M: Mapper> Cpu<M> {
// println!("0x{:0>4X}: {:0>2X}", self.pc-1, opcode); // 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), 0x69 => adc(mode_immediate),
0x65 => adc(mode_zero_page), 0x65 => adc(mode_zero_page),
0x75 => adc(mode_zero_page_x), 0x75 => adc(mode_zero_page_x),

View File

@ -18,8 +18,8 @@ use peripherals::mapper::Nrom128;
mod utils; mod utils;
use canvas::{ use canvas::{
Application, Application,
Canvas, Canvas,
sprite::{Sprite, TextureSprite, TextSprite, Center}, sprite::{Sprite, TextureSprite, TextSprite, Center},
utils::{Size, Color, Position}, utils::{Size, Color, Position},
}; };
@ -29,6 +29,7 @@ struct EmulatorState {
pub screen: Rc<RefCell<DisplayBuffer>>, pub screen: Rc<RefCell<DisplayBuffer>>,
pub screen_sprite: TextureSprite, pub screen_sprite: TextureSprite,
#[allow(dead_code)]
pub pattern_table: Rc<RefCell<DisplayBuffer>>, pub pattern_table: Rc<RefCell<DisplayBuffer>>,
pub pattern_sprite: TextureSprite, pub pattern_sprite: TextureSprite,
@ -66,13 +67,13 @@ impl Application<EmulatorState> for NesEmulator {
pattern_sprite.set_position(Position {x: 100, y: 50}); pattern_sprite.set_position(Position {x: 100, y: 50});
let pattern_table = Rc::new(RefCell::new(DisplayBuffer::from_texture(pattern_texture))); 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_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); 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_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 mapper = Rc::new(RefCell::new(Nrom128::new(false)));
let cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone()); let cpu = Cpu::new(mapper, screen.clone(), pattern_table.clone());
@ -124,9 +125,9 @@ impl Application<EmulatorState> for NesEmulator {
fn main() -> Result<(), &'static str> { fn main() -> Result<(), &'static str> {
setup_logger() setup_logger()
.map_err(|_| "Failed to setup logger")?; .map_err(|_| "Failed to setup logger")?;
canvas::run_canvas("NES emulator", Size {w: 1280, h: 720}, NesEmulator {}); canvas::run_canvas("NES emulator", Size {w: 1280, h: 720}, NesEmulator {});
} }
// use utils::{Pixel, PixelBuffer, FontRenderer, DisplayBuffer}; // use utils::{Pixel, PixelBuffer, FontRenderer, DisplayBuffer};
@ -239,22 +240,22 @@ fn main() -> Result<(), &'static str> {
fn setup_logger() -> Result<(), fern::InitError> { fn setup_logger() -> Result<(), fern::InitError> {
fern::Dispatch::new() fern::Dispatch::new()
.format(|out, message, record| { .format(|out, message, record| {
out.finish(format_args!( out.finish(format_args!(
"{}[{}][{}] {}", "{}[{}][{}] {}",
chrono::Local::now().format("[%H:%M:%S]"), chrono::Local::now().format("[%H:%M:%S]"),
record.target(), record.target(),
//record.file(), //record.file(),
record.level(), record.level(),
message message
)) ))
}) })
.level(log::LevelFilter::Error) .level(log::LevelFilter::Error)
.chain(std::io::stdout()) .chain(std::io::stdout())
.chain(fern::log_file("output.log")?) .chain(fern::log_file("output.log")?)
.apply()?; .apply()?;
Ok(()) Ok(())
} }

View File

@ -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 ///A Mapper is a special `Peripheral` that can also be read by the `Ppu`. The exact memory layout
///is defined by the implementation ///is defined by the implementation
pub trait Mapper: Peripheral { pub trait Mapper: Peripheral {
///read the specified 16 bits address using the ppu bus ///read the specified 16 bits address using the ppu bus
fn ppu_read_addr(&self, addr: u16) -> u8; fn ppu_read_addr(&self, addr: u16) -> u8;
} }

View File

@ -20,32 +20,32 @@ impl Peripheral for Nrom128 {
match addr { match addr {
0x6000..=0x7FFF => self.prg_ram.read_addr(addr - 0x6000), 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 //mirrored every 16KiB
_ => panic!("{}: Invalid address", addr), _ => panic!("{}: Invalid address", addr),
} }
} }
fn write_addr(&mut self, addr: u16, data: u8) { fn write_addr(&mut self, addr: u16, data: u8) {
match addr { match addr {
0x6000..=0x7FFF => self.prg_ram.write_addr(addr - 0x6000, data), 0x6000..=0x7FFF => self.prg_ram.write_addr(addr - 0x6000, data),
_ => (), //writes are ignored for rom or invald addresses _ => (), //writes are ignored for rom or invald addresses
} }
} }
} }
impl Mapper for Nrom128 { impl Mapper for Nrom128 {
fn ppu_read_addr(&self, addr: u16) -> u8 { fn ppu_read_addr(&self, addr: u16) -> u8 {
match addr { match addr {
0x0000..=0x1FFF => self.chr_rom.read_addr(addr), 0x0000..=0x1FFF => self.chr_rom.read_addr(addr),
0x2000..=0x3EFF => { 0x2000..=0x3EFF => {
match self.vertical { match self.vertical {
false => match (addr - 0x2000) % 0x0FFF { false => match (addr - 0x2000) % 0x0FFF {
0x0000..=0x07FF => self.v_ram.read_addr(addr % 0x0400), 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"), _ => panic!("Unexpected behaviour"),
}, },
true => self.v_ram.read_addr(addr % 0x0800), true => self.v_ram.read_addr(addr % 0x0800),
@ -58,7 +58,7 @@ impl Mapper for Nrom128 {
impl Nrom128 { impl Nrom128 {
pub fn new(vertical: bool) -> Self { pub fn new(vertical: bool) -> Self {
Self { Self {
prg_rom: Ram::<0x4000>::new(), prg_rom: Ram::<0x4000>::new(),
prg_ram: Ram::<0x2000>::new(), prg_ram: Ram::<0x2000>::new(),

View File

@ -48,6 +48,7 @@ bitflags! {
} }
} }
#[allow(dead_code)]
pub struct Ppu<M: Mapper> { pub struct Ppu<M: Mapper> {
vbus: Rc<RefCell<M>>, vbus: Rc<RefCell<M>>,
ppu_ctrl: PpuCtrl, ppu_ctrl: PpuCtrl,
@ -76,7 +77,7 @@ impl<M: Mapper> Peripheral for Ppu<M> {
unimplemented!(); unimplemented!();
} }
fn write_addr(&mut self, addr: u16, data: u8) { fn write_addr(&mut self, _addr: u16, _data: u8) {
unimplemented!(); unimplemented!();
} }
} }

View File

@ -8,7 +8,7 @@ pub struct Ram<const SIZE: usize> {
} }
impl<const SIZE: usize> fmt::Debug for Ram<SIZE> { impl<const SIZE: usize> fmt::Debug for Ram<SIZE> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for i in 0x100..=0x1FF { for i in 0x100..=0x1FF {
if i%0x10 == 0 { if i%0x10 == 0 {
@ -16,7 +16,7 @@ impl<const SIZE: usize> fmt::Debug for Ram<SIZE> {
} }
f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))? f.write_fmt(format_args!(" {:0>2X}", self.buffer[i]))?
} }
Ok(()) Ok(())
} }
} }
@ -35,7 +35,7 @@ impl<const SIZE: usize> Peripheral for Ram<SIZE> {
impl<const SIZE: usize> Ram<SIZE> { impl<const SIZE: usize> Ram<SIZE> {
pub fn new() -> Self { pub fn new() -> Self {
Ram { Ram {
buffer: [0u8; SIZE], buffer: [0u8; SIZE],
} }

View File

@ -1,8 +1,6 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use log::{debug, error, info, trace, warn}; use log::{debug, error, info, trace, warn};
use rusttype::{point, Font, Scale, VMetrics};
mod display_buffer; mod display_buffer;
pub use display_buffer::DisplayBuffer; pub use display_buffer::DisplayBuffer;
@ -42,7 +40,7 @@ impl std::ops::Add for Pixel {
} }
impl std::ops::AddAssign for Pixel { impl std::ops::AddAssign for Pixel {
fn add_assign(&mut self, other: Self) { fn add_assign(&mut self, other: Self) {
let alpha = other.a as f32 / 255.0; let alpha = other.a as f32 / 255.0;
@ -76,7 +74,7 @@ pub struct PixelBuffer {
} }
impl PixelBuffer { impl PixelBuffer {
pub fn new(w: usize, h: usize) -> Self { pub fn new(w: usize, h: usize) -> Self {
PixelBuffer { PixelBuffer {
buffer: vec![Pixel::rgba(255u8, 255u8, 255u8, 255); h * w], 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),
)
}
});
}
}
});
}
}

View File

@ -4,20 +4,20 @@ use canvas::texture::TextureHandle;
//-------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------------
pub struct DisplayBuffer { pub struct DisplayBuffer {
pub is_ready: bool, pub is_ready: bool,
texture: TextureHandle, texture: TextureHandle,
} }
impl DisplayBuffer { impl DisplayBuffer {
pub fn from_texture(texture: TextureHandle) -> Self { pub fn from_texture(texture: TextureHandle) -> Self {
Self { Self {
texture, texture,
is_ready: false, is_ready: false,
} }
} }
pub fn set_pixel(&mut self, x: usize, y: usize, pixel: Pixel) { pub fn set_pixel(&mut self, x: usize, y: usize, pixel: Pixel) {
self.texture.set_pixel( self.texture.set_pixel(