main.rs (1925B)
1 use std::{error::Error, path::PathBuf}; 2 3 use clap::{Parser, Subcommand}; 4 use perilus_core::perilus::Perilus; 5 6 #[derive(Parser)] 7 struct Cli { 8 #[command(subcommand)] 9 command: Command, 10 } 11 12 #[derive(Subcommand)] 13 enum Command { 14 /// Run a raw binary program to completion and report pass/fail 15 Test { file: PathBuf }, 16 } 17 18 const EBREAK_INSTRUCTION: u32 = 0x00100073; 19 const TEST_MAX_CYCLES: u32 = 1_000_000; 20 const TEST_PASS_VALUE: u32 = 0xebbb3689; 21 const TEST_FAIL_VALUE: u32 = 0xd02a545a; 22 23 fn main() -> Result<(), Box<dyn Error>> { 24 let cli = Cli::parse(); 25 let perilus = Perilus::init(); 26 27 match cli.command { 28 Command::Test { file } => { 29 perilus.load_file(file)?; 30 let mut cycles = 0; 31 loop { 32 perilus.pulse_clock(); 33 cycles += 1; 34 if cycles > TEST_MAX_CYCLES { 35 return Err("Test execution hit maximum cycle count limit".into()); 36 } 37 if perilus.get_control_unit_state() == 0 { 38 let pc = perilus.get_pc(); 39 let instr = perilus.get_memory().get((pc / 4) as usize); 40 if instr.is_none() { 41 return Err(format!( 42 "Program counter diverged to an address outside memory: 0x{pc:08x}" 43 ) 44 .into()); 45 } 46 if let Some(&EBREAK_INSTRUCTION) = instr { 47 let result = perilus.get_registers()[1]; 48 match result { 49 TEST_PASS_VALUE => return Ok(()), 50 TEST_FAIL_VALUE => return Err("Test failed".into()), 51 v => return Err(format!("Got unexpected test result 0x{v:08x}").into()), 52 } 53 } 54 } 55 } 56 } 57 } 58 }