Murad
2 years ago
4 changed files with 1855 additions and 138 deletions
File diff suppressed because it is too large
@ -0,0 +1,235 @@ |
|||||
|
// SPDX-License-Identifier: MIT
|
||||
|
// Copyright Murad Karammaev, Nikita Kuzmin
|
||||
|
|
||||
|
use ux::{u2, u3, u4}; |
||||
|
|
||||
|
#[derive(Debug)] |
||||
|
pub enum Register { |
||||
|
R0, |
||||
|
R1, |
||||
|
} |
||||
|
|
||||
|
#[derive(Debug)] |
||||
|
pub enum ShiftMode { |
||||
|
Logical, |
||||
|
Circular, |
||||
|
} |
||||
|
|
||||
|
#[derive(Debug)] |
||||
|
pub 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, |
||||
|
Halt, |
||||
|
Cload { |
||||
|
reg: Register, |
||||
|
}, |
||||
|
Zero { |
||||
|
reg: Register, |
||||
|
}, |
||||
|
Div, |
||||
|
Mul, |
||||
|
Swap, |
||||
|
PortReady, |
||||
|
ReadPort, |
||||
|
WritePort, |
||||
|
} |
||||
|
|
||||
|
pub 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::Halt, |
||||
|
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, |
||||
|
} |
||||
|
} |
@ -1,144 +1,16 @@ |
|||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||
// Copyright Murad Karammaev, Nikita Kuzmin
|
// Copyright Murad Karammaev, Nikita Kuzmin
|
||||
|
|
||||
use ux::{u2, u3, u4}; |
mod cpu; |
||||
|
mod instruction; |
||||
|
|
||||
#[derive(Debug)] |
use cpu::*; |
||||
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() { |
fn main() { |
||||
for i in 0..=255u8 { |
let mut cpu = CPU::new(&[]); |
||||
println!("{:#08b} -> {:?}", i, decode(i)); |
loop { |
||||
|
if cpu.step() { |
||||
|
break; |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
Loading…
Reference in new issue