123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- 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<u32, usize>, // active arrays
- mem: Vec<Vec<u32>> // 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<u32,usize> = 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);
- }
|