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::A))
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::B))
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::A))
317/// .argument(Argument::Reg(Register::B))
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::IP)
384 | Argument::Reg(Register::SP)
385 | Argument::Reg(Register::R)
386 | Argument::Reg(Register::S) => 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::IP). 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::S).
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::R) 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::R) 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::R) 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::S).
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::S).
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::S) is set.
954 #[encode(1)]
955 Zero,
956
957 /// Indicates that the instruction should only be executed if
958 /// the [zero bit](Register::S) is cleared.
959 #[encode(2)]
960 NotZero,
961
962 /// Indicates that the instruction should only be executed if
963 /// the [carry bit](Register::S) is set.
964 #[encode(3)]
965 Carry,
966
967 /// Indicates that the instruction should only be executed if
968 /// both the [negative bit](Register::S) is clear, and the
969 /// [zero bit](Register::S) is clear.
970 #[encode(4)]
971 Greater,
972
973 /// Indicates that the instruction should only be executed if
974 /// the [negative bit](Register::S) is clear.
975 #[encode(5)]
976 GreaterEq,
977
978 /// Indicates that the instruction should only be executed if
979 /// the [negative bit](Register::S) is set.
980 #[encode(6)]
981 Lesser,
982
983 /// Indicates that the instruction should only be executed if
984 /// the [negative bit](Register::S) is set, or if the
985 /// [zero bit](Register::S) 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, 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 Label(String),
1007}
1008
1009impl Codable for Argument {
1010 fn encode(&self) -> u16 {
1011 use Argument::*;
1012
1013 match self {
1014 Imm(i) => *i as u16,
1015 Reg(r) => r.encode(),
1016 Label(_) => unreachable!(),
1017 }
1018 }
1019
1020 // This function should never be called.
1021 fn decode(value: u16, mode: Mode) -> Option<Self> {
1022 let _ = value;
1023 let _ = mode;
1024
1025 unreachable!();
1026 }
1027}
1028
1029/// A register in the CFD-16 Instruction Set Architecture, eight of which
1030/// are general-purpose ([%a](Register::A), [%b](Register::B),
1031/// [%c](Register::C), [%d](Register::D), [%e](Register::E),
1032/// [%f](Register::F), [%g](Register::G), [%h](Register::H)), and
1033/// four of which are system registers which cannot be accessed by user
1034/// processes, as they are shadowed over in [user mode](Register::S). (
1035/// [%ip](Register::IP), [%sp](Register::SP), [%r](Register::R),
1036/// [%s](Register::S))
1037#[allow(missing_docs)]
1038#[derive(Debug, Clone, Copy, PartialEq, Eq, cfd16_lib_derive::Codable)]
1039pub enum Register {
1040 /// General-purpose register. Available in user and kernel mode.
1041 #[encode(0)]
1042 A,
1043
1044 /// General-purpose register. Available in user and kernel mode.
1045 #[encode(1)]
1046 B,
1047
1048 /// General-purpose register. Available in user and kernel mode.
1049 #[encode(2)]
1050 C,
1051
1052 /// General-purpose register. Available in user and kernel mode.
1053 #[encode(3)]
1054 D,
1055
1056 /// This register contains the instruction pointer, i.e. the address
1057 /// (plus 4 bytes due to pipelining) at which the current instruction
1058 /// resides. The branch and jump instructions ([br](OpCode::Br)
1059 /// [jsr](OpCode::Jsr) [ret](OpCode::Ret) are the only way to modify
1060 /// this value when in userspace. This is the only register which is
1061 /// in actuality 24-bit wide to match the size of the ISA's address
1062 /// space.
1063 #[kencode(4)]
1064 IP,
1065
1066 /// This register contains the stack pointer, i.e. the address in memory
1067 /// where the top of the stack is currently located. The instructions
1068 /// [push](OpCode::Push) and [pop](OpCode::Pop) modify this value when in
1069 /// userspace.
1070 #[kencode(5)]
1071 SP,
1072
1073 /// This register contains the return address of the last-called function
1074 /// call (through the instruction [jsr](OpCode::Jsr)) and is used by the
1075 /// [ret](OpCode::Ret) instruction.
1076 #[kencode(6)]
1077 R,
1078
1079 /// This register contains the status register which is encoded as follows.
1080 /// `0bNZCMPPPP-SSSSSSSS`, where `N` is the negative bit, (when the result
1081 /// of the ALU calculation is negative) `Z` is the zero bit, (when the
1082 /// result of the ALU calculation is zero), `C` is the carry bit, (when
1083 /// the ALU carries or overflows in a given integer calculation), `M` is
1084 /// the mode bit, which indicates whether the current process is in user
1085 /// mode (0) or kernel mode. (1) `P`s designate the current process id,
1086 /// which is important for controlling access to segments of memory, and
1087 /// `S` designates the currently accessed segment in memory.
1088 #[kencode(7)]
1089 S,
1090
1091 /// General-purpose register. Available only in user mode.
1092 #[uencode(4)]
1093 E,
1094
1095 /// General-purpose register. Available only in user mode.
1096 #[uencode(5)]
1097 F,
1098
1099 /// General-purpose register. Available only in user mode.
1100 #[uencode(6)]
1101 G,
1102
1103 /// General-purpose register. Available only in user mode.
1104 #[uencode(7)]
1105 H,
1106}
1107
1108impl fmt::Display for Argument {
1109 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1110 match self {
1111 Argument::Imm(i) => write!(f, "{i}"),
1112 Argument::Reg(Register::A) => write!(f, "%a"),
1113 Argument::Reg(Register::B) => write!(f, "%b"),
1114 Argument::Reg(Register::C) => write!(f, "%c"),
1115 Argument::Reg(Register::D) => write!(f, "%d"),
1116 Argument::Reg(Register::E) => write!(f, "%e"),
1117 Argument::Reg(Register::F) => write!(f, "%f"),
1118 Argument::Reg(Register::G) => write!(f, "%g"),
1119 Argument::Reg(Register::H) => write!(f, "%h"),
1120 Argument::Reg(Register::IP) => write!(f, "%ip"),
1121 Argument::Reg(Register::SP) => write!(f, "%sp"),
1122 Argument::Reg(Register::R) => write!(f, "%r"),
1123 Argument::Reg(Register::S) => write!(f, "%s"),
1124 Argument::Label(s) => write!(f, "{s}"),
1125 }
1126 }
1127}