cfd16_lib/
lib.rs

1//! A library for constructing, printing, encoding, and decoding
2//! CFD-16 assembly instructions.
3//!
4//! This common model and functionality is used throughout the CFD-16
5//! tooling programs such as [cfd16-as](../../cfd16-assem),
6//! [cfd16-objdump](../../cfd16-objdump), etc...
7
8#![warn(missing_docs)]
9
10use std::{default, error::Error, fmt};
11
12use cfd16_lib_impl::{Codable, Mode};
13
14mod parse;
15
16#[allow(missing_docs)]
17pub mod prelude;
18
19#[cfg(test)]
20mod tests;
21
22/// A builder pattern for [Instruction]s that ensures they are always
23/// valid when instantiated.
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct InstructionBuilder {
26    /// A code representing the instruction executed on the processor.
27    pub opcode: OpCode,
28
29    /// A code which specifies under which conditions to execute.
30    pub cdcode: CondCode,
31
32    /// Whether the status register should be updated.
33    pub update: bool,
34
35    /// Arguments provided to the instruction, interpreted as specified
36    /// in [OpCode]
37    pub args: Vec<Argument>,
38}
39
40impl default::Default for InstructionBuilder {
41    fn default() -> Self {
42        // NOTE: Effectively a NOP.
43        InstructionBuilder::new(OpCode::Add)
44            .argument(Argument::Reg(Register::A))
45            .argument(Argument::Imm(0))
46    }
47}
48
49impl InstructionBuilder {
50    /// Constructs a new instruction builder with default values for
51    /// condition, arguments, and s-bit from an [opcode](OpCode). Should
52    /// be used in conjunction with chained methods like
53    /// [condition](InstructionBuilder::condition) and
54    /// [argument](InstructionBuilder::argument) when manually
55    /// constructing a valid instruction.
56    pub fn new(opcode: OpCode) -> Self {
57        Self {
58            opcode,
59            cdcode: CondCode::default(),
60            update: false,
61            args: vec![],
62        }
63    }
64
65    /// Sets the condition of an existing instruction to the chosen
66    /// [condition code](CondCode). Can be chained with other methods.
67    pub fn condition(mut self, cond: CondCode) -> Self {
68        self.cdcode = cond;
69        self
70    }
71
72    /// Appends an [argument](Argument) to an existing instruction.
73    /// Can be chained with other methods operating on
74    /// [InstructionBuilder].
75    pub fn argument(mut self, arg: Argument) -> Self {
76        self.args.push(arg);
77        self
78    }
79
80    /// Sets the s-bit of an existing instruction. Can be chained with
81    /// other methods.
82    pub fn update(mut self) -> Self {
83        self.update = true;
84        self
85    }
86
87    /// Replaces any labels with the same name as the value provided with
88    /// a copy of the argument provided.
89    pub fn replace(&mut self, label: &str, value: Argument) {
90        let mut newargs = vec![];
91
92        for arg in &self.args {
93            match arg {
94                Argument::Label(l) if l == label => newargs.push(value.clone()),
95                a => newargs.push(a.clone()),
96            }
97        }
98
99        self.args = newargs;
100    }
101
102    /// Attempts to build a valid, encodable instruction from the
103    /// arguments in the [InstructionBuilder]. Will return an
104    /// [InstructionError] on invalid instructions.
105    ///
106    /// ```rust
107    /// use cfd16_lib::prelude::*;
108    ///
109    /// let wrong = InstructionBuilder::new(OpCode::Ret)
110    ///     .argument(Argument::Reg(Register::B))
111    ///     .build();
112    ///
113    /// assert!(wrong.is_err());
114    /// ```
115    pub fn build(mut self) -> Result<Instruction, InstructionError> {
116        use Argument::*;
117        use CondCode::*;
118        use InstructionError::*;
119        use OpCode::*;
120
121        // Check whether the condition code is valid for the instruction.
122        if match (self.opcode, self.cdcode) {
123            (Add, cond) if cond.encode() > 0b11 => true,
124            (And, cond) if cond.encode() > 0b11 => true,
125            (Ashr, cond) if cond.encode() > 0b11 => true,
126            (Cmp, cond) if cond.encode() > 0b11 => true,
127            (Jsr, cond) if cond.encode() > 0b11 => true,
128            (Ldb, cond) if cond.encode() > 0b11 => true,
129            (Ldr, cond) if cond.encode() > 0b11 => true,
130            (Mfhi, cond) if cond.encode() > 0b11 => true,
131            (Mov, cond) if cond != Always => true,
132            (Movr, cond) if cond.encode() > 0b11 => true,
133            (Movt, cond) if cond != Always => true,
134            (Mul, cond) if cond.encode() > 0b11 => true,
135            (Not, cond) if cond.encode() > 0b11 => true,
136            (Or, cond) if cond.encode() > 0b11 => true,
137            (Pop, cond) if cond.encode() > 0b11 => true,
138            (Push, cond) if cond.encode() > 0b11 => true,
139            (Ror, cond) if cond.encode() > 0b11 => true,
140            (Seg, cond) if cond.encode() > 0b11 => true,
141            (Shl, cond) if cond.encode() > 0b11 => true,
142            (Shr, cond) if cond.encode() > 0b11 => true,
143            (Stb, cond) if cond.encode() > 0b11 => true,
144            (Str, cond) if cond.encode() > 0b11 => true,
145            (Sub, cond) if cond.encode() > 0b11 => true,
146            (Uadd, cond) if cond.encode() > 0b11 => true,
147            (Umul, cond) if cond.encode() > 0b11 => true,
148            (Usub, cond) if cond.encode() > 0b11 => true,
149            (Xor, cond) if cond.encode() > 0b11 => true,
150            _ => false,
151        } {
152            return Err(InvalidCondCodeForInstr);
153        }
154
155        // Check the compatibility with the s-bit
156        if match (self.opcode, self.update) {
157            (Cmp, _) => {
158                self.update = true;
159                false
160            }
161
162            (Jsr, true) => true,
163            (Mov, true) => true,
164            (Movt, true) => true,
165            (Pop, true) => true,
166            (Push, true) => true,
167            (Ret, true) => true,
168            (Sc, true) => true,
169            (Seg, true) => true,
170            (Stb, true) => true,
171            (Str, true) => true,
172            (Ucmp, _) => {
173                self.update = true;
174                false
175            }
176
177            _ => false,
178        } {
179            return Err(CannotTakeSBit);
180        }
181
182        // Check argument compatibility
183        match (self.opcode, self.args.as_slice()) {
184            (Add, [Reg(_), Imm(-8..=7)]) => Ok(()),
185            (Add, [Reg(_), Imm(_)]) => Err(ImproperInteger),
186            (Add, [Reg(_), Reg(_)]) => Ok(()),
187            (Add, [Imm(_), ..]) => Err(WrongKindArgs),
188            (Add, _) => Err(WrongNumArgs),
189            (And, [Reg(_), Imm(0..=15)]) => Ok(()),
190            (And, [Reg(_), Imm(_)]) => Err(ImproperInteger),
191            (And, [Reg(_), Reg(_)]) => Ok(()),
192            (And, [Imm(_), ..]) => Err(WrongKindArgs),
193            (And, _) => Err(WrongNumArgs),
194            (Ashr, [Reg(_), Imm(0..=15)]) => Ok(()),
195            (Ashr, [Reg(_), Imm(_)]) => Err(ImproperInteger),
196            (Ashr, [Reg(_), Reg(_)]) => Ok(()),
197            (Ashr, [Imm(_), ..]) => Err(WrongKindArgs),
198            (Ashr, _) => Err(WrongNumArgs),
199            (Br, [Imm(-128..=127)]) => Ok(()),
200            (Br, [Imm(_)]) => Err(ImproperInteger),
201            (Br, [Reg(_)]) => Err(WrongKindArgs),
202            (Br, _) => Err(WrongNumArgs),
203            (Cmp, [Reg(_), Imm(-8..=7)]) => Ok(()),
204            (Cmp, [Reg(_), Imm(_)]) => Err(ImproperInteger),
205            (Cmp, [Reg(_), Reg(_)]) => Ok(()),
206            (Cmp, [Imm(_), ..]) => Err(WrongKindArgs),
207            (Cmp, _) => Err(WrongNumArgs),
208            (Jsr, [Reg(_)]) => Ok(()),
209            (Jsr, [Imm(_)]) => Err(WrongKindArgs),
210            (Jsr, _) => Err(WrongNumArgs),
211            (Ldb, [Reg(_), Reg(_)]) => Ok(()),
212            (Ldb, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
213            (Ldb, [Imm(_), ..]) => Err(WrongKindArgs),
214            (Ldb, _) => Err(WrongNumArgs),
215            (Ldr, [Reg(_), Reg(_)]) => Ok(()),
216            (Ldr, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
217            (Ldr, [Imm(_), ..]) => Err(WrongKindArgs),
218            (Ldr, _) => Err(WrongNumArgs),
219            (Mfhi, [Reg(_)]) => Ok(()),
220            (Mfhi, [Imm(_)]) => Err(WrongKindArgs),
221            (Mfhi, _) => Err(WrongNumArgs),
222            (Mov, [Reg(_), Imm(0..=255)]) => Ok(()),
223            (Mov, [Reg(_), Imm(_)]) => Err(ImproperInteger),
224            (Mov, [Reg(_), Reg(_)]) => Err(WrongKindArgs),
225            (Mov, [Imm(_), ..]) => Err(WrongKindArgs),
226            (Mov, _) => Err(WrongNumArgs),
227            (Movr, [Reg(_), Reg(_)]) => Ok(()),
228            (Movr, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
229            (Movr, [Imm(_), ..]) => Err(WrongKindArgs),
230            (Movr, _) => Err(WrongNumArgs),
231            (Movt, [Reg(_), Imm(0..=255)]) => Ok(()),
232            (Movt, [Reg(_), Imm(_)]) => Err(ImproperInteger),
233            (Movt, [Reg(_), Reg(_)]) => Err(WrongKindArgs),
234            (Movt, [Imm(_), ..]) => Err(WrongKindArgs),
235            (Movt, _) => Err(WrongNumArgs),
236            (Mul, [Reg(_), Imm(-8..=7)]) => Ok(()),
237            (Mul, [Reg(_), Imm(_)]) => Err(ImproperInteger),
238            (Mul, [Reg(_), Reg(_)]) => Ok(()),
239            (Mul, [Imm(_), ..]) => Err(WrongKindArgs),
240            (Mul, _) => Err(WrongNumArgs),
241            (Not, [Reg(_)]) => Ok(()),
242            (Not, [Imm(_)]) => Err(WrongKindArgs),
243            (Not, _) => Err(WrongNumArgs),
244            (Or, [Reg(_), Imm(0..=15)]) => Ok(()),
245            (Or, [Reg(_), Imm(_)]) => Err(ImproperInteger),
246            (Or, [Reg(_), Reg(_)]) => Ok(()),
247            (Or, [Imm(_), ..]) => Err(WrongKindArgs),
248            (Or, _) => Err(WrongNumArgs),
249            (Pop, [Reg(_)]) => Ok(()),
250            (Pop, [Imm(_)]) => Err(WrongKindArgs),
251            (Pop, _) => Err(WrongNumArgs),
252            (Push, [Imm(-128..=127)]) => Ok(()),
253            (Push, [Imm(_)]) => Err(ImproperInteger),
254            (Push, [Reg(_)]) => Ok(()),
255            (Push, _) => Err(WrongNumArgs),
256            (Ret, []) => Ok(()),
257            (Ret, _) => Err(WrongNumArgs),
258            (Ror, [Reg(_), Imm(0..=15)]) => Ok(()),
259            (Ror, [Reg(_), Imm(_)]) => Err(ImproperInteger),
260            (Ror, [Reg(_), Reg(_)]) => Ok(()),
261            (Ror, [Imm(_), ..]) => Err(WrongKindArgs),
262            (Ror, _) => Err(WrongNumArgs),
263            (Sc, [Imm(0..=255)]) => Ok(()),
264            (Sc, [Imm(_)]) => Err(ImproperInteger),
265            (Sc, [Reg(_)]) => Err(WrongKindArgs),
266            (Sc, _) => Err(WrongNumArgs),
267            (Seg, [Imm(0..=255)]) => Ok(()),
268            (Seg, [Imm(_)]) => Err(ImproperInteger),
269            (Seg, [Reg(_)]) => Ok(()),
270            (Seg, _) => Err(WrongNumArgs),
271            (Shl, [Reg(_), Imm(0..=15)]) => Ok(()),
272            (Shl, [Reg(_), Imm(_)]) => Err(ImproperInteger),
273            (Shl, [Reg(_), Reg(_)]) => Ok(()),
274            (Shl, [Imm(_), ..]) => Err(WrongKindArgs),
275            (Shl, _) => Err(WrongNumArgs),
276            (Shr, [Reg(_), Imm(0..=15)]) => Ok(()),
277            (Shr, [Reg(_), Imm(_)]) => Err(ImproperInteger),
278            (Shr, [Reg(_), Reg(_)]) => Ok(()),
279            (Shr, [Imm(_), ..]) => Err(WrongKindArgs),
280            (Shr, _) => Err(WrongNumArgs),
281            (Stb, [Reg(_), Reg(_)]) => Ok(()),
282            (Stb, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
283            (Stb, [Imm(_), ..]) => Err(WrongKindArgs),
284            (Stb, _) => Err(WrongNumArgs),
285            (Str, [Reg(_), Reg(_)]) => Ok(()),
286            (Str, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
287            (Str, [Imm(_), ..]) => Err(WrongKindArgs),
288            (Str, _) => Err(WrongNumArgs),
289            (Sub, [Reg(_), Imm(-8..=7)]) => Ok(()),
290            (Sub, [Reg(_), Imm(_)]) => Err(WrongKindArgs),
291            (Sub, [Reg(_), Reg(_)]) => Ok(()),
292            (Sub, [Imm(_), ..]) => Err(WrongKindArgs),
293            (Sub, _) => Err(WrongNumArgs),
294            (Uadd, [Reg(_), Imm(0..=15)]) => Ok(()),
295            (Uadd, [Reg(_), Imm(_)]) => Err(ImproperInteger),
296            (Uadd, [Reg(_), Reg(_)]) => Ok(()),
297            (Uadd, [Imm(_), ..]) => Err(WrongKindArgs),
298            (Uadd, _) => Err(WrongNumArgs),
299            (Ucmp, [Reg(_), Imm(0..=15)]) => Ok(()),
300            (Ucmp, [Reg(_), Imm(_)]) => Err(ImproperInteger),
301            (Ucmp, [Reg(_), Reg(_)]) => Ok(()),
302            (Ucmp, [Imm(_), ..]) => Err(WrongKindArgs),
303            (Ucmp, _) => Err(WrongNumArgs),
304            (Umul, [Reg(_), Imm(0..=15)]) => Ok(()),
305            (Umul, [Reg(_), Imm(_)]) => Err(ImproperInteger),
306            (Umul, [Reg(_), Reg(_)]) => Ok(()),
307            (Umul, [Imm(_), ..]) => Err(WrongKindArgs),
308            (Umul, _) => Err(WrongNumArgs),
309            (Usub, [Reg(_), Imm(0..=15)]) => Ok(()),
310            (Usub, [Reg(_), Imm(_)]) => Err(ImproperInteger),
311            (Usub, [Reg(_), Reg(_)]) => Ok(()),
312            (Usub, [Imm(_), ..]) => Err(WrongKindArgs),
313            (Usub, _) => Err(WrongNumArgs),
314            (Xor, [Reg(_), Imm(0..=15)]) => Ok(()),
315            (Xor, [Reg(_), Imm(_)]) => Err(ImproperInteger),
316            (Xor, [Reg(_), Reg(_)]) => Ok(()),
317            (Xor, [Imm(_), ..]) => Err(WrongKindArgs),
318            (Xor, _) => Err(WrongNumArgs),
319            (_RESERVED, _) => unreachable!(),
320        }?;
321
322        Ok(Instruction {
323            opcode: self.opcode,
324            cdcode: self.cdcode,
325            update: self.update,
326            args: self.args,
327        })
328    }
329}
330
331impl fmt::Display for InstructionBuilder {
332    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
333        write!(
334            f,
335            "{}",
336            Instruction {
337                opcode: self.opcode,
338                cdcode: self.cdcode,
339                update: self.update,
340                args: self.args.clone(),
341            }
342        )
343    }
344}
345
346/// An instruction for the CFD-16 ISA. Please use the [InstructionBuilder]
347/// interface to ensure that the built Instruction is valid.
348///
349/// ```rust
350/// use cfd16_lib::prelude::*;
351///
352/// let instr = InstructionBuilder::new(OpCode::Add)
353///     .condition(CondCode::Zero)
354///     .argument(Argument::Reg(Register::A))
355///     .argument(Argument::Reg(Register::B))
356///     .build()
357///     .unwrap();
358///
359/// println!("{}", instr);
360///
361/// let encoding = instr.encode();
362///
363/// println!("{:#4x}", encoding);
364/// ```
365#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct Instruction {
367    opcode: OpCode,
368    cdcode: CondCode,
369    update: bool,
370    args: Vec<Argument>,
371}
372
373impl Instruction {
374    /// Checks if the instruction can be executed in the given mode.
375    pub fn executable(&self, mode: Mode) -> bool {
376        if mode != Mode::User {
377            return true;
378        }
379
380        for arg in &self.args {
381            use Argument::*;
382
383            match arg {
384                Reg(Register::IP) | Reg(Register::SP) | Reg(Register::R) | Reg(Register::S) => {
385                    return false;
386                }
387
388                _ => {}
389            }
390        }
391
392        true
393    }
394}
395
396fn sign_extend4(value: u16) -> isize {
397    if (value & 0b1000) != 0 {
398        (value & 0b111) as isize - 8
399    } else {
400        value as isize
401    }
402}
403
404fn sign_extend8(value: u16) -> isize {
405    if (value & 0b10000000) != 0 {
406        (value & 0b1111111) as isize - 128
407    } else {
408        value as isize
409    }
410}
411
412impl cfd16_lib_impl::Codable for Instruction {
413    fn encode(&self) -> u16 {
414        use OpCode::*;
415
416        let output = self.opcode.encode() << 11;
417
418        output
419            ^ match self.opcode {
420                Add | And | Ashr | Cmp | Ldb | Ldr | Movr | Mul | Or | Ror | Shl | Shr | Stb
421                | Str | Sub | Uadd | Ucmp | Umul | Usub | Xor | Mfhi | Not | Jsr => {
422                    let mut output =
423                        ((self.args[0].encode() & 0xff) << 8) ^ (self.cdcode.encode() << 6);
424
425                    if self.update {
426                        output ^= 0b10000;
427                    }
428
429                    if self.args.len() > 1 {
430                        if let Argument::Imm(_) = self.args[1] {
431                            output ^= 0b100000;
432                        }
433
434                        output |= self.args[1].encode()
435                    }
436
437                    output
438                }
439
440                Pop | Push | Seg => {
441                    let mut output = (self.cdcode.encode() << 9) | (self.args[0].encode() & 0xff);
442
443                    match self.args[0] {
444                        Argument::Reg(Register::IP)
445                        | Argument::Reg(Register::SP)
446                        | Argument::Reg(Register::R)
447                        | Argument::Reg(Register::S) => output |= 0b1000,
448
449                        _ => {}
450                    }
451
452                    if let Argument::Imm(_) = self.args[0] {
453                        output ^= 0b100000000;
454                    }
455
456                    output
457                }
458
459                Mov | Movt => (self.args[0].encode() << 8) | (self.args[1].encode() & 0xff),
460
461                Ret => 0,
462
463                Br | Sc => (self.cdcode.encode() << 8) | (self.args[0].encode() & 0xff),
464
465                _RESERVED => unreachable!(),
466            }
467    }
468
469    fn decode(value: u16, mode: Mode) -> Option<Instruction> {
470        use OpCode::*;
471
472        let opcode = OpCode::decode(value >> 11, mode)?;
473        let cdcode: CondCode;
474        let mut update = false;
475        let mut args = vec![];
476
477        match opcode {
478            Add | And | Ashr | Cmp | Ldb | Ldr | Movr | Mul | Or | Ror | Shl | Shr | Stb | Str
479            | Sub | Uadd | Ucmp | Umul | Usub | Xor | Mfhi => {
480                cdcode = CondCode::decode((value >> 6) & 0b11, mode)?;
481                if ((value >> 4) & 0b1) == 1 {
482                    update = true;
483                }
484
485                args.push(Argument::Reg(Register::decode((value >> 8) & 0b111, mode)?));
486
487                if ((value >> 5) & 0b1) == 1 {
488                    args.push(Argument::Imm(sign_extend4(value & 0b1111)));
489                } else {
490                    args.push(Argument::Reg(Register::decode(value & 0b111, mode)?));
491                }
492            }
493
494            Not | Jsr => {
495                cdcode = CondCode::decode((value >> 6) & 0b11, mode)?;
496                if ((value >> 4) & 0b1) == 1 {
497                    update = true;
498                }
499
500                args.push(Argument::Reg(Register::decode((value >> 8) & 0b111, mode)?));
501            }
502
503            Pop | Push | Seg => {
504                cdcode = CondCode::decode((value >> 9) & 0b11, mode)?;
505                if ((value >> 8) & 0b1) == 1 {
506                    args.push(Argument::Imm(sign_extend8(value & 0b11111111)));
507                } else if ((value >> 3) & 0b1) == 1 {
508                    args.push(Argument::Reg(Register::decode(
509                        value & 0b111,
510                        Mode::Kernel,
511                    )?));
512                } else {
513                    args.push(Argument::Reg(Register::decode(value & 0b111, Mode::User)?));
514                }
515            }
516
517            Mov | Movt => {
518                cdcode = CondCode::Always;
519
520                args.push(Argument::Reg(Register::decode((value >> 8) & 0b111, mode)?));
521                args.push(Argument::Imm(sign_extend8(value & 0xff)))
522            }
523
524            _RESERVED | Ret => {
525                cdcode = CondCode::decode((value >> 8) & 0b111, mode)?;
526            }
527
528            Br | Sc => {
529                cdcode = CondCode::decode((value >> 8) & 0b111, mode)?;
530
531                args.push(Argument::Imm(sign_extend8(value & 0xff)));
532            }
533        }
534
535        Some(Instruction {
536            opcode,
537            cdcode,
538            update,
539            args,
540        })
541    }
542}
543
544impl default::Default for Instruction {
545    fn default() -> Self {
546        InstructionBuilder::default().build().unwrap()
547    }
548}
549
550impl fmt::Display for Instruction {
551    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
552        use CondCode::*;
553        use OpCode::*;
554
555        let mut output = match self.opcode {
556            Add => "add",
557            And => "and",
558            Ashr => "ashr",
559            Br => "br",
560            Cmp => "cmp",
561            Jsr => "jsr",
562            Ldb => "ldb",
563            Ldr => "ldr",
564            Mfhi => "mfhi",
565            Mov => "mov",
566            Movr => "movr",
567            Movt => "movt",
568            Mul => "mul",
569            Not => "not",
570            Or => "or",
571            Pop => "pop",
572            Push => "push",
573            Ret => "ret",
574            Ror => "ror",
575            Sc => "sc",
576            Seg => "seg",
577            Shl => "shl",
578            Shr => "shr",
579            Stb => "stb",
580            Str => "str",
581            Sub => "sub",
582            Uadd => "uadd",
583            Ucmp => "ucmp",
584            Umul => "umul",
585            Usub => "usub",
586            Xor => "xor",
587            _RESERVED => unreachable!(),
588        }
589        .into();
590
591        if self.update {
592            output = format!("{}s", output);
593        }
594
595        output = format!(
596            "{output}{}",
597            match self.cdcode {
598                Always => "",
599                Zero => "z",
600                NotZero => "nz",
601                Carry => "c",
602                Greater => "gt",
603                GreaterEq => "ge",
604                Lesser => "lt",
605                LesserEq => "le",
606            }
607        );
608
609        if self.args.len() == 1 {
610            output = format!("{output} {}", self.args[0]);
611        } else {
612            for arg in &self.args {
613                output = format!("{output} {arg},");
614            }
615        }
616
617        if self.args.len() > 1 {
618            output.pop();
619        }
620
621        write!(f, "{output}")
622    }
623}
624
625#[derive(Debug, Clone, Copy, PartialEq, Eq)]
626/// An Error type which reports unsuccessful attempts at parsing an
627/// [Instruction].
628pub enum InstructionError {
629    /// Used when too many or too little arguments are provided to an
630    /// instruction.
631    WrongNumArgs,
632
633    /// Used when either an integer couldn't be parsed where it was expected,
634    /// or when it is too large for a given instruction encoding type.
635    ImproperInteger,
636
637    /// Used when the condition code doesn't match the encoding type.
638    InvalidCondCodeForInstr,
639
640    /// Used when the instruction cannot take an s-bit.
641    CannotTakeSBit,
642
643    /// Used when an argument of the wrong kind is provided to an
644    /// instrution.
645    WrongKindArgs,
646}
647
648impl Error for InstructionError {}
649
650impl fmt::Display for InstructionError {
651    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
652        write!(
653            f,
654            "{}",
655            match self {
656                Self::WrongNumArgs => "Wrong number of arguments provided.",
657                Self::ImproperInteger => "Could not parse argument as integer.",
658                Self::InvalidCondCodeForInstr => "Condition code is invalid on this instruction.",
659                Self::CannotTakeSBit => "Cannot take s-bit.",
660                Self::WrongKindArgs => "Wrong kind of argument provided.",
661            }
662        )
663    }
664}
665
666/// A mnemonic and associated binary value for encoding an [Instruction].
667/// These are divided into four broad categories depending on the way
668/// they are encoded: Type C, Type S, Type I, Type J. These encoding
669/// patterns are described below. Additional documentation on the
670/// instructions associated with each opcode is provided on each variant.
671///
672/// Type-C Encoding: `0bMMMMMDDD-CCISOOOO`
673///
674/// Type-S Encoding: `0bMMMMMCCI-OOOOOOOO`
675///
676/// Type-I Encoding: `0bMMMMMDDD-IIIIIIII`
677///
678/// Type-J Encoding: `0bMMMMMCCC-IIIIIIII`
679#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, cfd16_lib_derive::Codable)]
680pub enum OpCode {
681    /// Adds the value in op8 into the register, interpreting
682    /// both as signed quantities.
683    ///
684    /// ```txt
685    /// (Type-C Encoding)
686    ///   ADD[S][C] <reg>, <op8>
687    /// ```
688    #[encode(0)]
689    Add,
690
691    /// Preforms a bit-wise and operation onto the value in the
692    /// register.
693    ///
694    /// ```txt
695    /// (Type-C Encoding)
696    ///   AND[S][C] <reg>, <uop8>
697    /// ```
698    #[encode(1)]
699    And,
700
701    /// Shifts the value in the register by the value in _op8_,
702    /// while preserving the sign bit.
703    ///
704    /// ```txt
705    /// (Type-C Encoding)
706    ///   ASHR[S][C] <reg>, <uop8>
707    /// ```
708    ///
709    #[encode(2)]
710    Ashr,
711
712    /// Branches to an offset of the current
713    /// [%ip](Register::IP). Takes extended condition
714    /// codes ([ge](CondCode::GreaterEq),
715    /// [gt](CondCode::Greater), [le](CondCode::Lesser),
716    /// [lt](CondCode::LesserEq)).
717    ///
718    /// ```txt
719    /// (Type-J Encoding)
720    ///   BR[CC] <imm8>
721    /// ```
722    #[encode(3)]
723    Br,
724
725    /// Compares two values as signed integers and sets
726    /// corresponding bits in [%s](Register::S).
727    ///
728    /// ```txt
729    /// (Type-C Encoding)
730    ///   CMP[C] <reg>, <op8>
731    /// ```
732    #[encode(4)]
733    Cmp,
734
735    /// Changes the value of the instruction pointer to a
736    /// value stored in one of the general-purpose registers.
737    ///
738    /// ```txt
739    /// (Type-C Encoding)
740    ///   JSR[C] <reg>
741    /// ```
742    #[encode(5)]
743    Jsr,
744
745    /// Loads a byte into _regd_ from address in memory
746    /// specified by _regs_. Fills the upper byte with zeroes
747    /// when loading the value into the register.
748    ///
749    /// ```txt
750    /// (Type-C Encoding)
751    ///   LDB[S][C] <regd>, (<regs>)
752    /// ```
753    #[encode(6)]
754    Ldb,
755
756    /// Loads a word (2 bytes) from memory into _regd_ from
757    /// an address specified in _regs_.
758    ///
759    /// ```txt
760    /// (Type-C Encoding)
761    ///   LDR[S][C] <regd>, (<regs>)
762    /// ```
763    #[encode(7)]
764    Ldr,
765
766    /// Moves the value in the %hi register resulting from
767    /// a multiplication into _reg_.
768    ///
769    /// ```txt
770    /// (Type-C Encoding)
771    ///   MFHI[S][C] <reg>
772    /// ```
773    #[encode(8)]
774    Mfhi,
775
776    /// Moves an immediate value into the lower byte of
777    /// _reg_, padding the upper byte with zeroes.
778    ///
779    /// ```txt
780    /// (Type-I Encoding)
781    ///   MOV <reg>, <uimm8>
782    /// ```
783    #[encode(9)]
784    Mov,
785
786    /// Moves the value of _regs_ into _regd_.
787    ///
788    /// ```txt
789    /// (Type-C Encoding)
790    ///   MOVR[S][C] <regd>, <regs>
791    /// ```
792    #[encode(10)]
793    Movr,
794
795    /// Moves an immediate value into the upper byte of
796    /// _reg_, doesn't affect the lower byte.
797    ///
798    /// ```txt
799    /// (Type-I Encoding)
800    ///   MOVT <reg>, <uimm8>
801    /// ```
802    #[encode(11)]
803    Movt,
804
805    /// Multiplies two signed numbers, storing the lower word
806    /// of the result in _reg_, while the rest goes in a special
807    /// register %hi. Use [mfhi](OpCode::Mfhi) to retrieve the
808    /// value.
809    ///
810    /// ```txt
811    /// (Type-C Encoding)
812    ///   MUL[S][C] <reg>, <op4>
813    /// ```
814    #[encode(12)]
815    Mul,
816
817    /// Performs a bit-wise not operation on the value in _reg_.
818    ///
819    /// ```txt
820    /// (Type-C Encoding)
821    ///   NOT[S][C] <reg>
822    /// ```
823    #[encode(13)]
824    Not,
825
826    /// Performs a bit-wise or operation on between the values in
827    /// _reg_ and _uop8_, storing the result in _reg_.
828    ///
829    /// ```txt
830    /// (Type-C Encoding)
831    ///   OR[S][C] <reg>, <uop8>
832    /// ```
833    #[encode(14)]
834    Or,
835
836    /// Pops a value off the stack, and stores it in _reg_. Due to the
837    /// encoding type, it is possible to pop [%r](Register::R) off of
838    /// the stack.
839    ///
840    /// ```txt
841    /// (Type-S Encoding)
842    ///   POP[C] <reg>
843    /// ```
844    #[encode(15)]
845    Pop,
846
847    /// Pushes the value of _uop16_ onto the stack. If this value is a
848    /// register, then even in user mode, [%r](Register::R) can be
849    /// pushed onto the stack.
850    ///
851    /// ```txt
852    /// (Type-S Encoding)
853    ///   PUSH[C] <uop16>
854    /// ```
855    #[encode(16)]
856    Push,
857
858    /// Moves the value in [%r](Register::R) into the instruction
859    /// pointer, effectively returning back from a subroutine.
860    ///
861    /// ```txt
862    /// (Type-J Encoding)
863    ///   RET[CC]
864    /// ```
865    #[encode(17)]
866    Ret,
867
868    /// Shifts the bits of _reg_ by the value of _uop8_, placing the
869    /// shifted out bit in the new most significant bit.
870    ///
871    /// ```txt
872    /// (Type-C Encoding)
873    ///   ROR[S][C] <reg> <uop8>
874    /// ```
875    #[encode(18)]
876    Ror,
877
878    /// Initiates a system call indexed at _uimm8_ in the interrupt jump
879    /// table, switching the mode to supervisor.
880    ///
881    /// ```txt
882    /// (Type-J Encoding)
883    ///   SC[CC] <uimm8>
884    /// ```
885    #[encode(19)]
886    Sc,
887
888    /// Changes the segment portion of the status register to the value
889    /// contained in _uop16_, allowing a different part segment in the
890    /// memory space to be accessed for data storage, inter-process
891    /// communication, etc...
892    ///
893    /// ```txt
894    /// (Type-S Encoding)
895    ///   SEG[C] <uop16>
896    /// ```
897    #[encode(20)]
898    Seg,
899
900    /// Shifts the value contained in _reg_ to the left by _uop8_.
901    ///
902    /// ```txt
903    /// (Type-C Encoding)
904    ///   SHL[S][C] <reg>, <uop8>
905    /// ```
906    #[encode(21)]
907    Shl,
908
909    /// Shifts the value contained in _reg_ to the right by _uop8_.
910    ///
911    /// ```txt
912    /// (Type-C Encoding)
913    ///   SHR[S][C] <reg>, <uop8>
914    /// ```
915    #[encode(22)]
916    Shr,
917
918    /// Stores the lower byte of the value in _regs_ to the address in
919    /// memory contained in _regd_, with the segment corresponding to the
920    /// value in the [status register](Register::S).
921    ///
922    /// ```txt
923    /// (Type-C Encoding)
924    ///   STB[C] <regs>, (<regd>)
925    /// ```
926    #[encode(23)]
927    Stb,
928
929    /// Stores the value in _regs_ to the address in memory contained in
930    /// _regd_, with the segment corresponding to the value in the [status
931    /// register](Register::S).
932    ///
933    /// ```txt
934    /// (Type-C Encoding)
935    ///   STR[C] <regs>, (<regd>)
936    /// ```
937    #[encode(24)]
938    Str,
939
940    /// Subtracts the value of the _op8_ from the value in _reg_.
941    ///
942    /// ```txt
943    /// (Type-C Encoding)
944    ///   SUB[S][C] <reg>, <op8>
945    /// ```
946    #[encode(25)]
947    Sub,
948
949    /// Adds the value of _uop8_ to the value in _reg_, treating
950    /// both as unsigned values.
951    ///
952    /// ```txt
953    /// (Type-C Encoding)
954    ///   UADD[S][C] <reg>, <uop8>
955    /// ```
956    #[encode(26)]
957    Uadd,
958
959    /// Compares the value in _reg_ to the value in _uop8_, treating
960    /// both as unsigned values.
961    ///
962    /// ```txt
963    /// (Type-C Encoding)
964    ///   UCMP[C] <reg>, <uop8>
965    /// ```
966    #[encode(27)]
967    Ucmp,
968
969    /// Multiplies the value in _reg_ with _uop8_, treating both as
970    /// unsigned values.
971    ///
972    /// ```txt
973    /// (Type-C Encoding)
974    ///   UMUL[S][C] <reg>, <uop8>
975    /// ```
976    #[encode(28)]
977    Umul,
978
979    /// Subtracts the value of _uop8_ from the value in _reg_, treating
980    /// both as unsigned values.
981    ///
982    /// ```txt
983    /// (Type-C Encoding)
984    ///   USUB[S][C] <reg>, <uop8>
985    /// ```
986    #[encode(29)]
987    Usub,
988
989    /// Performs a bit-wise xor between the value in _reg_ and _uop8_.
990    ///
991    /// ```txt
992    /// (Type-C Encoding)
993    ///   XOR[S][C] <reg>, <uop8>
994    /// ```
995    #[encode(30)]
996    Xor,
997
998    #[doc(hidden)]
999    #[encode(31)]
1000    _RESERVED,
1001}
1002
1003#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, cfd16_lib_derive::Codable)]
1004/// The condition code potentially associated to a given instruction.
1005/// Any instruction may either contain no condition code (Type-I Encoding)
1006/// contain a limited condition code (Type-C Encoding) or an extended
1007/// condition code (Type-J Encoding).
1008pub enum CondCode {
1009    /// Indicates that the instruction should always be executed.
1010    #[encode(0)]
1011    Always,
1012
1013    /// Indicates that the instruction should only be executed if
1014    /// the [zero bit](Register::S) is set.
1015    #[encode(1)]
1016    Zero,
1017
1018    /// Indicates that the instruction should only be executed if
1019    /// the [zero bit](Register::S) is cleared.
1020    #[encode(2)]
1021    NotZero,
1022
1023    /// Indicates that the instruction should only be executed if
1024    /// the [carry bit](Register::S) is set.
1025    #[encode(3)]
1026    Carry,
1027
1028    /// Indicates that the instruction should only be executed if
1029    /// both the [negative bit](Register::S) is clear, and the
1030    /// [zero bit](Register::S) is clear.
1031    #[encode(4)]
1032    Greater,
1033
1034    /// Indicates that the instruction should only be executed if
1035    /// the [negative bit](Register::S) is clear.
1036    #[encode(5)]
1037    GreaterEq,
1038
1039    /// Indicates that the instruction should only be executed if
1040    /// the [negative bit](Register::S) is set.
1041    #[encode(6)]
1042    Lesser,
1043
1044    /// Indicates that the instruction should only be executed if
1045    /// the [negative bit](Register::S) is set, or if the
1046    /// [zero bit](Register::S) is set.
1047    #[encode(7)]
1048    LesserEq,
1049}
1050
1051impl default::Default for CondCode {
1052    fn default() -> Self {
1053        Self::Always
1054    }
1055}
1056
1057#[derive(Debug, Clone, PartialEq, Eq)]
1058/// A high-level representation for an argument given to an instruction.
1059/// The [Argument::Imm] variant may represent any of the following
1060/// concrete arguments: _uimm4_, _imm4_, _uimm8_, _imm8_. An _op2_ or
1061/// _uop2_ is considered to be either a register or a _imm4_, _uimm4_
1062/// respectively.
1063#[allow(missing_docs)]
1064pub enum Argument {
1065    Imm(isize),
1066    Reg(Register),
1067    Label(String),
1068}
1069
1070impl Codable for Argument {
1071    fn encode(&self) -> u16 {
1072        use Argument::*;
1073
1074        match self {
1075            Imm(i) => *i as u16,
1076            Reg(r) => r.encode(),
1077            Label(_) => unreachable!(),
1078        }
1079    }
1080
1081    // This function should never be called.
1082    fn decode(value: u16, mode: Mode) -> Option<Self> {
1083        let _ = value;
1084        let _ = mode;
1085
1086        unreachable!();
1087    }
1088}
1089
1090impl Argument {
1091    /// Applies an arithmetic manipulation to an argument if it is
1092    /// an immediate.
1093    pub fn apply<F: FnOnce(&mut isize)>(&mut self, f: F) {
1094        use Argument::*;
1095
1096        match self {
1097            Imm(i) => f(i),
1098            _ => {}
1099        }
1100    }
1101}
1102
1103/// A register in the CFD-16 Instruction Set Architecture, eight of which
1104/// are general-purpose ([%a](Register::A), [%b](Register::B),
1105/// [%c](Register::C), [%d](Register::D), [%e](Register::E),
1106/// [%f](Register::F), [%g](Register::G), [%h](Register::H)), and
1107/// four of which are system registers which cannot be accessed by user
1108/// processes, as they are shadowed over in [user mode](Register::S). (
1109/// [%ip](Register::IP), [%sp](Register::SP), [%r](Register::R),
1110/// [%s](Register::S))
1111#[allow(missing_docs)]
1112#[derive(Debug, Clone, Copy, PartialEq, Eq, cfd16_lib_derive::Codable)]
1113pub enum Register {
1114    /// General-purpose register. Available in user and kernel mode.
1115    #[encode(0)]
1116    A,
1117
1118    /// General-purpose register. Available in user and kernel mode.
1119    #[encode(1)]
1120    B,
1121
1122    /// General-purpose register. Available in user and kernel mode.
1123    #[encode(2)]
1124    C,
1125
1126    /// General-purpose register. Available in user and kernel mode.
1127    #[encode(3)]
1128    D,
1129
1130    /// This register contains the instruction pointer, i.e. the address
1131    /// (plus 4 bytes due to pipelining) at which the current instruction
1132    /// resides. The branch and jump instructions ([br](OpCode::Br)
1133    /// [jsr](OpCode::Jsr) [ret](OpCode::Ret) are the only way to modify
1134    /// this value when in userspace. This is the only register which is
1135    /// in actuality 24-bit wide to match the size of the ISA's address
1136    /// space.
1137    #[kencode(4)]
1138    IP,
1139
1140    /// This register contains the stack pointer, i.e. the address in memory
1141    /// where the top of the stack is currently located. The instructions
1142    /// [push](OpCode::Push) and [pop](OpCode::Pop) modify this value when in
1143    /// userspace.
1144    #[kencode(5)]
1145    SP,
1146
1147    /// This register contains the return address of the last-called function
1148    /// call (through the instruction [jsr](OpCode::Jsr)) and is used by the
1149    /// [ret](OpCode::Ret) instruction.
1150    #[kencode(6)]
1151    R,
1152
1153    /// This register contains the status register which is encoded as follows.
1154    /// `0bNZCMPPPP-SSSSSSSS`, where `N` is the negative bit, (when the result
1155    /// of the ALU calculation is negative) `Z` is the zero bit, (when the
1156    /// result of the ALU calculation is zero), `C` is the carry bit, (when
1157    /// the ALU carries or overflows in a given integer calculation), `M` is
1158    /// the mode bit, which indicates whether the current process is in user
1159    /// mode (0) or kernel mode. (1) `P`s designate the current process id,
1160    /// which is important for controlling access to segments of memory, and
1161    /// `S` designates the currently accessed segment in memory.
1162    #[kencode(7)]
1163    S,
1164
1165    /// General-purpose register. Available only in user mode.
1166    #[uencode(4)]
1167    E,
1168
1169    /// General-purpose register. Available only in user mode.
1170    #[uencode(5)]
1171    F,
1172
1173    /// General-purpose register. Available only in user mode.
1174    #[uencode(6)]
1175    G,
1176
1177    /// General-purpose register. Available only in user mode.
1178    #[uencode(7)]
1179    H,
1180}
1181
1182impl fmt::Display for Argument {
1183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1184        match self {
1185            Argument::Imm(i) => write!(f, "{i}"),
1186            Argument::Reg(Register::A) => write!(f, "%a"),
1187            Argument::Reg(Register::B) => write!(f, "%b"),
1188            Argument::Reg(Register::C) => write!(f, "%c"),
1189            Argument::Reg(Register::D) => write!(f, "%d"),
1190            Argument::Reg(Register::E) => write!(f, "%e"),
1191            Argument::Reg(Register::F) => write!(f, "%f"),
1192            Argument::Reg(Register::G) => write!(f, "%g"),
1193            Argument::Reg(Register::H) => write!(f, "%h"),
1194            Argument::Reg(Register::IP) => write!(f, "%ip"),
1195            Argument::Reg(Register::SP) => write!(f, "%sp"),
1196            Argument::Reg(Register::R) => write!(f, "%r"),
1197            Argument::Reg(Register::S) => write!(f, "%s"),
1198            Argument::Label(s) => write!(f, "{s}"),
1199        }
1200    }
1201}