1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
use enum_primitive::FromPrimitive; use types::*; error_chain! { errors { BasicOp(val: u16) { description("invalid basic opcode") display("invalid basic opcode: {:#x}", val) } SpecialOp(val: u16) { description("invalid special opcode") display("invalid special opcode: {:#x}", val) } } } impl Instruction<u16> { pub fn decode(data: &[u16; 3]) -> Result<(u16, Instruction<u16>)> { let op_bin = data[0] & MASK_OP; let a_bin = data[0] >> SHIFT_A; let b_bin = (data[0] >> SHIFT_B) & MASK_B; if op_bin == 0 { let op = try!(SpecialOp::decode(b_bin)); let (used, a) = Value::decode(a_bin, data[1], true); Ok((1 + used, Instruction::SpecialOp(op, a))) } else { let op = try!(BasicOp::decode(op_bin)); let (used_a, a) = Value::decode(a_bin, data[1], true); let (used_b, b) = Value::decode(b_bin, data[(1 + used_a) as usize], false); Ok((1 + used_a + used_b, Instruction::BasicOp(op, b, a))) } } } impl Value<u16> { pub fn decode(val: u16, next: u16, is_a: bool) -> (u16, Value<u16>) { match val { x if x <= 0x17 => { let reg = Register::from_u16(x % 0x8).expect("Invalid reg id"); if x <= 0x07 { (0, Value::Reg(reg)) } else if x <= 0x0f { (0, Value::AtReg(reg)) } else { (1, Value::AtRegPlus(reg, next)) } }, 0x18 => (0, Value::Push), 0x19 => (0, Value::Peek), 0x1a => (1, Value::Pick(next)), 0x1b => (0, Value::SP), 0x1c => (0, Value::PC), 0x1d => (0, Value::EX), 0x1e => (1, Value::AtAddr(next)), 0x1f => (1, Value::Litteral(next)), x if is_a && x >= 0x20 && x <= 0x3f => (0, Value::Litteral(x.wrapping_sub(0x21))), _ => unreachable!() } } } impl BasicOp { pub fn decode(op: u16) -> Result<BasicOp> { match BasicOp::from_u16(op) { Some(o) => Ok(o), None => try!(Err(ErrorKind::BasicOp(op))), } } } impl SpecialOp { pub fn decode(op: u16) -> Result<SpecialOp> { match SpecialOp::from_u16(op) { Some(o) => Ok(o), None => try!(Err(ErrorKind::SpecialOp(op))), } } }