use std::collections::HashMap; use std::fmt; use std::fs; use text_io::read; struct UMState { pc: usize, // program counter regs: [u32; 8], // register contents arrmap: HashMap, // active arrays mem: Vec> // memory contents (array of arrays) } enum UMOp { ConditionalMove(u8, u8, u8), ArrayIndex(u8, u8, u8), ArrayAmend(u8, u8, u8), Add(u8, u8, u8), Mult(u8, u8, u8), Div(u8, u8, u8), NotAnd(u8, u8, u8), Halt, Allocate(u8, u8), Abandon(u8), Output(u8), Input(u8), Load(u8, u8), Value(u8, u32), } fn reg(i:u8) -> &'static str { match i { 0 => "A", 1 => "B", 2 => "C", 3 => "D", 4 => "E", 5 => "F", 6 => "G", 7 => "H", _ => panic!("Bad register! {}",i) } } impl fmt::Display for UMOp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let repr = match self { UMOp::ConditionalMove(a, b, c) => format!("Conditional #{} <- {} ? #{} : #{}", reg(*a), reg(*c), reg(*b), reg(*a)), UMOp::ArrayIndex(a, b, c) => format!("ArrIndex #{} <- #{}[#{}]", reg(*a), reg(*b), reg(*c)), UMOp::ArrayAmend(a, b, c) => format!("ArrAmend #{}[#{}] <- #{}", reg(*a), reg(*b), reg(*c)), UMOp::Add(a, b, c) => format!("Add #{} <- #{} + #{}", reg(*a), reg(*b), reg(*c)), UMOp::Mult(a, b, c) => format!("Mult #{} <- #{} * #{}", reg(*a), reg(*b), reg(*c)), UMOp::Div(a, b, c) => format!("Div #{} <- #{} / #{}", reg(*a), reg(*b), reg(*c)), UMOp::NotAnd(a, b, c) => format!("NotAnd #{} <- #{} !&& #{}", reg(*a), reg(*b), reg(*c)), UMOp::Halt => format!("Halt!"), UMOp::Allocate(b, c) => format!("Alloc #{} <- [#{}]", reg(*b), reg(*c)), UMOp::Abandon(c) => format!("Abandon @#{}", reg(*c)), UMOp::Output(c) => format!("Output #{}", reg(*c)), UMOp::Input(c) => format!("Input #{} <-", reg(*c)), UMOp::Load(b, c) => format!("Load <- #{}[#{}]", reg(*b), reg(*c)), UMOp::Value(a, val) => format!("Value <- #{} <- $#{}", reg(*a), val), }; write!(f, "{}", repr) } } fn num_extract(masks_map: &HashMap<&str, (u32,u32)>, num: u32, mask_name: &str) -> u32 { let masktup = masks_map.get(mask_name).unwrap(); (num & masktup.0) >> masktup.1 } fn parse_instr(masks_map: &HashMap<&str, (u32,u32)>, instr: u32) -> UMOp { let opcode = num_extract(masks_map, instr, "op_mask"); let rega = num_extract(masks_map, instr, "rega_mask") as u8; let regb = num_extract(masks_map, instr, "regb_mask") as u8; let regc = num_extract(masks_map, instr, "regc_mask") as u8; let alta = num_extract(masks_map, instr, "alta_mask") as u8; let val = num_extract(masks_map, instr, "val_mask"); match opcode { 0 => UMOp::ConditionalMove(rega, regb, regc), 1 => UMOp::ArrayIndex(rega, regb, regc), 2 => UMOp::ArrayAmend(rega, regb, regc), 3 => UMOp::Add(rega, regb, regc), 4 => UMOp::Mult(rega, regb, regc), 5 => UMOp::Div(rega, regb, regc), 6 => UMOp::NotAnd(rega, regb, regc), 7 => UMOp::Halt, 8 => UMOp::Allocate(regb, regc), 9 => UMOp::Abandon(regc), 10 => UMOp::Output(regc), 11 => UMOp::Input(regc), 12 => UMOp::Load(regb, regc), 13 => UMOp::Value(alta, val), _ => panic!("Bad Instruction! ({})", instr) } } fn um_step(um: &mut UMState, op: UMOp) { match op { UMOp::ConditionalMove(a, b, c) => { if um.regs[c as usize] != 0 { um.regs[a as usize] = um.regs[b as usize] } }, UMOp::ArrayIndex(a, b, c) => { um.regs[a as usize] = um.mem[um.regs[b as usize] as usize][um.regs[c as usize] as usize] }, UMOp::ArrayAmend(a, b, c) => { um.mem[um.regs[a as usize] as usize][um.regs[b as usize] as usize] = um.regs[c as usize] }, UMOp::Add(a, b, c) => { um.regs[a as usize] = um.regs[b as usize].wrapping_add(um.regs[c as usize]) }, UMOp::Mult(a, b, c) => { um.regs[a as usize] = um.regs[b as usize].wrapping_mul(um.regs[c as usize]) }, UMOp::Div(a, b, c) => { um.regs[a as usize] = um.regs[b as usize] / um.regs[c as usize] }, UMOp::NotAnd(a, b, c) => { um.regs[a as usize] = ! (um.regs[b as usize] & um.regs[c as usize]) }, UMOp::Halt => { println!("\n\n end of program"); panic!("Halt reached") }, UMOp::Allocate(b, c) => { let new_arr = vec![0u32; um.regs[c as usize] as usize]; let new_arr_add = um.mem.len() as u32; um.mem.push(new_arr); um.arrmap.insert(new_arr_add, new_arr_add as usize); um.regs[b as usize] = new_arr_add; }, UMOp::Abandon(c) => { let i = um.arrmap[&um.regs[c as usize]]; um.arrmap.remove(&um.regs[c as usize]); um.mem[i] = vec![0u32; 0]; }, UMOp::Output(c) => { print!("{}", um.regs[c as usize] as u8 as char) }, UMOp::Input(c) => { let input: String = read!(); um.regs[c as usize] = input.chars().nth(0).unwrap() as u32 as u8 as u32; if um.regs[c as usize] == 4 { um.regs[c as usize] = 255 } }, UMOp::Load(b, c) => { let new_arr = um.mem[um.arrmap[&um.regs[b as usize]]].clone(); let new_arr_add = um.mem.len() as u32; um.mem.push(new_arr); um.arrmap.remove(&0); um.arrmap.insert(0,new_arr_add as usize); um.pc = um.regs[c as usize] as usize; }, UMOp::Value(a, val) => { um.regs[a as usize] = val } } } fn um_run(masks: HashMap<&str, (u32,u32)>, um: &mut UMState) { loop { let instr = um.mem[0][um.pc]; let full_op = parse_instr(&masks, instr); //println!("{}", full_op); um.pc = um.pc+1; um_step(um, full_op); } } fn main() { let mut masks_map: HashMap<&str, (u32,u32)> = HashMap::new(); masks_map.insert("op_mask", (0b11110000000000000000000000000000, 28)); masks_map.insert("rega_mask", (0b00000000000000000000000111000000, 6)); masks_map.insert("regb_mask", (0b00000000000000000000000000111000, 3)); masks_map.insert("regc_mask", (0b00000000000000000000000000000111, 0)); masks_map.insert("alta_mask", (0b00001110000000000000000000000000, 25)); masks_map.insert("val_mask", (0b00000001111111111111111111111111, 0)); let codex8 = &fs::read("data/sandmark.umz").unwrap(); let mut codex = vec![0u32; codex8.len() / 4]; for i in 0..codex.len() { codex[i] = u32::from_be_bytes([ codex8[i*4], codex8[i*4+1], codex8[i*4+2], codex8[i*4+3] ]); } let mut arrmap: HashMap = HashMap::new(); arrmap.insert(0,0); let mut um = UMState { pc: 0, arrmap: arrmap, regs: [0,0,0,0,0,0,0,0], mem: vec![codex] }; um_run(masks_map, &mut um); }