gui to step through cpu instructions
This commit is contained in:
1210
Cargo.lock
generated
1210
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,9 @@ edition = "2018"
|
||||
test = []
|
||||
|
||||
[dependencies]
|
||||
log = "*"
|
||||
simple_logger = "*"
|
||||
log = "0.4.*"
|
||||
simple_logger = "1.3.*"
|
||||
phf = { version = "0.8", features = ['macros'] }
|
||||
failure = "*"
|
||||
failure = "0.1.*"
|
||||
piston_window = "0.105.*"
|
||||
piston2d-opengl_graphics = "0.70.*"
|
||||
94
resources/fonts/LICENSE.txt
Normal file
94
resources/fonts/LICENSE.txt
Normal file
@@ -0,0 +1,94 @@
|
||||
Copyright (c) 2011, Cody "CodeMan38" Boisclair (cody@zone38.net),
|
||||
with Reserved Font Name "Press Start".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
BIN
resources/fonts/PressStart2P.ttf
Normal file
BIN
resources/fonts/PressStart2P.ttf
Normal file
Binary file not shown.
37
src/cpu.rs
37
src/cpu.rs
@@ -7,12 +7,12 @@ use crate::types::*;
|
||||
use log::{debug};
|
||||
|
||||
pub struct Registers {
|
||||
a: Byte,
|
||||
x: Byte,
|
||||
y: Byte,
|
||||
sp: Byte,
|
||||
pc: Addr,
|
||||
flags: Byte
|
||||
pub a: Byte,
|
||||
pub x: Byte,
|
||||
pub y: Byte,
|
||||
pub sp: Byte,
|
||||
pub pc: Addr,
|
||||
pub flags: Byte
|
||||
}
|
||||
|
||||
impl Registers {
|
||||
@@ -37,17 +37,17 @@ impl Debug for Registers {
|
||||
}
|
||||
|
||||
|
||||
const CARRY: Byte = 1 << 0;
|
||||
const ZERO: Byte = 1 << 1;
|
||||
const IRQ: Byte = 1 << 2;
|
||||
const DECIMAL: Byte = 1 << 3;
|
||||
const BREAK: Byte = 1 << 4;
|
||||
const UNUSED: Byte = 1 << 5;
|
||||
const OVERFLOW: Byte = 1 << 6;
|
||||
const NEGATIVE: Byte = 1 << 7;
|
||||
pub const CARRY: Byte = 1 << 0;
|
||||
pub const ZERO: Byte = 1 << 1;
|
||||
pub const IRQ: Byte = 1 << 2;
|
||||
pub const DECIMAL: Byte = 1 << 3;
|
||||
pub const BREAK: Byte = 1 << 4;
|
||||
pub const UNUSED: Byte = 1 << 5;
|
||||
pub const OVERFLOW: Byte = 1 << 6;
|
||||
pub const NEGATIVE: Byte = 1 << 7;
|
||||
|
||||
pub struct CPU {
|
||||
regs: Registers,
|
||||
pub regs: Registers,
|
||||
curr_op: Byte, // current operation
|
||||
cycles: u8, // number of clock clycles the CPU is ahead of global clock
|
||||
}
|
||||
@@ -86,6 +86,11 @@ impl CPU {
|
||||
self.curr_op = 0x00;
|
||||
}
|
||||
|
||||
// True if the operation is not finished yet
|
||||
pub fn is_ahead(&self) -> bool {
|
||||
return self.cycles > 0;
|
||||
}
|
||||
|
||||
fn readb<T: Bus>(&self, bus: &T, addr: Addr) -> Byte {
|
||||
bus.readb(addr)
|
||||
}
|
||||
@@ -122,7 +127,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_flag(&mut self, flag: Byte) -> Byte {
|
||||
pub fn get_flag(&self, flag: Byte) -> Byte {
|
||||
if self.regs.flags & flag > 0 {
|
||||
1
|
||||
} else {
|
||||
|
||||
156
src/main.rs
156
src/main.rs
@@ -2,18 +2,27 @@
|
||||
#[macro_use] extern crate failure;
|
||||
extern crate simple_logger;
|
||||
extern crate phf;
|
||||
extern crate piston_window;
|
||||
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
mod cpu;
|
||||
mod bus;
|
||||
mod types;
|
||||
|
||||
use std::path::Path;
|
||||
use piston_window::*;
|
||||
use types::*;
|
||||
use cpu::CPU;
|
||||
use cpu::*;
|
||||
use bus::{MemoryBus, Bus};
|
||||
use opengl_graphics::OpenGL;
|
||||
use log::Level;
|
||||
use piston_window::Text;
|
||||
|
||||
fn main() {
|
||||
simple_logger::init().unwrap();
|
||||
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();
|
||||
|
||||
@@ -30,12 +39,145 @@ fn main() {
|
||||
bus.writeb(0xfffc, offset as Byte);
|
||||
bus.writeb(0xfffc + 1, (offset >> 8) as Byte);
|
||||
|
||||
// Create and reset CPU
|
||||
let mut cpu: CPU = CPU::new();
|
||||
cpu.reset(&bus);
|
||||
for _ in 0..500+10 {
|
||||
cpu.clock(&mut bus);
|
||||
debug!("Mem: {} {} {}", bus.readb(0x00), bus.readb(0x01), bus.readb(0x02))
|
||||
|
||||
// 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() {
|
||||
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() {
|
||||
cpu.clock(&mut bus);
|
||||
}
|
||||
}
|
||||
}
|
||||
render(&mut window, &event, &mut glyphs, &cpu, &bus);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
fn render(window: &mut PistonWindow, event: &Event, glyphs: &mut Glyphs, cpu: &CPU, bus: &dyn Bus) {
|
||||
window.draw_2d(event, |c, g, d| {
|
||||
clear([0.0, 0.0, 1.0, 1.0], g);
|
||||
render_cpu(&c, g, glyphs, cpu);
|
||||
render_pc(&c, g, glyphs, cpu, bus);
|
||||
glyphs.factory.encoder.flush(d);
|
||||
});
|
||||
}
|
||||
|
||||
fn render_cpu(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU) {
|
||||
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(
|
||||
&"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(
|
||||
&"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(
|
||||
&"V",
|
||||
glyphs,
|
||||
&c.draw_state,
|
||||
transform,
|
||||
g
|
||||
);
|
||||
transform = transform.trans(72.0, 0.0);
|
||||
Text::new_color(color_white, font_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(
|
||||
&"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(
|
||||
&"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(
|
||||
&"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(
|
||||
&"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(
|
||||
&"C",
|
||||
glyphs,
|
||||
&c.draw_state,
|
||||
transform,
|
||||
g
|
||||
);
|
||||
|
||||
let cpu_register_texts = [
|
||||
&format!("A: {:#x} ({})", cpu.regs.a, cpu.regs.a),
|
||||
&format!("X: {:#x} ({})", cpu.regs.x, cpu.regs.y),
|
||||
&format!("Y: {:#x} ({})", cpu.regs.y, cpu.regs.x),
|
||||
&format!("Stack P: {:#x} ({})", cpu.regs.sp, cpu.regs.sp),
|
||||
&format!("Program P: {:#x}", cpu.regs.pc),
|
||||
];
|
||||
|
||||
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(
|
||||
&text,
|
||||
glyphs,
|
||||
&c.draw_state,
|
||||
transform,
|
||||
g
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn render_pc(c: &Context, g: &mut G2d, glyphs: &mut Glyphs, cpu: &CPU, bus: &dyn Bus) {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user