lc3_ensemble/ast/
sim.rs

1//! This module is used for holding simulation instructions ([`SimInstr`]),
2//! which are instructions that directly map to bytecode.
3//! 
4//! For instructions that map to assembly source code 
5//! (i.e., the text representation of assembly instructions), see [`asm::AsmInstr`].
6//! 
7//! [`asm::AsmInstr`]: crate::ast::asm::AsmInstr
8
9use std::fmt::Write as _;
10use std::ops::Range;
11
12use crate::sim::SimErr;
13
14use super::{CondCode, IOffset, ImmOrReg, Reg, TrapVect8};
15
16const OP_BR: u16   = 0b0000; 
17const OP_ADD: u16  = 0b0001; 
18const OP_LD: u16   = 0b0010; 
19const OP_ST: u16   = 0b0011; 
20const OP_JSR: u16  = 0b0100; 
21const OP_AND: u16  = 0b0101; 
22const OP_LDR: u16  = 0b0110; 
23const OP_STR: u16  = 0b0111; 
24const OP_RTI: u16  = 0b1000; 
25const OP_NOT: u16  = 0b1001; 
26const OP_LDI: u16  = 0b1010; 
27const OP_STI: u16  = 0b1011; 
28const OP_JMP: u16  = 0b1100; 
29const OP_LEA: u16  = 0b1110; 
30const OP_TRAP: u16 = 0b1111; 
31
32/// An enum representing all of the possible instructions in LC-3 bytecode.
33/// 
34/// The variants in this enum represent instructions after the both assembly passes.
35/// There are no notions of aliases and labels in the variants in this enum.
36/// 
37/// For instructions that map to assembly source code 
38/// (i.e., the text representation of assembly instructions), refer to [`asm::AsmInstr`].
39/// 
40/// [`asm::AsmInstr`]: crate::ast::asm::AsmInstr
41#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
42pub enum SimInstr {
43    #[allow(missing_docs)]
44    BR(CondCode, IOffset<9>),
45    #[allow(missing_docs)]
46    ADD(Reg, Reg, ImmOrReg<5>),
47    #[allow(missing_docs)]
48    LD(Reg, IOffset<9>),
49    #[allow(missing_docs)]
50    ST(Reg, IOffset<9>),
51    #[allow(missing_docs)]
52    JSR(ImmOrReg<11>),
53    #[allow(missing_docs)]
54    AND(Reg, Reg, ImmOrReg<5>),
55    #[allow(missing_docs)]
56    LDR(Reg, Reg, IOffset<6>),
57    #[allow(missing_docs)]
58    STR(Reg, Reg, IOffset<6>),
59    #[allow(missing_docs)]
60    RTI,
61    #[allow(missing_docs)]
62    NOT(Reg, Reg),
63    #[allow(missing_docs)]
64    LDI(Reg, IOffset<9>),
65    #[allow(missing_docs)]
66    STI(Reg, IOffset<9>),
67    #[allow(missing_docs)]
68    JMP(Reg),
69    // Reserved,
70    #[allow(missing_docs)]
71    LEA(Reg, IOffset<9>),
72    #[allow(missing_docs)]
73    TRAP(TrapVect8),
74}
75impl std::fmt::Display for SimInstr {
76    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
77        match self {
78            Self::BR(cc, off) => {
79                if cc != &0 {
80                    write!(f, "BR")?;
81                    if cc & 0b100 != 0 { f.write_char('n')?; };
82                    if cc & 0b010 != 0 { f.write_char('z')?; };
83                    if cc & 0b001 != 0 { f.write_char('p')?; };
84                } else {
85                    write!(f, "NOP")?;
86                }
87                
88                write!(f, " {off}")
89            },
90            Self::ADD(dr, sr1, sr2) => write!(f, "ADD {dr}, {sr1}, {sr2}"),
91            Self::LD(dr, off) => write!(f, "LD {dr}, {off}"),
92            Self::ST(sr, off) => write!(f, "ST {sr}, {off}"),
93            Self::JSR(off) => match off {
94                ImmOrReg::Imm(imm) => write!(f, "JSR {imm}"),
95                ImmOrReg::Reg(reg) => write!(f, "JSRR {reg}"),
96            },
97            Self::AND(dr, sr1, sr2) => write!(f, "AND {dr}, {sr1}, {sr2}"),
98            Self::LDR(dr, br, off) => write!(f, "LDR {dr}, {br}, {off}"),
99            Self::STR(sr, br, off) => write!(f, "STR {sr}, {br}, {off}"),
100            Self::RTI   => f.write_str("RTI"),
101            Self::NOT(dr, sr) => write!(f, "NOT {dr}, {sr}"),
102            Self::LDI(dr, off) => write!(f, "LDI {dr}, {off}"),
103            Self::STI(sr, off) => write!(f, "STI {sr}, {off}"),
104            Self::JMP(br) => write!(f, "JMP {br}"),
105            Self::LEA(dr, off) => write!(f, "LEA {dr}, {off}"),
106            Self::TRAP(vect) => write!(f, "TRAP {vect:02X}")
107        }
108    }
109}
110
111impl SimInstr {
112    /// Gets the opcode for the given instruction. This is always 4 bits.
113    pub fn opcode(&self) -> u16 {
114        match self {
115            SimInstr::BR(_, _) => OP_BR,
116            SimInstr::ADD(_, _, _) => OP_ADD,
117            SimInstr::LD(_, _) => OP_LD,
118            SimInstr::ST(_, _) => OP_ST,
119            SimInstr::JSR(_) => OP_JSR,
120            SimInstr::AND(_, _, _) => OP_AND,
121            SimInstr::LDR(_, _, _) => OP_LDR,
122            SimInstr::STR(_, _, _) => OP_STR,
123            SimInstr::RTI => OP_RTI,
124            SimInstr::NOT(_, _) => OP_NOT,
125            SimInstr::LDI(_, _) => OP_LDI,
126            SimInstr::STI(_, _) => OP_STI,
127            SimInstr::JMP(_) => OP_JMP,
128            // reserved => 0b1101
129            SimInstr::LEA(_, _) => OP_LEA,
130            SimInstr::TRAP(_) => OP_TRAP,
131        }
132    }
133
134    /// Encodes this instruction as 16-bit bytecode.
135    pub fn encode(&self) -> u16 {
136        match self {
137            SimInstr::BR(cc, off) => join_bits([
138                (self.opcode(),    12..16),
139                (*cc as u16,       9..12),
140                (off.get() as u16, 0..9)
141            ]),
142            SimInstr::ADD(dr, sr1, ImmOrReg::Imm(i2)) => join_bits([ // ADD DR, SR1, imm5
143                (self.opcode(),       12..16),
144                (dr.reg_no() as u16,  9..12),
145                (sr1.reg_no() as u16, 6..9),
146                (0b1,                 5..6),
147                (i2.get() as u16,     0..5)
148            ]),
149            SimInstr::ADD(dr, sr1, ImmOrReg::Reg(r2)) => join_bits([ // ADD DR, SR1, SR2
150                (self.opcode(),       12..16),
151                (dr.reg_no() as u16,  9..12),
152                (sr1.reg_no() as u16, 6..9),
153                (0b000,               3..6),
154                (r2.reg_no() as u16,  0..3)
155            ]),
156            SimInstr::LD(dr, off) => join_bits([
157                (self.opcode(),      12..16),
158                (dr.reg_no() as u16, 9..12),
159                (off.get() as u16,   0..9)
160            ]),
161            SimInstr::ST(sr, off) => join_bits([
162                (self.opcode(),      12..16),
163                (sr.reg_no() as u16, 9..12),
164                (off.get() as u16,   0..9)
165            ]),
166            SimInstr::JSR(ImmOrReg::Imm(off)) => join_bits([ // JSR
167                (self.opcode(),    12..16),
168                (0b1,              11..12),
169                (off.get() as u16, 0..11)
170            ]),
171            SimInstr::JSR(ImmOrReg::Reg(br)) => join_bits([ // JSRR
172                (self.opcode(),      12..16),
173                (0b000,              9..12),
174                (br.reg_no() as u16, 6..9),
175                (0b000_000,          0..6)
176            ]),
177            SimInstr::AND(dr, sr1, ImmOrReg::Imm(i2)) => join_bits([ // AND DR, SR1, imm5
178                (self.opcode(),       12..16),
179                (dr.reg_no() as u16,  9..12),
180                (sr1.reg_no() as u16, 6..9),
181                (0b1,                 5..6),
182                (i2.get() as u16,     0..5)
183            ]),
184            SimInstr::AND(dr, sr1, ImmOrReg::Reg(r2)) => join_bits([ // AND DR, SR1, SR2
185                (self.opcode(),      12..16),
186                (dr.reg_no() as u16,  9..12),
187                (sr1.reg_no() as u16, 6..9),
188                (0b000,               3..6),
189                (r2.reg_no() as u16,  0..3)
190            ]),
191            SimInstr::LDR(dr, br, off) => join_bits([
192                (self.opcode(),      12..16),
193                (dr.reg_no() as u16, 9..12),
194                (br.reg_no() as u16, 6..9),
195                (off.get() as u16,   0..6)
196            ]),
197            SimInstr::STR(dr, br, off) => join_bits([
198                (self.opcode(),      12..16),
199                (dr.reg_no() as u16, 9..12),
200                (br.reg_no() as u16, 6..9),
201                (off.get() as u16,   0..6)
202            ]),
203            SimInstr::RTI => join_bits([
204                (self.opcode(),    12..16),
205                (0b0000_0000_0000, 0..12)
206            ]),
207            SimInstr::NOT(dr, sr) => join_bits([
208                (self.opcode(),      12..16),
209                (dr.reg_no() as u16, 9..12),
210                (sr.reg_no() as u16, 6..9),
211                (0b111_111,          0..6)
212            ]),
213            SimInstr::LDI(dr, off) => join_bits([
214                (self.opcode(),      12..16),
215                (dr.reg_no() as u16, 9..12),
216                (off.get() as u16,   0..9)
217            ]),
218            SimInstr::STI(sr, off) => join_bits([
219                (self.opcode(),      12..16),
220                (sr.reg_no() as u16, 9..12),
221                (off.get() as u16,   0..9)
222            ]),
223            SimInstr::JMP(br) => join_bits([
224                (self.opcode(),      12..16),
225                (0b000,              9..12),
226                (br.reg_no() as u16, 6..9),
227                (0b000_000,          0..6)
228            ]),
229            SimInstr::LEA(dr, off) => join_bits([
230                (self.opcode(),      12..16),
231                (dr.reg_no() as u16, 9..12),
232                (off.get() as u16,   0..9)
233            ]),
234            SimInstr::TRAP(vect) => join_bits([
235                (self.opcode(), 12..16),
236                (0b0000,        8..12),
237                (vect.get(),    0..8)
238            ]),
239        }
240    }
241
242    /// Converts a 16-bit bytecode representation into a `SimInstr`.
243    /// This will error if the format is invalid.
244    pub fn decode(word: u16) -> Result<Self, SimErr> {
245        // Note, there's a lot of magic being used in this function.
246        // Refer to `DecodeUtils` at the bottom of this file.
247        let opcode = word.slice(12..16);
248
249        match opcode {
250            OP_BR => {
251                let cc  = word.slice(9..12) as u8;
252                let off = word.slice(0..9).interpret();
253                Ok(Self::BR(cc, off))
254            },
255            OP_ADD => {
256                let dr  = word.slice(9..12).interpret();
257                let sr1 = word.slice(6..9).interpret();
258                let sr2 = match word.slice(5..6) != 0 {
259                    false => {
260                        word.slice(3..5).assert_equals(0b00)?;
261                        ImmOrReg::Reg(word.slice(0..3).interpret())
262                    },
263                    true  => ImmOrReg::Imm(word.slice(0..5).interpret()),
264                };
265                Ok(Self::ADD(dr, sr1, sr2))
266            },
267            OP_LD => {
268                let dr  = word.slice(9..12).interpret();
269                let off = word.slice(0..9).interpret();
270                Ok(Self::LD(dr, off))
271            }
272            OP_ST => {
273                let sr  = word.slice(9..12).interpret();
274                let off = word.slice(0..9).interpret();
275                Ok(Self::ST(sr, off))
276            },
277            OP_JSR => {
278                let val = match word.slice(11..12) != 0 {
279                    true  => ImmOrReg::Imm(word.slice(0..11).interpret()),
280                    false => {
281                        word.slice(9..11).assert_equals(0b00)?;
282                        word.slice(0..6).assert_equals(0b000_000)?;
283                        ImmOrReg::Reg(word.slice(6..9).interpret())
284                    },
285                };
286                Ok(Self::JSR(val))
287            },
288            OP_AND => {
289                let dr  = word.slice(9..12).interpret();
290                let sr1 = word.slice(6..9).interpret();
291                let sr2 = match word.slice(5..6) != 0 {
292                    false => {
293                        word.slice(3..5).assert_equals(0b00)?;
294                        ImmOrReg::Reg(word.slice(0..3).interpret())
295                    },
296                    true  => ImmOrReg::Imm(word.slice(0..5).interpret()),
297                };
298                Ok(Self::AND(dr, sr1, sr2))
299            },
300            OP_LDR => {
301                let dr  = word.slice(9..12).interpret();
302                let br  = word.slice(6..9).interpret();
303                let off = word.slice(0..6).interpret();
304                Ok(Self::LDR(dr, br, off))
305            },
306            OP_STR => {
307                let sr  = word.slice(9..12).interpret();
308                let br  = word.slice(6..9).interpret();
309                let off = word.slice(0..6).interpret();
310                Ok(Self::STR(sr, br, off))
311            },
312            OP_RTI => {
313                word.slice(0..12).assert_equals(0b0000_0000_0000)?;
314                Ok(Self::RTI)
315            },
316            OP_NOT => {
317                let dr = word.slice(9..12).interpret();
318                let sr = word.slice(6..9).interpret();
319                word.slice(0..6).assert_equals(0b111_111)?;
320                Ok(Self::NOT(dr, sr))
321            },
322            OP_LDI => {
323                let dr  = word.slice(9..12).interpret();
324                let off = word.slice(0..9).interpret();
325                Ok(Self::LDI(dr, off))
326            },
327            OP_STI => {
328                let sr  = word.slice(9..12).interpret();
329                let off = word.slice(0..9).interpret();
330                Ok(Self::STI(sr, off))
331            },
332            OP_JMP => {
333                word.slice(9..11).assert_equals(0b00)?;
334                let reg = word.slice(6..9).interpret();
335                word.slice(0..6).assert_equals(0b000_000)?;
336                Ok(Self::JMP(reg))
337            },
338            OP_LEA => {
339                let dr  = word.slice(9..12).interpret();
340                let off = word.slice(0..9).interpret();
341                Ok(Self::LEA(dr, off))
342            },
343            OP_TRAP => {
344                word.slice(8..12).assert_equals(0b0000)?;
345                let vect = word.slice(0..8).interpret();
346                Ok(Self::TRAP(vect))
347            },
348            _ => Err(SimErr::IllegalOpcode)
349        }
350    }
351}
352
353/// Given a sequence of values and ranges, it writes each value into its corresponding range,
354/// truncating the input value if it is too long.
355fn join_bits<const N: usize>(bits: [(u16, Range<usize>); N]) -> u16 {
356    bits.into_iter()
357        .map(|(val, Range { start, end })| {
358            let len = end - start;
359            let mask = (1 << len) - 1;
360            (val & mask) << start
361        })
362        .fold(0, std::ops::BitOr::bitor)
363}
364
365trait FromBits: Sized {
366    /// Converts bits into self, assuming bits are the correct size.
367    fn from_bits(bits: u16) -> Self;
368}
369trait DecodeUtils: Sized + Eq {
370    /// Interprets the bits as another value.
371    fn interpret<T: FromBits>(self) -> T;
372
373    /// Asserts the two are equal or errors.
374    fn assert_equals(self, bits: Self) -> Result<(), SimErr> {
375        match self == bits {
376            true  => Ok(()),
377            false => Err(SimErr::InvalidInstrFormat),
378        }
379    }
380
381    /// Gets the bits of `self` within the range provided,
382    /// returning them as the least-significant bits
383    fn slice(self, range: Range<usize>) -> Self;
384}
385impl DecodeUtils for u16 {
386    fn interpret<T: FromBits>(self) -> T {
387        T::from_bits(self)
388    }
389
390    fn slice(self, range: Range<usize>) -> Self {
391        let len = range.end - range.start;
392        (self >> range.start) & ((1 << len) - 1)
393    }
394}
395
396impl FromBits for Reg {
397    fn from_bits(bits: u16) -> Self {
398        Reg::try_from(bits as u8).unwrap()
399    }
400}
401impl<const N: u32> FromBits for IOffset<N> {
402    fn from_bits(bits: u16) -> Self {
403        Self::new_trunc(bits as i16)
404    }
405}
406impl<const N: u32> FromBits for crate::ast::Offset<u16, N> {
407    fn from_bits(bits: u16) -> Self {
408        Self::new_trunc(bits)
409    }
410}