render memory

This commit is contained in:
Daniel Bauer
2019-12-24 14:06:10 +01:00
parent f2f4d49cc7
commit 0f73777413
4 changed files with 166 additions and 85 deletions

1
Cargo.lock generated
View File

@@ -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)",

View File

@@ -14,3 +14,4 @@ phf = { version = "0.8", features = ['macros'] }
failure = "0.1.*"
piston_window = "0.105.*"
piston2d-opengl_graphics = "0.70.*"
gfx_core = "0.9.2"

View File

@@ -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,10 +17,22 @@ 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();
@@ -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
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(
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();
}
}
}

View File

@@ -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<String>,
pub addresses: Vec<Addr>
}
impl BusDevice for Disasm {}
impl Clockable for Disasm {
fn clock<T: Bus>(&mut self, bus: &mut T) {
// TODO find new pc location
}
}
impl Disasm {
// Disassemble given code region
pub fn disassemble(mem: &[Byte], offset: Addr) -> Result<Self, Error> {
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 {