From 0f737774138e0ed0e14cdc184561cdff08858182 Mon Sep 17 00:00:00 2001 From: Daniel Bauer Date: Tue, 24 Dec 2019 14:06:10 +0100 Subject: [PATCH] render memory --- Cargo.lock | 1 + Cargo.toml | 3 +- src/main.rs | 232 +++++++++++++++++++++++++++++++--------------- src/nes/disasm.rs | 15 ++- 4 files changed, 166 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f230eb6..11eeab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ name = "NESemu" version = "0.1.0" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "gfx_core 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "piston2d-opengl_graphics 0.70.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index b6ff4fa..38f394a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,5 @@ simple_logger = "1.3.*" phf = { version = "0.8", features = ['macros'] } failure = "0.1.*" piston_window = "0.105.*" -piston2d-opengl_graphics = "0.70.*" \ No newline at end of file +piston2d-opengl_graphics = "0.70.*" +gfx_core = "0.9.2" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0f3102d..cfec351 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ mod nes; use std::path::Path; use piston_window::*; +use gfx_core::Device; use nes::types::*; use nes::cpu::*; use nes::bus::*; @@ -16,11 +17,23 @@ use opengl_graphics::OpenGL; use log::Level; use piston_window::Text; +// font options +const FT_SIZE_PT: u32 = 6; +const FT_SIZE_PX: f64 = 8.0; +const FT_COLOR_WHITE: [f32; 4] = [1.0; 4]; +const FT_COLOR_RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; +const FT_COLOR_GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; +const FT_LINE_DISTANCE: f64 = FT_SIZE_PX * 0.5; + +// font for text drawing +fn get_glyphs(window: &mut PistonWindow) -> Glyphs { + let font_path = Path::new("resources/fonts/PressStart2P.ttf"); + window.load_font(font_path).unwrap() +} + fn main() { simple_logger::init_with_level(Level::Debug).unwrap(); - let mut window: PistonWindow = WindowSettings::new("NESemu", [256*6, 240*4]) - .exit_on_esc(true).graphics_api(OpenGL::V3_2).build().unwrap(); - + let mut bus = MemoryBus::new(); // Load little test program into ram @@ -32,129 +45,143 @@ fn main() { bus.writeb(addr, test_prog[i]) } - // hint program location to processor - bus.writew(0xfffc, offset); - // disassemble instructions let disasm = Disasm::disassemble(&test_prog, offset).unwrap(); + // hint program location to processor + bus.writew(0xfffc, offset); + // Create and reset CPU let mut cpu: CPU = CPU::new(); cpu.reset(&bus); - // Load font and start main loop - let font_path = Path::new("resources/fonts/PressStart2P.ttf"); - let mut glyphs = window.load_font(font_path).unwrap(); - while let Some(event) = window.next() { + // Prepare window and drawing resources + let mut window: PistonWindow = WindowSettings::new("NESemu", [256*3, 240*2]) + .exit_on_esc(true).graphics_api(OpenGL::V3_2).build().unwrap(); + let mut event_settings = EventSettings::new(); + event_settings.max_fps = 60; + let mut events = Events::new(event_settings); + let mut glyphs = get_glyphs(&mut window); + + // Main loop + while let Some(event) = events.next(&mut window) { + if let Some(_) = event.render_args() { + render(&mut window, &event, &mut glyphs, &cpu, &bus, &disasm); + } if let Some(Button::Keyboard(key)) = event.press_args() { - if key == Key::C { // advance one clock - cpu.clock(&mut bus); - } else if key == Key::Space { // advance to next instruction - cpu.clock(&mut bus); - while cpu.is_ahead() { + match key { + Key::C => cpu.clock(&mut bus), // advance one clock + Key::Space => { // advance to next instruction cpu.clock(&mut bus); + while cpu.is_ahead() { + cpu.clock(&mut bus); + } } + _ => { } } - } - render(&mut window, &event, &mut glyphs, &cpu, &bus, &disasm); + } } } fn render(window: &mut PistonWindow, event: &Event, glyphs: &mut Glyphs, cpu: &CPU, bus: &dyn Bus, disasm: &Disasm) { window.draw_2d(event, |c, g, d| { clear([0.0, 0.0, 1.0, 1.0], g); - render_cpu(&c, g, glyphs, cpu, disasm); - render_pc(&c, g, glyphs, cpu, bus); + + let debug_offset = [10.0, 10.0]; + render_cpu(&c, g, glyphs, cpu, debug_offset); + render_disasm(&c, g, glyphs, disasm, cpu.regs.pc, + [debug_offset[0], debug_offset[1] + (7.0 * (FT_LINE_DISTANCE+FT_SIZE_PX))]); + render_memory(&c, g, glyphs, bus, + [debug_offset[0] + 300.0, debug_offset[1]]); + glyphs.factory.encoder.flush(d); }); } -fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, disasm: &Disasm) { - let font_size_pt = 36; - let color_white = [1.0; 4]; - let color_red = [1.0, 0.0, 0.0, 1.0]; - let color_green = [0.0, 1.0, 0.0, 1.0]; - - let font_scale = 0.25; - let font_size_px = 12; - - let line_distance = font_size_px as f64 * 0.5; - let x_dist = font_size_px as f64; - - let flags_y = line_distance + font_size_px as f64; - let mut flags_x_offset = x_dist; - let mut transform = c.transform.trans(x_dist, flags_y).scale(font_scale, font_scale); - Text::new_color(color_white, font_size_pt).draw( +fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, offset: [f64; 2]) { + let mut transform = c.transform + .trans(offset[0], offset[1] + FT_SIZE_PX); + let mut color = FT_COLOR_WHITE; + Text::new_color(color, FT_SIZE_PT).draw( &"Flags:", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(300.0, 0.0); - Text::new_color(if cpu.get_flag(NEGATIVE) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + + transform = transform.trans(70.0, 0.0); + color = if cpu.get_flag(NEGATIVE) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color , FT_SIZE_PT).draw( &"N", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(OVERFLOW) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(OVERFLOW) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"V", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(color_white, font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = FT_COLOR_WHITE; + Text::new_color(color, FT_SIZE_PT).draw( &"-", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(BREAK) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(BREAK) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"B", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(DECIMAL) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(DECIMAL) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"D", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(IRQ) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(IRQ) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"I", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(ZERO) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(ZERO) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"Z", glyphs, &c.draw_state, transform, g - ); - transform = transform.trans(72.0, 0.0); - Text::new_color(if cpu.get_flag(CARRY) == 1 { color_green} else { color_red } , font_size_pt).draw( + ).unwrap(); + transform = transform.trans(16.0, 0.0); + color = if cpu.get_flag(CARRY) == 1 { FT_COLOR_GREEN} else { FT_COLOR_RED }; + Text::new_color(color, FT_SIZE_PT).draw( &"C", glyphs, &c.draw_state, transform, g - ); + ).unwrap(); let cpu_register_texts = [ &format!("A: {:#x} ({})", cpu.regs.a, cpu.regs.a), @@ -165,32 +192,85 @@ fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, disasm: ]; for (i, &text) in cpu_register_texts.iter().enumerate() { - let y_dist: f64 = (i+2) as f64*(line_distance + font_size_px as f64); - let transform = c.transform.trans(x_dist, y_dist).scale(font_scale, font_scale); - Text::new_color(color_white, font_size_pt).draw( + let y_offset = (i+2) as f64 * (FT_LINE_DISTANCE + FT_SIZE_PX); + let transform = c.transform.trans(offset[0], offset[1] + y_offset); + Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( &text, glyphs, &c.draw_state, transform, g - ); + ).unwrap(); } +} - for (i, text) in disasm.instructions.iter().enumerate() { - let y_dist: f64 = (i+8) as f64*(line_distance + font_size_px as f64); - let transform = c.transform.trans(x_dist, y_dist).scale(font_scale, font_scale); - Text::new_color(color_white, font_size_pt).draw( - &text, - glyphs, - &c.draw_state, - transform, - g - ); - } +fn render_disasm(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, disasm: &Disasm, pc: Addr, offset: [f64; 2]) { + let mut transform = c.transform.trans(offset[0], offset[1]); + for (text, addr) in disasm.instructions.iter().zip(disasm.addresses.iter()) { + transform = transform.trans(0.0, FT_LINE_DISTANCE + FT_SIZE_PX); + let color = if *addr == pc { + FT_COLOR_RED + } else { + FT_COLOR_WHITE + }; + Text::new_color(color, FT_SIZE_PT).draw( + &text, + glyphs, + &c.draw_state, + transform, + g + ).unwrap(); + } } -fn render_pc(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, bus: &dyn Bus) { +fn render_memory(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, bus: &dyn Bus, offset: [f64; 2]) { + let mut transform_y = c.transform.trans(offset[0], offset[1]); + for page in (0x0000..0x00F0).step_by(16) { + transform_y = transform_y.trans(0.0, FT_LINE_DISTANCE+FT_SIZE_PX); + Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( + &format!("{:#06x}:", page), + glyphs, + &c.draw_state, + transform_y, + g + ).unwrap(); + let mut transform_x = transform_y.trans(40.0, 0.0); + for offset in 0u16..16u16 { + transform_x = transform_x.trans(20.0, 0.0); + let addr = page + offset; + Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( + &format!("{:02x}", bus.readb(addr)), + glyphs, + &c.draw_state, + transform_x, + g + ).unwrap(); + } + } + transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX) * 1.5); + for page in (0x8000..0x80F0).step_by(16) { + transform_y = transform_y.trans(0.0, (FT_LINE_DISTANCE+FT_SIZE_PX)); + Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( + &format!("{:#06x}:", page), + glyphs, + &c.draw_state, + transform_y, + g + ).unwrap(); + let mut transform_x = transform_y.trans(40.0, 0.0); + for offset in 0u16..16u16 { + transform_x = transform_x.trans(20.0, 0.0); + let addr = page + offset; + Text::new_color(FT_COLOR_WHITE, FT_SIZE_PT).draw( + &format!("{:02x}", bus.readb(addr)), + glyphs, + &c.draw_state, + transform_x, + g + ).unwrap(); + } + } } \ No newline at end of file diff --git a/src/nes/disasm.rs b/src/nes/disasm.rs index 991c55c..a2b3777 100644 --- a/src/nes/disasm.rs +++ b/src/nes/disasm.rs @@ -2,31 +2,29 @@ use failure::Error; use crate::nes::bus::*; use crate::nes::types::*; use crate::nes::cpu::instructions::*; +use std::collections::HashMap; // Disassemble code around the pc of the cpu pub struct Disasm { pub offset: Addr, pub instructions: Vec, + pub addresses: Vec } impl BusDevice for Disasm {} -impl Clockable for Disasm { - fn clock(&mut self, bus: &mut T) { - // TODO find new pc location - } -} impl Disasm { // Disassemble given code region pub fn disassemble(mem: &[Byte], offset: Addr) -> Result { let mut instructions = Vec::new(); + let mut addresses = Vec::new(); let mut mem_iter = mem.iter().enumerate(); while let Some(b) = mem_iter.next() { let addr = offset + (b.0 as Addr); let i = Instruction::decode_op(*b.1)?; let args = match i.addr_mode { - AddrMode::IMM => format!("#{0:#04x} ({0})", mem_iter.next().unwrap().1), + AddrMode::IMM => format!("#{0:02x} ({0})", mem_iter.next().unwrap().1), // AddrMode::ZP0 => self.am_ZP0(bus), // AddrMode::ZPX => self.am_ZPX(bus), // AddrMode::ZPY => self.am_ZPY(bus), @@ -40,7 +38,7 @@ impl Disasm { AddrMode::REL => { let rel_addr = (*mem_iter.next().unwrap().1) as Addr; let jmp_addr = Disasm::get_rel_addr(rel_addr, addr+2); - format!("{:#04x} => {:#06x}", rel_addr, jmp_addr) + format!("#{:02x} => {:#06x}", rel_addr, jmp_addr) }, // AddrMode::ABX => self.am_ABX(bus), @@ -54,8 +52,9 @@ impl Disasm { let s = format!("{:#06x}: {} {} ({})", addr, i.operation, args, i.addr_mode); instructions.push(s); + addresses.push(addr); } - Ok(Disasm { offset, instructions }) + Ok(Disasm { offset, instructions, addresses }) } fn get_rel_addr(rel_addr: Addr, curr_addr: Addr) -> Addr {