lc3b_isa/
instruction.rs

1#![allow(dead_code)]
2
3use std::str::FromStr;
4
5use crate::Register;
6
7#[derive(Debug, PartialEq, Clone, Copy)]
8pub enum Instruction {
9    AddInstruction(AddInstruction),
10    AndInstruction(AndInstruction),
11    Br(Condition, PCOffset9),
12    Jmp(Register),
13    Jsr(PCOffset11),
14    Jsrr(Register),
15    Ldb(Register, Register, PCOffset6),
16    Ldi(Register, Register, PCOffset6),
17    Ldr(Register, Register, PCOffset6),
18    Lea(Register, PCOffset9),
19    Not(Register, Register),
20    Ret,
21    Rti,
22    Shf(Register, Register, Bit, Bit, Immediate4),
23    Stb(Register, Register, PCOffset6),
24    Sti(Register, Register, PCOffset6),
25    Str(Register, Register, PCOffset6),
26    Trap(TrapVect8),
27}
28
29impl From<&Instruction> for [u8; 2] {
30    fn from(value: &Instruction) -> Self {
31        let mut bytes = [0; 2];
32
33        match value {
34            Instruction::AddInstruction(AddInstruction::AddReg(r1, r2, r3)) => {
35                bytes[0] |= 0b00010000;
36                bytes[0] |= (r1.to_index() as u8) << 1;
37                bytes[0] |= (r2.to_index() as u8) >> 2;
38
39                bytes[1] |= (r2.to_index() as u8) << 6;
40                bytes[1] |= (r3.to_index() as u8) << 0;
41            }
42            Instruction::AddInstruction(AddInstruction::AddImm(r1, r2, imm5)) => {
43                bytes[0] |= 0b00010000;
44                bytes[0] |= (r1.to_index() as u8) << 1;
45                bytes[0] |= (r2.to_index() as u8) >> 2;
46
47                bytes[1] |= (r2.to_index() as u8) << 6;
48                bytes[1] |= 0b00100000;
49                bytes[1] |= imm5.0 & 0b00011111;
50            }
51            other => todo!("wah: {:?}", other),
52        }
53
54        bytes
55    }
56}
57
58#[derive(Debug, PartialEq, Clone, Copy)]
59pub enum AddInstruction {
60    AddReg(Register, Register, Register),
61    AddImm(Register, Register, Immediate5),
62}
63
64#[derive(Debug, PartialEq, Clone, Copy)]
65pub enum AndInstruction {
66    AndReg(Register, Register, Register),
67    AndImm(Register, Register, Immediate5),
68}
69
70#[derive(Debug, PartialEq, Clone, Copy)]
71pub struct Immediate5(pub(crate) u8);
72
73impl Immediate5 {
74    pub fn new(imm5: u8) -> eyre::Result<Self> {
75        assert!(imm5 < 32);
76        if imm5 >= 32 {
77            return Err(eyre::eyre!("value `{}` too large, must be < 32", imm5));
78        }
79
80        Ok(Immediate5(imm5))
81    }
82
83    pub fn value(&self) -> u8 {
84        self.0
85    }
86}
87
88impl FromStr for Immediate5 {
89    type Err = eyre::Report;
90
91    fn from_str(s: &str) -> Result<Self, Self::Err> {
92        // TODO: range check
93        Self::new(s.parse()?)
94    }
95}
96
97impl Immediate5 {
98    pub fn to_value(&self) -> u16 {
99        self.0 as u16
100    }
101}
102
103#[derive(Debug, PartialEq, Clone, Copy)]
104pub struct Immediate4(pub(crate) u8);
105
106impl Immediate4 {
107    pub fn new(val: u8) -> eyre::Result<Self> {
108        if val >= 16 {
109            return Err(eyre::eyre!("value `{}` too large, must be < 16", val));
110        }
111
112        Ok(Immediate4(val))
113    }
114}
115
116#[derive(Debug, Default, PartialEq, Clone, Copy)]
117pub struct Condition {
118    n: bool,
119    z: bool,
120    p: bool,
121}
122
123#[derive(Debug, PartialEq, Clone, Copy)]
124pub struct PCOffset9(u16);
125#[derive(Debug, PartialEq, Clone, Copy)]
126pub struct PCOffset11(u16);
127#[derive(Debug, PartialEq, Clone, Copy)]
128pub struct PCOffset6(u8);
129
130#[derive(Debug, PartialEq, Clone, Copy)]
131pub struct Bit(bool);
132
133#[derive(Debug, PartialEq, Clone, Copy)]
134pub struct TrapVect8(u8);