refactor printing + args
This commit is contained in:
parent
744f769728
commit
13bd9f0a1c
3 changed files with 113 additions and 46 deletions
100
src/main.rs
100
src/main.rs
|
@ -2,16 +2,36 @@
|
||||||
|
|
||||||
mod processor;
|
mod processor;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::{ArgGroup, Parser};
|
||||||
use processor::CPU;
|
use processor::CPU;
|
||||||
use std::{
|
use std::{
|
||||||
fs,
|
fs,
|
||||||
io::{self, stdout, Write},
|
io::{self, stdout, Write},
|
||||||
|
sync::RwLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! verbose_println {
|
||||||
|
($($tts:tt)*) => {
|
||||||
|
if crate::is_verbose() {
|
||||||
|
println!($($tts)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! verbose_print {
|
||||||
|
($($tts:tt)*) => {
|
||||||
|
if crate::is_verbose() {
|
||||||
|
print!($($tts)*);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Simple program to greet a person
|
/// Simple program to greet a person
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(author, version, about, long_about = None)]
|
#[command(author, version, about, long_about = None)]
|
||||||
|
#[command(group(ArgGroup::new("prints").args(["verbose","cycle_count"])))]
|
||||||
struct Args {
|
struct Args {
|
||||||
/// ROM path
|
/// ROM path
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
@ -25,6 +45,14 @@ struct Args {
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
run_bootrom: bool,
|
run_bootrom: bool,
|
||||||
|
|
||||||
|
/// Verbose print
|
||||||
|
#[arg(short, long)]
|
||||||
|
verbose: bool,
|
||||||
|
|
||||||
|
/// Show cycle count
|
||||||
|
#[arg(short, long)]
|
||||||
|
cycle_count: bool,
|
||||||
|
|
||||||
/// Step emulation by...
|
/// Step emulation by...
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
step_by: Option<usize>,
|
step_by: Option<usize>,
|
||||||
|
@ -130,7 +158,8 @@ impl Memory {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(&mut self, address: Address, data: u8) {
|
fn set(&mut self, address: Address, data: u8) {
|
||||||
println!("write addr: {:#X}, data: {:#X}", address, data);
|
verbose_println!("write addr: {:#X}, data: {:#X}", address, data);
|
||||||
|
|
||||||
match address {
|
match address {
|
||||||
0x0..0x100 => {
|
0x0..0x100 => {
|
||||||
if !self.bootrom_enabled {
|
if !self.bootrom_enabled {
|
||||||
|
@ -162,7 +191,7 @@ impl Memory {
|
||||||
// println!("empty space write: {:#X} to addr {:#X}", data, address);
|
// println!("empty space write: {:#X} to addr {:#X}", data, address);
|
||||||
}
|
}
|
||||||
0xFF00..0xFF4C => {
|
0xFF00..0xFF4C => {
|
||||||
print!("writing to addr {:#X}\r", address);
|
verbose_print!("writing to addr {:#X}\r", address);
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
|
|
||||||
if address == 0xFF02 && data == 0x81 {
|
if address == 0xFF02 && data == 0x81 {
|
||||||
|
@ -178,8 +207,8 @@ impl Memory {
|
||||||
self.cpu_ram[(address - 0xFF80) as usize] = data;
|
self.cpu_ram[(address - 0xFF80) as usize] = data;
|
||||||
}
|
}
|
||||||
0xFFFF => {
|
0xFFFF => {
|
||||||
println!("interrupts set to {:#b}", data);
|
verbose_println!("interrupts set to {:#b}", data);
|
||||||
println!(" / {:#X}", data);
|
verbose_println!(" / {:#X}", data);
|
||||||
self.interrupts = data;
|
self.interrupts = data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,9 +276,15 @@ fn swap_rom_endian(rom: &ROM) -> ROM {
|
||||||
|
|
||||||
static mut PAUSE_ENABLED: bool = false;
|
static mut PAUSE_ENABLED: bool = false;
|
||||||
static mut PAUSE_QUEUED: bool = false;
|
static mut PAUSE_QUEUED: bool = false;
|
||||||
|
// static mut VERBOSE: bool = false;
|
||||||
|
static VERBOSE: RwLock<bool> = RwLock::new(false);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
|
{
|
||||||
|
let mut v = VERBOSE.write().unwrap();
|
||||||
|
*v = args.verbose;
|
||||||
|
}
|
||||||
|
|
||||||
let rom: ROM = fs::read(args.rom).expect("Could not load ROM");
|
let rom: ROM = fs::read(args.rom).expect("Could not load ROM");
|
||||||
let bootrom: ROM = fs::read(args.bootrom).expect("Could not load BootROM");
|
let bootrom: ROM = fs::read(args.bootrom).expect("Could not load BootROM");
|
||||||
|
@ -269,15 +304,19 @@ fn main() {
|
||||||
let mut cycle_num = 0;
|
let mut cycle_num = 0;
|
||||||
let mut instructions_seen = vec![];
|
let mut instructions_seen = vec![];
|
||||||
let mut last_state = cpu.state.clone();
|
let mut last_state = cpu.state.clone();
|
||||||
let mut next_state: State;
|
let mut next_state = last_state;
|
||||||
match args.step_by {
|
match args.step_by {
|
||||||
Some(step_size) => loop {
|
Some(step_size) => loop {
|
||||||
for _ in 0..step_size {
|
for _ in 0..step_size {
|
||||||
cycle_num += 1;
|
cycle_num += 1;
|
||||||
cpu.exec_next();
|
if args.cycle_count {
|
||||||
println!(
|
print_cycles(&cycle_num);
|
||||||
"exec {:#4X} from {:#4X}",
|
}
|
||||||
cpu.last_instruction, cpu.last_instruction_addr
|
run_cycle(
|
||||||
|
&mut cpu,
|
||||||
|
&mut next_state,
|
||||||
|
&mut last_state,
|
||||||
|
&mut instructions_seen,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
print!(
|
print!(
|
||||||
|
@ -285,24 +324,42 @@ fn main() {
|
||||||
cycle_num
|
cycle_num
|
||||||
);
|
);
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
pause();
|
pause_once();
|
||||||
},
|
},
|
||||||
None => loop {
|
None => loop {
|
||||||
|
cycle_num += 1;
|
||||||
|
if args.cycle_count {
|
||||||
|
print_cycles(&cycle_num);
|
||||||
|
}
|
||||||
|
run_cycle(
|
||||||
|
&mut cpu,
|
||||||
|
&mut next_state,
|
||||||
|
&mut last_state,
|
||||||
|
&mut instructions_seen,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_cycle(
|
||||||
|
cpu: &mut CPU,
|
||||||
|
next_state: &mut State,
|
||||||
|
last_state: &mut State,
|
||||||
|
instructions_seen: &mut Vec<u8>,
|
||||||
|
) {
|
||||||
let will_pause;
|
let will_pause;
|
||||||
unsafe {
|
unsafe {
|
||||||
will_pause = PAUSE_QUEUED.clone();
|
will_pause = PAUSE_QUEUED.clone();
|
||||||
}
|
}
|
||||||
cycle_num += 1;
|
|
||||||
// print_cycles(&cycle_num);
|
|
||||||
cpu.exec_next();
|
cpu.exec_next();
|
||||||
unsafe {
|
unsafe {
|
||||||
next_state = cpu.state;
|
*next_state = cpu.state;
|
||||||
if !PAUSE_ENABLED {
|
if !PAUSE_ENABLED {
|
||||||
if next_state.pc.as_u16 >= 0x100 {
|
if next_state.pc.as_u16 >= 0x100 {
|
||||||
PAUSE_ENABLED = true;
|
PAUSE_ENABLED = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_state = next_state;
|
*last_state = *next_state;
|
||||||
if will_pause {
|
if will_pause {
|
||||||
pause();
|
pause();
|
||||||
}
|
}
|
||||||
|
@ -314,8 +371,6 @@ fn main() {
|
||||||
instructions_seen.push(cpu.last_instruction);
|
instructions_seen.push(cpu.last_instruction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -328,6 +383,10 @@ fn pause() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn pause_once() {
|
||||||
|
io::stdin().read_line(&mut String::new()).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn print_cycles(cycles: &i32) {
|
fn print_cycles(cycles: &i32) {
|
||||||
|
@ -342,3 +401,10 @@ fn print_cycles(cycles: &i32) {
|
||||||
);
|
);
|
||||||
stdout().flush().unwrap();
|
stdout().flush().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_verbose() -> bool {
|
||||||
|
match VERBOSE.read() {
|
||||||
|
Ok(v) => *v,
|
||||||
|
Err(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{
|
||||||
ops::{BitAnd, BitOr, BitXor},
|
ops::{BitAnd, BitOr, BitXor},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Inner, Memory, Register, State};
|
use crate::{verbose_println, Inner, Memory, Register, State};
|
||||||
|
|
||||||
mod opcodes;
|
mod opcodes;
|
||||||
|
|
||||||
|
@ -33,9 +33,10 @@ impl CPU {
|
||||||
unsafe { self.last_instruction_addr = self.state.pc.as_u16 };
|
unsafe { self.last_instruction_addr = self.state.pc.as_u16 };
|
||||||
let opcode = self.next_opcode();
|
let opcode = self.next_opcode();
|
||||||
self.last_instruction = opcode;
|
self.last_instruction = opcode;
|
||||||
println!(
|
verbose_println!(
|
||||||
"exec {:#4X} from pc: {:#X}",
|
"exec {:#4X} from pc: {:#X}",
|
||||||
opcode, self.last_instruction_addr
|
opcode,
|
||||||
|
self.last_instruction_addr
|
||||||
);
|
);
|
||||||
self.run_opcode(opcode);
|
self.run_opcode(opcode);
|
||||||
}
|
}
|
||||||
|
@ -177,15 +178,15 @@ impl CPU {
|
||||||
|
|
||||||
fn set_flag(&mut self, flag: FLAGS) {
|
fn set_flag(&mut self, flag: FLAGS) {
|
||||||
if flag == FLAGS::Z {
|
if flag == FLAGS::Z {
|
||||||
println!("setting z flag");
|
verbose_println!("setting z flag");
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
println!(
|
verbose_println!(
|
||||||
"setting flag: currently {0:#b} / {0:#X}",
|
"setting flag: currently {0:#b} / {0:#X}",
|
||||||
self.state.af.as_u8s.right
|
self.state.af.as_u8s.right
|
||||||
);
|
);
|
||||||
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitor(1 << flag as u8);
|
self.state.af.as_u8s.right = self.state.af.as_u8s.right.bitor(1 << flag as u8);
|
||||||
println!(
|
verbose_println!(
|
||||||
" now {0:#b} / {0:#X}",
|
" now {0:#b} / {0:#X}",
|
||||||
self.state.af.as_u8s.right
|
self.state.af.as_u8s.right
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Inner, Register};
|
use crate::{verbose_println, Inner, Register};
|
||||||
use std::ops::{BitAnd, BitOr, BitXor};
|
use std::ops::{BitAnd, BitOr, BitXor};
|
||||||
|
|
||||||
use super::{as_signed, res, set, swap_nibbles, CPU, FLAGS};
|
use super::{as_signed, res, set, swap_nibbles, CPU, FLAGS};
|
||||||
|
@ -84,7 +84,7 @@ impl CPU {
|
||||||
0x20 => {
|
0x20 => {
|
||||||
let jump_size = self.ld_immediate_byte();
|
let jump_size = self.ld_immediate_byte();
|
||||||
if self.get_flag(FLAGS::Z) == 0 {
|
if self.get_flag(FLAGS::Z) == 0 {
|
||||||
println!("z flag is 0... so doing jump...");
|
verbose_println!("z flag is 0... so doing jump...");
|
||||||
unsafe {
|
unsafe {
|
||||||
self.state.pc.as_u16 = self
|
self.state.pc.as_u16 = self
|
||||||
.state
|
.state
|
||||||
|
@ -94,7 +94,7 @@ impl CPU {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
unsafe {
|
||||||
println!(
|
verbose_println!(
|
||||||
"not jumping! z flag is {0:#b}, flags are {1:#b} / {1:#X}",
|
"not jumping! z flag is {0:#b}, flags are {1:#b} / {1:#X}",
|
||||||
self.get_flag(FLAGS::Z),
|
self.get_flag(FLAGS::Z),
|
||||||
self.state.af.as_u8s.right
|
self.state.af.as_u8s.right
|
||||||
|
@ -117,7 +117,7 @@ impl CPU {
|
||||||
},
|
},
|
||||||
0x26 => self.state.hl.as_u8s.left = self.ld_immediate_byte(),
|
0x26 => self.state.hl.as_u8s.left = self.ld_immediate_byte(),
|
||||||
0x27 => unsafe {
|
0x27 => unsafe {
|
||||||
println!("Running DAA instruction (0x27) that I'm not too sure about...");
|
verbose_println!("Running DAA instruction (0x27) that I'm not too sure about...");
|
||||||
if self.get_flag(FLAGS::N) == 0 {
|
if self.get_flag(FLAGS::N) == 0 {
|
||||||
if self.get_flag(FLAGS::C) == 1 || self.state.af.as_u8s.left > 0x99 {
|
if self.get_flag(FLAGS::C) == 1 || self.state.af.as_u8s.left > 0x99 {
|
||||||
self.state.af.as_u8s.left += 0x60;
|
self.state.af.as_u8s.left += 0x60;
|
||||||
|
@ -133,7 +133,7 @@ impl CPU {
|
||||||
self.state.af.as_u8s.left -= 0x6;
|
self.state.af.as_u8s.left -= 0x6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!(
|
verbose_println!(
|
||||||
" ...this set register a to {:#X}...",
|
" ...this set register a to {:#X}...",
|
||||||
self.state.af.as_u8s.left
|
self.state.af.as_u8s.left
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Reference in a new issue