refactor printing + args

This commit is contained in:
Alex Janka 2023-01-22 12:13:02 +11:00
parent 744f769728
commit 13bd9f0a1c
3 changed files with 113 additions and 46 deletions

View file

@ -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,
}
}

View file

@ -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
); );

View file

@ -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
); );