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