diff --git a/src/main.rs b/src/main.rs index a93c888..43a7b86 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,16 +2,36 @@ mod processor; -use clap::Parser; +use clap::{ArgGroup, Parser}; use processor::CPU; use std::{ fs, 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 #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] +#[command(group(ArgGroup::new("prints").args(["verbose","cycle_count"])))] struct Args { /// ROM path #[arg(short, long)] @@ -25,6 +45,14 @@ struct Args { #[arg(long)] run_bootrom: bool, + /// Verbose print + #[arg(short, long)] + verbose: bool, + + /// Show cycle count + #[arg(short, long)] + cycle_count: bool, + /// Step emulation by... #[arg(long)] step_by: Option, @@ -130,7 +158,8 @@ impl Memory { } 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 { 0x0..0x100 => { if !self.bootrom_enabled { @@ -162,7 +191,7 @@ impl Memory { // println!("empty space write: {:#X} to addr {:#X}", data, address); } 0xFF00..0xFF4C => { - print!("writing to addr {:#X}\r", address); + verbose_print!("writing to addr {:#X}\r", address); stdout().flush().unwrap(); if address == 0xFF02 && data == 0x81 { @@ -178,8 +207,8 @@ impl Memory { self.cpu_ram[(address - 0xFF80) as usize] = data; } 0xFFFF => { - println!("interrupts set to {:#b}", data); - println!(" / {:#X}", data); + verbose_println!("interrupts set to {:#b}", data); + verbose_println!(" / {:#X}", data); self.interrupts = data; } } @@ -247,9 +276,15 @@ fn swap_rom_endian(rom: &ROM) -> ROM { static mut PAUSE_ENABLED: bool = false; static mut PAUSE_QUEUED: bool = false; +// static mut VERBOSE: bool = false; +static VERBOSE: RwLock = RwLock::new(false); fn main() { 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 bootrom: ROM = fs::read(args.bootrom).expect("Could not load BootROM"); @@ -269,15 +304,19 @@ fn main() { let mut cycle_num = 0; let mut instructions_seen = vec![]; let mut last_state = cpu.state.clone(); - let mut next_state: State; + let mut next_state = last_state; match args.step_by { Some(step_size) => loop { for _ in 0..step_size { cycle_num += 1; - cpu.exec_next(); - println!( - "exec {:#4X} from {:#4X}", - cpu.last_instruction, cpu.last_instruction_addr + if args.cycle_count { + print_cycles(&cycle_num); + } + run_cycle( + &mut cpu, + &mut next_state, + &mut last_state, + &mut instructions_seen, ); } print!( @@ -285,39 +324,55 @@ fn main() { cycle_num ); stdout().flush().unwrap(); - pause(); + pause_once(); }, None => loop { - let will_pause; - unsafe { - will_pause = PAUSE_QUEUED.clone(); - } cycle_num += 1; - // print_cycles(&cycle_num); - cpu.exec_next(); - unsafe { - next_state = cpu.state; - if !PAUSE_ENABLED { - if next_state.pc.as_u16 >= 0x100 { - PAUSE_ENABLED = true; - } - } - last_state = next_state; - if will_pause { - pause(); - } - } - match instructions_seen.contains(&cpu.last_instruction) { - true => {} - false => { - // println!("new instruction enountered: {:#X}", cpu.last_instruction); - instructions_seen.push(cpu.last_instruction); - } + 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, +) { + let will_pause; + unsafe { + will_pause = PAUSE_QUEUED.clone(); + } + cpu.exec_next(); + unsafe { + *next_state = cpu.state; + if !PAUSE_ENABLED { + if next_state.pc.as_u16 >= 0x100 { + PAUSE_ENABLED = true; + } + } + *last_state = *next_state; + if will_pause { + pause(); + } + } + match instructions_seen.contains(&cpu.last_instruction) { + true => {} + false => { + // println!("new instruction enountered: {:#X}", cpu.last_instruction); + instructions_seen.push(cpu.last_instruction); + } + } +} + #[allow(dead_code)] fn pause() { unsafe { @@ -328,6 +383,10 @@ fn pause() { } } } +#[allow(dead_code)] +fn pause_once() { + io::stdin().read_line(&mut String::new()).unwrap(); +} #[allow(dead_code)] fn print_cycles(cycles: &i32) { @@ -342,3 +401,10 @@ fn print_cycles(cycles: &i32) { ); stdout().flush().unwrap(); } + +fn is_verbose() -> bool { + match VERBOSE.read() { + Ok(v) => *v, + Err(_) => false, + } +} diff --git a/src/processor/mod.rs b/src/processor/mod.rs index 1a1d8b4..01204b2 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -3,7 +3,7 @@ use std::{ ops::{BitAnd, BitOr, BitXor}, }; -use crate::{Inner, Memory, Register, State}; +use crate::{verbose_println, Inner, Memory, Register, State}; mod opcodes; @@ -33,9 +33,10 @@ impl CPU { unsafe { self.last_instruction_addr = self.state.pc.as_u16 }; let opcode = self.next_opcode(); self.last_instruction = opcode; - println!( + verbose_println!( "exec {:#4X} from pc: {:#X}", - opcode, self.last_instruction_addr + opcode, + self.last_instruction_addr ); self.run_opcode(opcode); } @@ -177,15 +178,15 @@ impl CPU { fn set_flag(&mut self, flag: FLAGS) { if flag == FLAGS::Z { - println!("setting z flag"); + verbose_println!("setting z flag"); } unsafe { - println!( + verbose_println!( "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.bitor(1 << flag as u8); - println!( + verbose_println!( " now {0:#b} / {0:#X}", self.state.af.as_u8s.right ); diff --git a/src/processor/opcodes.rs b/src/processor/opcodes.rs index 1e0f0f6..cd92410 100644 --- a/src/processor/opcodes.rs +++ b/src/processor/opcodes.rs @@ -1,4 +1,4 @@ -use crate::{Inner, Register}; +use crate::{verbose_println, Inner, Register}; use std::ops::{BitAnd, BitOr, BitXor}; use super::{as_signed, res, set, swap_nibbles, CPU, FLAGS}; @@ -84,7 +84,7 @@ impl CPU { 0x20 => { let jump_size = self.ld_immediate_byte(); 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 { self.state.pc.as_u16 = self .state @@ -94,7 +94,7 @@ impl CPU { } } else { unsafe { - println!( + verbose_println!( "not jumping! z flag is {0:#b}, flags are {1:#b} / {1:#X}", self.get_flag(FLAGS::Z), self.state.af.as_u8s.right @@ -117,7 +117,7 @@ impl CPU { }, 0x26 => self.state.hl.as_u8s.left = self.ld_immediate_byte(), 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::C) == 1 || self.state.af.as_u8s.left > 0x99 { self.state.af.as_u8s.left += 0x60; @@ -133,7 +133,7 @@ impl CPU { self.state.af.as_u8s.left -= 0x6; } } - println!( + verbose_println!( " ...this set register a to {:#X}...", self.state.af.as_u8s.left );