emu/src/instr.rs

158 lines
2.5 KiB
Rust

#[derive(Clone, Debug)]
pub enum Instr {
Invalid,
Normal {
cond: Cond,
op: Op,
a: u8,
b: u8,
c: u8,
}
}
#[derive(Clone, Debug)]
pub enum Cond {
Uncond,
IfTrue,
IfFalse,
}
#[derive(Clone, Debug)]
pub enum Op {
// arithmetic and logic
Add,
AddI,
Sub,
Or,
OrI,
Xor,
XorI,
And,
AndI,
Shl,
Shr,
// comparison
CmpRR(Cm),
CmpRI(Cm),
CmpII(Cm),
// shift/rotate by immediate
ShlI,
ShrI,
Sar,
Rol,
// indirect memory access
Load,
Store,
// fixed-point multiply
Fmu,
Fms,
// control flow
Label,
JmpUp,
JmpDn,
// device io
IO,
}
#[derive(Clone, Debug)]
pub enum Cm {
Tr,
Fa,
Eq,
Ne,
Sl,
Sg,
Ul,
Ug,
}
impl Instr {
pub fn decode(instr: u32) -> Instr {
let opc = instr >> 18;
let a = ((instr >> 12) & 0b111111) as u8;
let b = ((instr >> 6) & 0b111111) as u8;
let c = (instr & 0b111111) as u8;
if opc == 0 { return Instr::Invalid; }
let cond = match (opc - 1) / 21 {
0 => Cond::Uncond,
1 => Cond::IfTrue,
2 => Cond::IfFalse,
_ => unreachable!("invalid cond: {:o}", opc),
};
let op = match (opc - 1) % 21 {
// arithmetic and logic
0o000 => Op::Add,
0o001 => Op::AddI,
0o002 => Op::Sub,
0o004 => Op::Or,
0o005 => Op::OrI,
0o006 => Op::Xor,
0o007 => Op::XorI,
0o010 => Op::And,
0o011 => Op::AndI,
0o013 => Op::Shl,
0o014 => Op::Shr,
// comparison
0o003 => {
let cc = match a % 0o010 {
0 => Cm::Tr,
1 => Cm::Fa,
2 => Cm::Eq,
3 => Cm::Ne,
4 => Cm::Sl,
5 => Cm::Sg,
6 => Cm::Ul,
7 => Cm::Ug,
v => unreachable!("invalid 003 cc: {:o}", a),
};
match a / 0o010 {
0 => Op::CmpRR(cc),
2 => Op::CmpRI(cc),
3 => Op::CmpII(cc),
v => unreachable!("invalid 003: {:o}", a),
}
},
// shift/rotate by immediate
0o012 => match c / 0o010 {
0 => Op::ShlI,
1 => Op::ShrI,
2 => Op::Sar,
3 => Op::Rol,
v => unreachable!("invalid 012: {:o}", c),
}
// indirect memory access
0o015 => Op::Load,
0o016 => Op::Store,
// fixed-point multiply
0o023 => match c / 0o020 {
0 => Op::Fmu,
1 => Op::Fms,
v => unreachable!("invalid 023: {:o}", c),
}
// control flow
0o017 => Op::Label,
0o020 => Op::JmpUp,
0o021 => Op::JmpDn,
// device io
0o022 => Op::IO,
v if v >= 21 => unreachable!("invalid {:o}", v),
_ => unreachable!("shiet"),
};
Instr::Normal {cond, op, a, b, c}
}
}