diff options
Diffstat (limited to 'crates/runrom')
| -rw-r--r-- | crates/runrom/README.md | 32 | ||||
| -rw-r--r-- | crates/runrom/src/main.rs | 65 |
2 files changed, 82 insertions, 15 deletions
diff --git a/crates/runrom/README.md b/crates/runrom/README.md index 5e232db..9bd5070 100644 --- a/crates/runrom/README.md +++ b/crates/runrom/README.md @@ -36,14 +36,30 @@ You can run a ROM file by simply: $ runrom <your-game-path>/game.nes ``` -This will display all of the instructions being run. By default it will run from -the reset vector. You can change that with the `-s/--start` option, which -accepts a 16-bit address from where to start execution. - -That being said, most of the times you want to test a specific function. For -that, you can toggle 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 can be halted. +This will display all of the instructions being run. + +### From where should the VM start? + +By default `runrom` will start from the advertised reset vector. You can change +that with the `-s/--start` option, which accepts a 16-bit address from where to +start execution. The address can be given in hexadecimal format, but you can +also provide a full address name with the `-n/--nasm` option. With this option +you provide the location to the hidden `.nasm/` directory for the project (see +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 +``` + +### When should the VM end? + +A lot of times you want to test a specific function. For that, you can toggle +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 Moreover, you may also find interesting the `-d/--dump-memory` option, which will display a summary of memory addresses which have been updated along diff --git a/crates/runrom/src/main.rs b/crates/runrom/src/main.rs index 1535c94..1b82822 100644 --- a/crates/runrom/src/main.rs +++ b/crates/runrom/src/main.rs @@ -1,6 +1,8 @@ use header::Header; +use std::collections::HashMap; use std::fs::File; -use std::io::{ErrorKind, Read, Seek, SeekFrom}; +use std::io::{BufRead, BufReader, ErrorKind, Read, Seek, SeekFrom}; +use std::path::PathBuf; use vnf::{Machine, MemoryInitialValue, MemoryPolicy}; /// Version for this program. @@ -11,6 +13,7 @@ struct Args { file: String, start: Option<u16>, assume_function: bool, + nasm: Option<String>, dump_memory: bool, } @@ -21,6 +24,7 @@ fn print_help() { println!(" -d, --dump-memory\tShow the memory that has changed after a run."); println!(" -f, --function\tRun the code by assuming it's a function."); println!(" -h, --help\t\tPrint this message and quit."); + println!(" -n, --nasm-directory <PATH>\tPath to the .nasm/ directory."); println!(" -s, --start\t\tAddress from where to start (default: reset vector)."); println!(" -v, --version\t\tPrint version information."); std::process::exit(0); @@ -64,9 +68,34 @@ fn parse_hex_argument(given: &str) -> Result<u16, String> { } } +// Fetch the address mapping from the .nasm/addresses.txt file. You need to pass +// the full 'path' to the .nasm/ directory for the project (i.e. the '-n/--nasm' +// option). +fn fetch_addresses(path: PathBuf) -> Result<HashMap<String, usize>, String> { + let mut addresses: HashMap<String, usize> = HashMap::default(); + + if let Ok(file) = File::open(path.join("addresses.txt")) { + let reader = BufReader::new(file); + for line in reader.lines() { + let line = line.map_err(|e| e.to_string())?; + let columns: Vec<&str> = line.split(',').map(|s| s.trim()).collect(); + if columns.len() != 3 { + return Err("badly formatted address file".to_string()); + } + + let parsed_start = usize::from_str_radix(columns[1], 16) + .map_err(|_| format!("invalid hex value: '{}'", columns[1]))?; + addresses.insert(columns[0].to_string(), parsed_start); + } + } + + Ok(addresses) +} + fn parse_arguments() -> Args { let mut args = std::env::args(); let mut res = Args::default(); + let mut start = None; // Skip command name. args.next(); @@ -78,13 +107,9 @@ fn parse_arguments() -> Args { if res.start.is_some() { die("do not specify the '-s/--start' flag twice".to_string()); } - let Some(val) = args.next() else { + start = args.next(); + if start.is_none() { die("you need to specify a value for the -s/--start flag!".to_string()); - return res; - }; - match parse_hex_argument(&val) { - Ok(n) => res.start = Some(n), - Err(e) => die(e), } } "-d" | "--dump-memory" => { @@ -93,6 +118,10 @@ fn parse_arguments() -> Args { "-f" | "--function" => { res.assume_function = true; } + "-n" | "--nasm" => match args.next() { + Some(a) => res.nasm = Some(a), + None => die("you need to specify a file for the '-n/--nasm' flag".to_string()), + }, "-v" | "--version" => { println!("runrom {VERSION}"); std::process::exit(0); @@ -109,6 +138,28 @@ 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. + 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), + }, + } + } + if res.file.is_empty() { die("you need to specify the file to be run".to_string()); } |
