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