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}