158 lines
2.5 KiB
Rust
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}
|
|
}
|
|
} |