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