diff options
| -rw-r--r-- | crates/runrom/README.md | 18 | ||||
| -rw-r--r-- | crates/runrom/src/main.rs | 93 | ||||
| -rw-r--r-- | lib/vnf/src/lib.rs | 16 |
3 files changed, 80 insertions, 47 deletions
diff --git a/crates/runrom/README.md b/crates/runrom/README.md index 9bd5070..86ac11f 100644 --- a/crates/runrom/README.md +++ b/crates/runrom/README.md @@ -36,7 +36,9 @@ You can run a ROM file by simply: $ runrom <your-game-path>/game.nes ``` -This will display all of the instructions being run. +This will display all of the instructions being run. Moreover, you can also pass +the `-d/--dump-memory` option, which will display a summary of memory addresses +which have been updated along execution, and some statistics about them. ### From where should the VM start? @@ -49,7 +51,7 @@ more details on [nasm's README file](../nasm/README.md)), which is then used to translate the given identifier with the actual address. So: ``` -$ runrom --start my-function --nasm <path-to-nasm-directory> game.nes +$ runrom --start my-function --nasm <path to .nasm/> game.nes ``` ### When should the VM end? @@ -59,8 +61,12 @@ the `-f/--function` option, which tells `runrom` that the address is just a function and, whenever a top-level `rts`/`rti` instruction is found, then execution should be halted. -### Other features +Otherwise, you can also pass the `--until-address` option. This option follows +the same format as `-s/--start` and it accepts an address (again, either in +hexadecimal form or with an identifier). With this, `runrom` will run until the +given address is met. This way, you can expect something like this to work just +fine: -Moreover, you may also find interesting the `-d/--dump-memory` option, which -will display a summary of memory addresses which have been updated along -execution, and some statistics about them. +``` +$ runrom --start init-loop --until-address end-loop --nasm <path to .nasm/> game.nes +``` diff --git a/crates/runrom/src/main.rs b/crates/runrom/src/main.rs index 1b82822..e7682e0 100644 --- a/crates/runrom/src/main.rs +++ b/crates/runrom/src/main.rs @@ -15,6 +15,7 @@ struct Args { assume_function: bool, nasm: Option<String>, dump_memory: bool, + until_address: u16, } fn print_help() { @@ -92,10 +93,41 @@ fn fetch_addresses(path: PathBuf) -> Result<HashMap<String, usize>, String> { Ok(addresses) } +// Parse the given 'val' as if it was an hexadecimal literal. If that fails, +// pick up whether a 'nasm' directory was provided (i.e. '-n/--nasm' option), +// and try to find a mapping on the 'addresses' map. If that map is empty, then +// it will be filled by parsing the "addresses.txt" file from the 'nasm' +// directory. +fn parse_hex_or_reference( + val: String, + nasm: &Option<String>, + addresses: &mut HashMap<String, usize>, +) -> u16 { + match parse_hex_argument(&val) { + Ok(n) => return n, + Err(e) => match nasm { + Some(nasm_path) => { + if addresses.is_empty() { + *addresses = match fetch_addresses(PathBuf::from(nasm_path)) { + Ok(addr) => addr, + Err(err) => die(err), + }; + } + match addresses.get(&val) { + Some(v) => return *v as u16, + None => die(format!("could not find '{val}'")), + } + } + None => die(e), + }, + } +} + fn parse_arguments() -> Args { let mut args = std::env::args(); let mut res = Args::default(); let mut start = None; + let mut until_address = None; // Skip command name. args.next(); @@ -122,6 +154,12 @@ fn parse_arguments() -> Args { Some(a) => res.nasm = Some(a), None => die("you need to specify a file for the '-n/--nasm' flag".to_string()), }, + "--until-address" => { + until_address = args.next(); + if until_address.is_none() { + die("you need to specify a value for the --until-address flag!".to_string()); + } + } "-v" | "--version" => { println!("runrom {VERSION}"); std::process::exit(0); @@ -138,27 +176,20 @@ fn parse_arguments() -> Args { } } - // If the '-s/--start' option was provided, we need to parse it. This is - // either a valid hexadecimal value, or a string representing an address - // from the .nasm/ directory. + // Further handle options which can be either an hexadecimal value or an + // address reference. + + let mut addresses = HashMap::new(); + if let Some(val) = start { - match parse_hex_argument(&val) { - Ok(n) => res.start = Some(n), - Err(e) => match res.nasm { - Some(ref nasm_path) => { - let addresses = match fetch_addresses(PathBuf::from(nasm_path)) { - Ok(addr) => addr, - Err(err) => die(err), - }; - match addresses.get(&val) { - Some(v) => res.start = Some(*v as u16), - None => die(format!("could not find '{val}'")), - } - } - None => die(e), - }, - } + res.start = Some(parse_hex_or_reference(val, &res.nasm, &mut addresses)); } + res.until_address = match until_address { + Some(val) => parse_hex_or_reference(val, &res.nasm, &mut addresses), + None => 0xFFFF, + }; + + // And finally, check that a ROM file was actually provided. if res.file.is_empty() { die("you need to specify the file to be run".to_string()); @@ -214,7 +245,13 @@ fn start_from_reset_vector(file: &String) -> u16 { ((buf[1] as u16) << 8) + buf[0] as u16 } -fn run(file: &String, start: u16, assume_function: bool, dump_memory: bool) -> Result<(), String> { +fn run( + file: &String, + start: u16, + end: u16, + assume_function: bool, + dump_memory: bool, +) -> Result<(), String> { let mut machine = Machine::from( file, start, @@ -226,13 +263,11 @@ fn run(file: &String, start: u16, assume_function: bool, dump_memory: bool) -> R minimum_stack_value: 0, }, )?; + machine.verbose = true; + machine.run_function_mode = assume_function; - if assume_function { - machine.run_function()?; - } else { - machine.until_address(0xFFFF)?; - } + machine.until_address(end)?; if dump_memory { let mut title = false; @@ -262,7 +297,13 @@ fn main() { None => start_from_reset_vector(&args.file), }; - match run(&args.file, start, args.assume_function, args.dump_memory) { + match run( + &args.file, + start, + args.until_address, + args.assume_function, + args.dump_memory, + ) { Ok(m) => m, Err(e) => { die(e); diff --git a/lib/vnf/src/lib.rs b/lib/vnf/src/lib.rs index d118157..349548a 100644 --- a/lib/vnf/src/lib.rs +++ b/lib/vnf/src/lib.rs @@ -183,7 +183,7 @@ pub struct Machine { /// Whether the machine is supposed to be running just a function (while /// also going into inner calls). Hence, it will stop whenever an 'rts' or /// 'rti' instruction is found at the top level. - run_function_mode: bool, + pub run_function_mode: bool, /// The PRG ROM pool of bytes. pub prg_rom: Vec<u8>, @@ -554,20 +554,6 @@ impl Machine { Ok(()) } - /// Run a top-level function. That is, assume that the current 'start' - /// address is the start of a function, and keep on iterating the machine - /// until an 'rts'/'rti' instruction is found at the top-level (we still - /// allow inner calls). - pub fn run_function(&mut self) -> Result<(), String> { - self.run_function_mode = true; - - while self.active { - self.next_iteration()?; - } - - Ok(()) - } - /// Run until the program counter reaches the given 'address'. pub fn until_address(&mut self, address: u16) -> Result<(), String> { while self.pc != address as usize { |
