You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
4.9 KiB
144 lines
4.9 KiB
// SPDX-License-Identifier: MIT
|
|
// Copyright Murad Karammaev, Nikita Kuzmin
|
|
|
|
use ux::{u2, u3, u4};
|
|
|
|
#[derive(Debug)]
|
|
enum Register {
|
|
R0,
|
|
R1,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum ShiftMode {
|
|
Logical,
|
|
Circular,
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum Instruction {
|
|
Load { reg: Register, addr: u4 },
|
|
Store { reg: Register, addr: u4 },
|
|
LoadImmediate { low: bool, reg: Register, val: u4 },
|
|
NearJumpBackward { use_carry: bool, offset: u2 },
|
|
NearJumpForward { use_carry: bool, offset: u3 },
|
|
FarJump { reg: Register, use_carry: bool },
|
|
CmpEqual,
|
|
CmpGreater,
|
|
CmpLess,
|
|
Not,
|
|
BitShift { right: bool, reg: Register, mode: ShiftMode, len: u3 },
|
|
Inc { reg: Register },
|
|
Dec { reg: Register },
|
|
Add,
|
|
Sub,
|
|
And,
|
|
Or,
|
|
Xor,
|
|
Xnor,
|
|
Complement { reg: Register },
|
|
BitShiftVar { right: bool, mode: ShiftMode },
|
|
Copy { reg_from: Register },
|
|
Setc { carry: bool },
|
|
Nop,
|
|
Reset,
|
|
Cload { reg: Register },
|
|
Zero { reg: Register },
|
|
Div,
|
|
Mul,
|
|
Swap,
|
|
PortReady,
|
|
ReadPort,
|
|
WritePort,
|
|
}
|
|
|
|
fn decode(insn: u8) -> Instruction {
|
|
match insn {
|
|
0b00000000..=0b00111111 => {
|
|
let reg = if insn & 0b00010000 == 0 { Register::R0 } else { Register::R1 };
|
|
let addr = u4::new(insn & 0b00001111);
|
|
match insn & 0b00100000 {
|
|
0 => Instruction::Load {reg, addr},
|
|
_ => Instruction::Store {reg, addr},
|
|
}
|
|
},
|
|
0b01000000..=0b01111111 => Instruction::LoadImmediate {
|
|
low: insn & 0b00100000 != 0,
|
|
reg: if insn & 0b00010000 == 0 { Register::R0 } else { Register::R1 },
|
|
val: u4::new(insn & 0b00001111),
|
|
},
|
|
0b10001000..=0b10001111 => Instruction::NearJumpBackward {
|
|
use_carry: insn & 0b00000100 != 0,
|
|
offset: u2::new(insn & 0b00000011),
|
|
},
|
|
0b10010000..=0b10011111 => Instruction::NearJumpForward {
|
|
use_carry: insn & 0b00001000 != 0,
|
|
offset: u3::new(insn & 0b00000111),
|
|
},
|
|
0b10000000..=0b10000011 => Instruction::FarJump {
|
|
reg: if insn & 0b00000010 == 0 { Register::R0 } else { Register::R1 },
|
|
use_carry: insn & 0b00000001 != 0,
|
|
},
|
|
0b10000100 => Instruction::CmpEqual,
|
|
0b10000101 => Instruction::CmpGreater,
|
|
0b10000110 => Instruction::CmpLess,
|
|
0b10000111 => Instruction::Not,
|
|
0b10100000..=0b10111111 => Instruction::BitShift {
|
|
right: true,
|
|
reg: if insn & 0b00010000 == 0 { Register::R0 } else { Register::R1 },
|
|
mode: if insn & 0b00001000 == 0 { ShiftMode::Logical } else { ShiftMode::Circular },
|
|
len: u3::new(insn & 0b00000111),
|
|
},
|
|
0b11000000..=0b11011111 => Instruction::BitShift {
|
|
right: false,
|
|
reg: if insn & 0b00010000 == 0 { Register::R0 } else { Register::R1 },
|
|
mode: if insn & 0b00001000 == 0 { ShiftMode::Logical } else { ShiftMode::Circular },
|
|
len: u3::new(insn & 0b00000111),
|
|
},
|
|
0b11100000..=0b11100001 => Instruction::Inc {
|
|
reg: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11100010..=0b11100011 => Instruction::Dec {
|
|
reg: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11100100 => Instruction::Add,
|
|
0b11100101 => Instruction::Sub,
|
|
0b11100110 => Instruction::And,
|
|
0b11100111 => Instruction::Or,
|
|
0b11101000 => Instruction::Xor,
|
|
0b11101001 => Instruction::Xnor,
|
|
0b11101010..=0b11101011 => Instruction::Complement {
|
|
reg: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11101100..=0b11101111 => Instruction::BitShiftVar {
|
|
right: insn & 0b00000010 != 0,
|
|
mode: if insn & 0b00000001 == 0 { ShiftMode::Logical } else { ShiftMode::Circular },
|
|
},
|
|
0b11110000..=0b11110001 => Instruction::Copy {
|
|
reg_from: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11110010..=0b11110011 => Instruction::Setc {
|
|
carry: insn & 0b00000001 != 0,
|
|
},
|
|
0b11110100 => Instruction::Nop,
|
|
0b11110101 => Instruction::Reset,
|
|
0b11110110..=0b11110111 => Instruction::Cload {
|
|
reg: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11111000..=0b11111001 => Instruction::Zero {
|
|
reg: if insn & 0b00000001 == 0 { Register::R0 } else { Register::R1 },
|
|
},
|
|
0b11111010 => Instruction::Div,
|
|
0b11111011 => Instruction::Mul,
|
|
0b11111100 => Instruction::Swap,
|
|
0b11111101 => Instruction::PortReady,
|
|
0b11111110 => Instruction::ReadPort,
|
|
0b11111111 => Instruction::WritePort,
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
for i in 0..=255u8 {
|
|
println!("{:#08b} -> {:?}", i, decode(i));
|
|
}
|
|
}
|
|
|