1pub mod decode;
5pub mod encode;
6
7pub const PERIPH_BASE: u32 = 0xFFFF80;
9pub const PERIPH_SIZE: usize = 128;
10pub const PC_MASK: u32 = 0xFFFFFF;
11
12#[inline(always)]
14pub const fn mask_pc(v: u32) -> u32 {
15 v & PC_MASK
16}
17
18pub mod reg {
20 pub const X0: usize = 0x04;
21 pub const X1: usize = 0x05;
22 pub const Y0: usize = 0x06;
23 pub const Y1: usize = 0x07;
24 pub const A0: usize = 0x08;
25 pub const B0: usize = 0x09;
26 pub const A2: usize = 0x0a;
27 pub const B2: usize = 0x0b;
28 pub const A1: usize = 0x0c;
29 pub const B1: usize = 0x0d;
30 pub const A: usize = 0x0e;
31 pub const B: usize = 0x0f;
32
33 pub const R0: usize = 0x10;
34 pub const R1: usize = 0x11;
35 pub const R2: usize = 0x12;
36 pub const R3: usize = 0x13;
37 pub const R4: usize = 0x14;
38 pub const R5: usize = 0x15;
39 pub const R6: usize = 0x16;
40 pub const R7: usize = 0x17;
41
42 pub const N0: usize = 0x18;
43 pub const N1: usize = 0x19;
44 pub const N2: usize = 0x1a;
45 pub const N3: usize = 0x1b;
46 pub const N4: usize = 0x1c;
47 pub const N5: usize = 0x1d;
48 pub const N6: usize = 0x1e;
49 pub const N7: usize = 0x1f;
50
51 pub const M0: usize = 0x20;
52 pub const M1: usize = 0x21;
53 pub const M2: usize = 0x22;
54 pub const M3: usize = 0x23;
55 pub const M4: usize = 0x24;
56 pub const M5: usize = 0x25;
57 pub const M6: usize = 0x26;
58 pub const M7: usize = 0x27;
59
60 pub const EP: usize = 0x2a;
61
62 pub const VBA: usize = 0x30;
63 pub const SC: usize = 0x31;
64
65 pub const SZ: usize = 0x38;
66 pub const SR: usize = 0x39;
67 pub const OMR: usize = 0x3a;
68 pub const SP: usize = 0x3b;
69 pub const SSH: usize = 0x3c;
70 pub const SSL: usize = 0x3d;
71 pub const LA: usize = 0x3e;
72 pub const LC: usize = 0x3f;
73
74 pub const NULL: usize = 0x00;
75 pub const TEMP: usize = 0x2b;
78
79 pub const COUNT: usize = 0x40;
80}
81
82pub fn qq_reg(qq: u8) -> usize {
84 match qq {
85 0 => reg::X0,
86 1 => reg::Y0,
87 2 => reg::X1,
88 3 => reg::Y1,
89 _ => unreachable!(),
90 }
91}
92
93pub fn qq_reg_mulshift(qq: u8) -> usize {
96 match qq {
97 0 => reg::Y1,
98 1 => reg::X0,
99 2 => reg::Y0,
100 3 => reg::X1,
101 _ => unreachable!(),
102 }
103}
104
105pub fn qqqq_regs(qqqq: u8) -> Option<(usize, usize)> {
109 match qqqq {
110 0x0 => Some((reg::X0, reg::X0)),
111 0x1 => Some((reg::Y0, reg::Y0)),
112 0x2 => Some((reg::X1, reg::X0)),
113 0x3 => Some((reg::Y1, reg::Y0)),
114 0x4 => Some((reg::X0, reg::Y1)),
115 0x5 => Some((reg::Y0, reg::X0)),
116 0x6 => Some((reg::X1, reg::Y0)),
117 0x7 => Some((reg::Y1, reg::X1)),
118 0x8 => Some((reg::X1, reg::X1)),
119 0x9 => Some((reg::Y1, reg::Y1)),
120 0xA => Some((reg::X0, reg::X1)),
121 0xB => Some((reg::Y0, reg::Y1)),
122 0xC => Some((reg::Y1, reg::X0)),
123 0xD => Some((reg::X0, reg::Y0)),
124 0xE => Some((reg::Y0, reg::X1)),
125 0xF => Some((reg::X1, reg::Y1)),
126 _ => None,
127 }
128}
129
130pub fn sss_reg(sss: u8) -> Option<usize> {
132 match sss {
133 2 => Some(reg::A1),
134 3 => Some(reg::B1),
135 4 => Some(reg::X0),
136 5 => Some(reg::Y0),
137 6 => Some(reg::X1),
138 7 => Some(reg::Y1),
139 _ => None,
140 }
141}
142
143pub fn qqq_reg(qqq: u8) -> Option<usize> {
146 match qqq {
147 2 => Some(reg::A0),
148 3 => Some(reg::B0),
149 4 => Some(reg::X0),
150 5 => Some(reg::Y0),
151 6 => Some(reg::X1),
152 7 => Some(reg::Y1),
153 _ => None,
154 }
155}
156
157pub fn ggg_reg(ggg: u8, d: Accumulator) -> Option<usize> {
160 match ggg {
161 0 => Some(match d {
162 Accumulator::A => reg::B,
163 Accumulator::B => reg::A,
164 }),
165 4 => Some(reg::X0),
166 5 => Some(reg::Y0),
167 6 => Some(reg::X1),
168 7 => Some(reg::Y1),
169 _ => None,
170 }
171}
172
173pub mod sr {
175 pub const C: u32 = 0;
176 pub const V: u32 = 1;
177 pub const Z: u32 = 2;
178 pub const N: u32 = 3;
179 pub const U: u32 = 4;
180 pub const E: u32 = 5;
181 pub const L: u32 = 6;
182 pub const S: u32 = 7;
183 pub const I0: u32 = 8;
184 pub const I1: u32 = 9;
185 pub const S0: u32 = 10;
186 pub const S1: u32 = 11;
187 pub const SC: u32 = 13;
188 pub const DM: u32 = 14;
189 pub const LF: u32 = 15;
190 pub const FV: u32 = 16;
191 pub const SA: u32 = 17;
192 pub const CE: u32 = 19;
193 pub const SM: u32 = 20;
194 pub const RM: u32 = 21;
195}
196
197pub const REG_MASKS: [u32; reg::COUNT] = {
203 let mut m = [0xFFFF_FFFFu32; reg::COUNT];
204 m[reg::X0] = 0x00FF_FFFF;
205 m[reg::X1] = 0x00FF_FFFF;
206 m[reg::Y0] = 0x00FF_FFFF;
207 m[reg::Y1] = 0x00FF_FFFF;
208 m[reg::A0] = 0x00FF_FFFF;
209 m[reg::B0] = 0x00FF_FFFF;
210 m[reg::A2] = 0x0000_00FF;
211 m[reg::B2] = 0x0000_00FF;
212 m[reg::A1] = 0x00FF_FFFF;
213 m[reg::B1] = 0x00FF_FFFF;
214 m[reg::A] = 0x00FF_FFFF;
215 m[reg::B] = 0x00FF_FFFF;
216 let mut i = 0;
217 while i < 8 {
218 m[reg::R0 + i] = 0x00FF_FFFF;
219 m[reg::N0 + i] = 0x00FF_FFFF;
220 m[reg::M0 + i] = 0x00FF_FFFF;
221 i += 1;
222 }
223 m[reg::EP] = 0x00FF_FFFF; m[reg::VBA] = 0x00FF_FF00; m[reg::SC] = 0x0000_001F; m[reg::SZ] = 0x00FF_FFFF; m[reg::SR] = 0x00FB_EFFF; m[reg::OMR] = 0x00FF_FFDF; m[reg::SP] = 0x0000_003F; m[reg::SSH] = 0x00FF_FFFF;
231 m[reg::SSL] = 0x00FF_FFFF;
232 m[reg::LA] = 0x00FF_FFFF;
233 m[reg::LC] = 0x00FF_FFFF;
234 m[reg::TEMP] = 0x00FF_FFFF;
235 m[reg::NULL] = 0;
236 m
237};
238
239#[inline(always)]
241pub const fn mask_reg(r: usize, v: u32) -> u32 {
242 v & REG_MASKS[r]
243}
244
245pub const REGISTER_NAMES: [&str; 64] = [
247 "", "", "", "", "x0", "x1", "y0", "y1", "a0", "b0", "a2", "b2", "a1", "b1", "a", "b", "r0",
248 "r1", "r2", "r3", "r4", "r5", "r6", "r7", "n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "m0",
249 "m1", "m2", "m3", "m4", "m5", "m6", "m7", "", "", "ep", "", "", "", "", "", "vba", "sc", "",
250 "", "", "", "", "", "sz", "sr", "omr", "sp", "ssh", "ssl", "la", "lc",
251];
252
253pub const CC_NAMES: [&str; 16] = [
255 "cc", "ge", "ne", "pl", "nn", "ec", "lc", "gt", "cs", "lt", "eq", "mi", "nr", "es", "ls", "le",
256];
257
258pub const REGISTERS_LMOVE: [&str; 8] = ["a10", "b10", "x", "y", "a", "b", "ab", "ba"];
260
261pub const REGISTERS_TCC: [[usize; 2]; 16] = [
263 [reg::B, reg::A],
264 [reg::A, reg::B],
265 [reg::NULL, reg::NULL],
266 [reg::NULL, reg::NULL],
267 [reg::NULL, reg::NULL],
268 [reg::NULL, reg::NULL],
269 [reg::NULL, reg::NULL],
270 [reg::NULL, reg::NULL],
271 [reg::X0, reg::A],
272 [reg::X0, reg::B],
273 [reg::Y0, reg::A],
274 [reg::Y0, reg::B],
275 [reg::X1, reg::A],
276 [reg::X1, reg::B],
277 [reg::Y1, reg::A],
278 [reg::Y1, reg::B],
279];
280
281#[derive(Debug, Clone, Copy, PartialEq, Eq)]
283#[repr(u32)]
284pub enum MemSpace {
285 X = 0,
286 Y = 1,
287 P = 2,
288}
289
290impl MemSpace {
291 pub fn xy(bit: u32) -> Self {
293 match bit {
294 0 => Self::X,
295 1 => Self::Y,
296 _ => unreachable!(),
297 }
298 }
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, Eq)]
303pub enum Accumulator {
304 A = 0,
305 B = 1,
306}
307
308#[derive(Debug, Clone, Copy, PartialEq, Eq)]
310pub enum MulShiftOp {
311 Mpy = 0,
312 Mpyr = 1,
313 Mac = 2,
314 Macr = 3,
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq)]
319#[repr(u8)]
320pub enum CondCode {
321 CC = 0, GE = 1,
323 NE = 2,
324 PL = 3,
325 NN = 4,
326 EC = 5,
327 LC = 6,
328 GT = 7,
329 CS = 8, LT = 9,
331 EQ = 10,
332 MI = 11,
333 NR = 12,
334 ES = 13,
335 LS = 14,
336 LE = 15,
337}
338
339impl CondCode {
340 pub fn from_bits(bits: u32) -> Self {
341 assert!(bits < 16);
342 unsafe { std::mem::transmute(bits as u8) }
344 }
345}
346
347#[derive(Debug, Clone, Copy, PartialEq, Eq)]
353pub enum ParallelAlu {
354 Move,
356
357 TfrAcc {
359 src: Accumulator,
360 d: Accumulator,
361 },
362 Addr {
363 src: Accumulator,
364 d: Accumulator,
365 },
366 Tst {
367 d: Accumulator,
368 },
369 CmpAcc {
370 src: Accumulator,
371 d: Accumulator,
372 },
373 Subr {
374 src: Accumulator,
375 d: Accumulator,
376 },
377 CmpmAcc {
378 src: Accumulator,
379 d: Accumulator,
380 },
381
382 AddAcc {
384 src: Accumulator,
385 d: Accumulator,
386 },
387 Rnd {
388 d: Accumulator,
389 },
390 Addl {
391 src: Accumulator,
392 d: Accumulator,
393 },
394 Clr {
395 d: Accumulator,
396 },
397 SubAcc {
398 src: Accumulator,
399 d: Accumulator,
400 },
401 Max,
403 Maxm,
405 Subl {
406 src: Accumulator,
407 d: Accumulator,
408 },
409 Not {
410 d: Accumulator,
411 },
412
413 AddXY {
415 hi: usize,
416 lo: usize,
417 d: Accumulator,
418 },
419 Adc {
420 hi: usize,
421 lo: usize,
422 d: Accumulator,
423 },
424 SubXY {
425 hi: usize,
426 lo: usize,
427 d: Accumulator,
428 },
429 Sbc {
430 hi: usize,
431 lo: usize,
432 d: Accumulator,
433 },
434 Asr {
435 d: Accumulator,
436 },
437 Lsr {
438 d: Accumulator,
439 },
440 Abs {
441 d: Accumulator,
442 },
443 Ror {
444 d: Accumulator,
445 },
446 Asl {
447 d: Accumulator,
448 },
449 Lsl {
450 d: Accumulator,
451 },
452 Neg {
453 d: Accumulator,
454 },
455 Rol {
456 d: Accumulator,
457 },
458
459 AddReg {
461 src: usize,
462 d: Accumulator,
463 },
464 TfrReg {
465 src: usize,
466 d: Accumulator,
467 },
468 Or {
469 src: usize,
470 d: Accumulator,
471 },
472 Eor {
473 src: usize,
474 d: Accumulator,
475 },
476 SubReg {
477 src: usize,
478 d: Accumulator,
479 },
480 CmpReg {
481 src: usize,
482 d: Accumulator,
483 },
484 And {
485 src: usize,
486 d: Accumulator,
487 },
488 CmpmReg {
489 src: usize,
490 d: Accumulator,
491 },
492
493 Mpy {
495 negate: bool,
496 s1: usize,
497 s2: usize,
498 d: Accumulator,
499 },
500 Mpyr {
501 negate: bool,
502 s1: usize,
503 s2: usize,
504 d: Accumulator,
505 },
506 Mac {
507 negate: bool,
508 s1: usize,
509 s2: usize,
510 d: Accumulator,
511 },
512 Macr {
513 negate: bool,
514 s1: usize,
515 s2: usize,
516 d: Accumulator,
517 },
518
519 Undefined,
521}
522
523fn qqq_mpy_regs(qqq: u8) -> (usize, usize) {
526 match qqq {
527 0 => (reg::X0, reg::X0),
528 1 => (reg::Y0, reg::Y0),
529 2 => (reg::X1, reg::X0),
530 3 => (reg::Y1, reg::Y0),
531 4 => (reg::X0, reg::Y1),
532 5 => (reg::Y0, reg::X0),
533 6 => (reg::X1, reg::Y0),
534 7 => (reg::Y1, reg::X1),
535 _ => unreachable!(),
536 }
537}
538
539const JJ_REGS: [usize; 4] = [reg::X0, reg::Y0, reg::X1, reg::Y1];
541
542pub fn decode_parallel_alu(b: u8) -> ParallelAlu {
544 use Accumulator::*;
545 use ParallelAlu::*;
546
547 if b == 0x00 {
548 return Move;
549 }
550
551 if b & 0x80 != 0 {
552 let qqq = (b >> 4) & 7;
554 let d = if (b >> 3) & 1 == 0 { A } else { B };
555 let negate = (b >> 2) & 1 == 1;
556 let op = b & 3;
557 let (s1, s2) = qqq_mpy_regs(qqq);
558 return match op {
559 0 => Mpy { negate, s1, s2, d },
560 1 => Mpyr { negate, s1, s2, d },
561 2 => Mac { negate, s1, s2, d },
562 3 => Macr { negate, s1, s2, d },
563 _ => unreachable!(),
564 };
565 }
566
567 let jjj = (b >> 4) & 7;
569 let d = if (b >> 3) & 1 == 0 { A } else { B };
570 let src = match d {
571 A => B,
572 B => A,
573 };
574 let kkk = b & 7;
575
576 match jjj {
577 0 => match kkk {
578 1 => TfrAcc { src, d },
579 2 => Addr { src, d },
580 3 => Tst { d },
581 5 => CmpAcc { src, d },
582 6 => Subr { src, d },
583 7 => CmpmAcc { src, d },
584 _ => Undefined, },
586 1 => match kkk {
587 0 => AddAcc { src, d },
588 1 => Rnd { d },
589 2 => Addl { src, d },
590 3 => Clr { d },
591 4 => SubAcc { src, d },
592 5 => {
593 if b == 0x1D {
594 Max
595 } else if b == 0x15 {
596 Maxm
597 } else {
598 Undefined
599 }
600 }
601 6 => Subl { src, d },
602 7 => Not { d },
603 _ => unreachable!(),
604 },
605 2 => {
606 match kkk {
608 0 => AddXY {
609 hi: reg::X1,
610 lo: reg::X0,
611 d,
612 },
613 1 => Adc {
614 hi: reg::X1,
615 lo: reg::X0,
616 d,
617 },
618 2 => Asr { d },
619 3 => Lsr { d },
620 4 => SubXY {
621 hi: reg::X1,
622 lo: reg::X0,
623 d,
624 },
625 5 => Sbc {
626 hi: reg::X1,
627 lo: reg::X0,
628 d,
629 },
630 6 => Abs { d },
631 7 => Ror { d },
632 _ => unreachable!(),
633 }
634 }
635 3 => {
636 match kkk {
638 0 => AddXY {
639 hi: reg::Y1,
640 lo: reg::Y0,
641 d,
642 },
643 1 => Adc {
644 hi: reg::Y1,
645 lo: reg::Y0,
646 d,
647 },
648 2 => Asl { d },
649 3 => Lsl { d },
650 4 => SubXY {
651 hi: reg::Y1,
652 lo: reg::Y0,
653 d,
654 },
655 5 => Sbc {
656 hi: reg::Y1,
657 lo: reg::Y0,
658 d,
659 },
660 6 => Neg { d },
661 7 => Rol { d },
662 _ => unreachable!(),
663 }
664 }
665 4..=7 => {
666 let jj = (jjj & 3) as usize;
668 let src = JJ_REGS[jj];
669 match kkk {
670 0 => AddReg { src, d },
671 1 => TfrReg { src, d },
672 2 => Or { src, d },
673 3 => Eor { src, d },
674 4 => SubReg { src, d },
675 5 => CmpReg { src, d },
676 6 => And { src, d },
677 7 => CmpmReg { src, d },
678 _ => unreachable!(),
679 }
680 }
681 _ => unreachable!(),
682 }
683}
684
685impl ParallelAlu {
686 pub fn encode(&self) -> Option<u8> {
688 use ParallelAlu::*;
689
690 Some(match *self {
691 Move => 0x00,
692
693 TfrAcc { d, .. } => 0x01 | ((d as u8) << 3),
695 Addr { d, .. } => 0x02 | ((d as u8) << 3),
696 Tst { d } => 0x03 | ((d as u8) << 3),
697 CmpAcc { d, .. } => 0x05 | ((d as u8) << 3),
698 Subr { d, .. } => 0x06 | ((d as u8) << 3),
699 CmpmAcc { d, .. } => 0x07 | ((d as u8) << 3),
700
701 AddAcc { d, .. } => 0x10 | ((d as u8) << 3),
703 Rnd { d } => 0x11 | ((d as u8) << 3),
704 Addl { d, .. } => 0x12 | ((d as u8) << 3),
705 Clr { d } => 0x13 | ((d as u8) << 3),
706 SubAcc { d, .. } => 0x14 | ((d as u8) << 3),
707 Max => 0x1D,
708 Maxm => 0x15,
709 Subl { d, .. } => 0x16 | ((d as u8) << 3),
710 Not { d } => 0x17 | ((d as u8) << 3),
711
712 AddXY { hi, d, .. } if hi == reg::X1 => 0x20 | ((d as u8) << 3),
714 Adc { hi, d, .. } if hi == reg::X1 => 0x21 | ((d as u8) << 3),
715 Asr { d } => 0x22 | ((d as u8) << 3),
716 Lsr { d } => 0x23 | ((d as u8) << 3),
717 SubXY { hi, d, .. } if hi == reg::X1 => 0x24 | ((d as u8) << 3),
718 Sbc { hi, d, .. } if hi == reg::X1 => 0x25 | ((d as u8) << 3),
719 Abs { d } => 0x26 | ((d as u8) << 3),
720 Ror { d } => 0x27 | ((d as u8) << 3),
721
722 AddXY { d, .. } => 0x30 | ((d as u8) << 3),
724 Adc { d, .. } => 0x31 | ((d as u8) << 3),
725 Asl { d } => 0x32 | ((d as u8) << 3),
726 Lsl { d } => 0x33 | ((d as u8) << 3),
727 SubXY { d, .. } => 0x34 | ((d as u8) << 3),
728 Sbc { d, .. } => 0x35 | ((d as u8) << 3),
729 Neg { d } => 0x36 | ((d as u8) << 3),
730 Rol { d } => 0x37 | ((d as u8) << 3),
731
732 AddReg { src, d } => 0x40 | (jj_encode(src)? << 4) | ((d as u8) << 3),
734 TfrReg { src, d } => 0x41 | (jj_encode(src)? << 4) | ((d as u8) << 3),
735 Or { src, d } => 0x42 | (jj_encode(src)? << 4) | ((d as u8) << 3),
736 Eor { src, d } => 0x43 | (jj_encode(src)? << 4) | ((d as u8) << 3),
737 SubReg { src, d } => 0x44 | (jj_encode(src)? << 4) | ((d as u8) << 3),
738 CmpReg { src, d } => 0x45 | (jj_encode(src)? << 4) | ((d as u8) << 3),
739 And { src, d } => 0x46 | (jj_encode(src)? << 4) | ((d as u8) << 3),
740 CmpmReg { src, d } => 0x47 | (jj_encode(src)? << 4) | ((d as u8) << 3),
741
742 Mpy { negate, s1, s2, d } => {
744 0x80 | (qqq_mpy_encode(s1, s2)? << 4) | ((d as u8) << 3) | ((negate as u8) << 2)
745 }
746 Mpyr { negate, s1, s2, d } => {
747 0x81 | (qqq_mpy_encode(s1, s2)? << 4) | ((d as u8) << 3) | ((negate as u8) << 2)
748 }
749 Mac { negate, s1, s2, d } => {
750 0x82 | (qqq_mpy_encode(s1, s2)? << 4) | ((d as u8) << 3) | ((negate as u8) << 2)
751 }
752 Macr { negate, s1, s2, d } => {
753 0x83 | (qqq_mpy_encode(s1, s2)? << 4) | ((d as u8) << 3) | ((negate as u8) << 2)
754 }
755
756 Undefined => return None,
757 })
758 }
759
760 pub fn dest_accumulator(&self) -> Option<Accumulator> {
763 use ParallelAlu::*;
764 match *self {
765 Move | Undefined => None,
766 CmpAcc { .. } | CmpmAcc { .. } | Tst { .. } | CmpReg { .. } | CmpmReg { .. } => None,
768 Max | Maxm => Some(Accumulator::B),
770 TfrAcc { d, .. }
772 | Addr { d, .. }
773 | Subr { d, .. }
774 | AddAcc { d, .. }
775 | Rnd { d }
776 | Addl { d, .. }
777 | Clr { d }
778 | SubAcc { d, .. }
779 | Subl { d, .. }
780 | Not { d }
781 | AddXY { d, .. }
782 | Adc { d, .. }
783 | SubXY { d, .. }
784 | Sbc { d, .. }
785 | Asr { d }
786 | Lsr { d }
787 | Abs { d }
788 | Ror { d }
789 | Asl { d }
790 | Lsl { d }
791 | Neg { d }
792 | Rol { d }
793 | AddReg { d, .. }
794 | TfrReg { d, .. }
795 | Or { d, .. }
796 | Eor { d, .. }
797 | SubReg { d, .. }
798 | And { d, .. }
799 | Mpy { d, .. }
800 | Mpyr { d, .. }
801 | Mac { d, .. }
802 | Macr { d, .. } => Some(d),
803 }
804 }
805
806 pub fn from_text(text: &str) -> Option<ParallelAlu> {
810 use ParallelAlu::*;
811
812 fn parse_acc(s: &str) -> Option<Accumulator> {
813 match s {
814 "a" => Some(Accumulator::A),
815 "b" => Some(Accumulator::B),
816 _ => None,
817 }
818 }
819
820 fn parse_jj_reg(s: &str) -> Option<usize> {
821 match s {
822 "x0" => Some(reg::X0),
823 "y0" => Some(reg::Y0),
824 "x1" => Some(reg::X1),
825 "y1" => Some(reg::Y1),
826 _ => None,
827 }
828 }
829
830 fn parse_xy_pair(s: &str) -> Option<(usize, usize)> {
831 match s {
832 "x" => Some((reg::X1, reg::X0)),
833 "y" => Some((reg::Y1, reg::Y0)),
834 _ => None,
835 }
836 }
837
838 fn parse_qqq_pair(s1: &str, s2: &str) -> Option<(usize, usize)> {
839 let r1 = parse_jj_reg(s1)?;
840 let r2 = parse_jj_reg(s2)?;
841 match (r1, r2) {
843 (reg::X0, reg::X0)
844 | (reg::Y0, reg::Y0)
845 | (reg::X1, reg::X0)
846 | (reg::Y1, reg::Y0)
847 | (reg::X0, reg::Y1)
848 | (reg::Y0, reg::X0)
849 | (reg::X1, reg::Y0)
850 | (reg::Y1, reg::X1) => Some((r1, r2)),
851 _ => None,
852 }
853 }
854
855 if text == "move" {
856 return Some(Move);
857 }
858
859 let (mnemonic, operands) = text.split_once(' ')?;
860 let ops: Vec<&str> = operands.split(',').collect();
861
862 match mnemonic {
863 "tst" | "rnd" | "clr" | "not" | "asr" | "lsr" | "abs" | "ror" | "asl" | "lsl"
865 | "neg" | "rol" => {
866 let d = parse_acc(ops.first()?)?;
867 match mnemonic {
868 "tst" => Some(Tst { d }),
869 "rnd" => Some(Rnd { d }),
870 "clr" => Some(Clr { d }),
871 "not" => Some(Not { d }),
872 "asr" => Some(Asr { d }),
873 "lsr" => Some(Lsr { d }),
874 "abs" => Some(Abs { d }),
875 "ror" => Some(Ror { d }),
876 "asl" => Some(Asl { d }),
877 "lsl" => Some(Lsl { d }),
878 "neg" => Some(Neg { d }),
879 "rol" => Some(Rol { d }),
880 _ => unreachable!(),
881 }
882 }
883
884 "tfr" | "add" | "sub" | "cmp" | "cmpm" | "addr" | "subr" | "addl" | "subl" | "adc"
886 | "sbc" | "or" | "eor" | "and" => {
887 if ops.len() != 2 {
888 return None;
889 }
890 let d = parse_acc(ops[1])?;
891 let src_str = ops[0];
892
893 if let Some(src) = parse_acc(src_str) {
895 return match mnemonic {
896 "tfr" => Some(TfrAcc { src, d }),
897 "addr" => Some(Addr { src, d }),
898 "cmp" => Some(CmpAcc { src, d }),
899 "subr" => Some(Subr { src, d }),
900 "cmpm" => Some(CmpmAcc { src, d }),
901 "add" => Some(AddAcc { src, d }),
902 "addl" => Some(Addl { src, d }),
903 "sub" => Some(SubAcc { src, d }),
904 "subl" => Some(Subl { src, d }),
905 _ => None,
906 };
907 }
908
909 if let Some((hi, lo)) = parse_xy_pair(src_str) {
911 return match mnemonic {
912 "add" => Some(AddXY { hi, lo, d }),
913 "adc" => Some(Adc { hi, lo, d }),
914 "sub" => Some(SubXY { hi, lo, d }),
915 "sbc" => Some(Sbc { hi, lo, d }),
916 _ => None,
917 };
918 }
919
920 if let Some(src) = parse_jj_reg(src_str) {
922 return match mnemonic {
923 "add" => Some(AddReg { src, d }),
924 "tfr" => Some(TfrReg { src, d }),
925 "or" => Some(Or { src, d }),
926 "eor" => Some(Eor { src, d }),
927 "sub" => Some(SubReg { src, d }),
928 "cmp" => Some(CmpReg { src, d }),
929 "and" => Some(And { src, d }),
930 "cmpm" => Some(CmpmReg { src, d }),
931 _ => None,
932 };
933 }
934
935 None
936 }
937
938 "max" | "maxm" => {
940 if ops.len() == 2 && ops[0] == "a" && ops[1] == "b" {
941 Some(if mnemonic == "max" { Max } else { Maxm })
942 } else {
943 None
944 }
945 }
946
947 "mpy" | "mpyr" | "mac" | "macr" => {
949 if ops.len() != 3 {
950 return None;
951 }
952 let d = parse_acc(ops[2])?;
953 let (negate, s1_str) = if let Some(rest) = ops[0].strip_prefix('-') {
954 (true, rest)
955 } else if let Some(rest) = ops[0].strip_prefix('+') {
956 (false, rest)
957 } else {
958 return None;
959 };
960 let (s1, s2) = parse_qqq_pair(s1_str, ops[1])?;
961 match mnemonic {
962 "mpy" => Some(Mpy { negate, s1, s2, d }),
963 "mpyr" => Some(Mpyr { negate, s1, s2, d }),
964 "mac" => Some(Mac { negate, s1, s2, d }),
965 "macr" => Some(Macr { negate, s1, s2, d }),
966 _ => unreachable!(),
967 }
968 }
969
970 _ => None,
971 }
972 }
973
974 pub fn is_logical_or_shift(&self) -> bool {
976 use ParallelAlu::*;
977 matches!(
978 self,
979 And { .. }
980 | Or { .. }
981 | Eor { .. }
982 | Not { .. }
983 | Asl { .. }
984 | Asr { .. }
985 | Lsl { .. }
986 | Lsr { .. }
987 | Rol { .. }
988 | Ror { .. }
989 )
990 }
991}
992
993fn jj_encode(src: usize) -> Option<u8> {
995 match src {
996 reg::X0 => Some(0),
997 reg::Y0 => Some(1),
998 reg::X1 => Some(2),
999 reg::Y1 => Some(3),
1000 _ => None,
1001 }
1002}
1003
1004fn qqq_mpy_encode(s1: usize, s2: usize) -> Option<u8> {
1006 match (s1, s2) {
1007 (reg::X0, reg::X0) => Some(0),
1008 (reg::Y0, reg::Y0) => Some(1),
1009 (reg::X1, reg::X0) => Some(2),
1010 (reg::Y1, reg::Y0) => Some(3),
1011 (reg::X0, reg::Y1) => Some(4),
1012 (reg::Y0, reg::X0) => Some(5),
1013 (reg::X1, reg::Y0) => Some(6),
1014 (reg::Y1, reg::X1) => Some(7),
1015 _ => None,
1016 }
1017}
1018
1019fn xy_pair_name(hi: usize) -> &'static str {
1021 match hi {
1022 reg::X1 => "x",
1023 reg::Y1 => "y",
1024 _ => unreachable!(),
1025 }
1026}
1027
1028impl std::fmt::Display for ParallelAlu {
1029 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1030 use ParallelAlu::*;
1031
1032 match *self {
1033 Move => write!(f, "move"),
1034
1035 TfrAcc { src, d } => write!(f, "tfr {},{}", acc_name(src), acc_name(d)),
1036 Addr { src, d } => write!(f, "addr {},{}", acc_name(src), acc_name(d)),
1037 Tst { d } => write!(f, "tst {}", acc_name(d)),
1038 CmpAcc { src, d } => write!(f, "cmp {},{}", acc_name(src), acc_name(d)),
1039 Subr { src, d } => write!(f, "subr {},{}", acc_name(src), acc_name(d)),
1040 CmpmAcc { src, d } => write!(f, "cmpm {},{}", acc_name(src), acc_name(d)),
1041
1042 AddAcc { src, d } => write!(f, "add {},{}", acc_name(src), acc_name(d)),
1043 Rnd { d } => write!(f, "rnd {}", acc_name(d)),
1044 Addl { src, d } => write!(f, "addl {},{}", acc_name(src), acc_name(d)),
1045 Clr { d } => write!(f, "clr {}", acc_name(d)),
1046 SubAcc { src, d } => write!(f, "sub {},{}", acc_name(src), acc_name(d)),
1047 Max => write!(f, "max a,b"),
1048 Maxm => write!(f, "maxm a,b"),
1049 Subl { src, d } => write!(f, "subl {},{}", acc_name(src), acc_name(d)),
1050 Not { d } => write!(f, "not {}", acc_name(d)),
1051
1052 AddXY { hi, d, .. } => write!(f, "add {},{}", xy_pair_name(hi), acc_name(d)),
1053 Adc { hi, d, .. } => write!(f, "adc {},{}", xy_pair_name(hi), acc_name(d)),
1054 SubXY { hi, d, .. } => write!(f, "sub {},{}", xy_pair_name(hi), acc_name(d)),
1055 Sbc { hi, d, .. } => write!(f, "sbc {},{}", xy_pair_name(hi), acc_name(d)),
1056 Asr { d } => write!(f, "asr {}", acc_name(d)),
1057 Lsr { d } => write!(f, "lsr {}", acc_name(d)),
1058 Abs { d } => write!(f, "abs {}", acc_name(d)),
1059 Ror { d } => write!(f, "ror {}", acc_name(d)),
1060 Asl { d } => write!(f, "asl {}", acc_name(d)),
1061 Lsl { d } => write!(f, "lsl {}", acc_name(d)),
1062 Neg { d } => write!(f, "neg {}", acc_name(d)),
1063 Rol { d } => write!(f, "rol {}", acc_name(d)),
1064
1065 AddReg { src, d } => write!(f, "add {},{}", REGISTER_NAMES[src], acc_name(d)),
1066 TfrReg { src, d } => write!(f, "tfr {},{}", REGISTER_NAMES[src], acc_name(d)),
1067 Or { src, d } => write!(f, "or {},{}", REGISTER_NAMES[src], acc_name(d)),
1068 Eor { src, d } => write!(f, "eor {},{}", REGISTER_NAMES[src], acc_name(d)),
1069 SubReg { src, d } => write!(f, "sub {},{}", REGISTER_NAMES[src], acc_name(d)),
1070 CmpReg { src, d } => write!(f, "cmp {},{}", REGISTER_NAMES[src], acc_name(d)),
1071 And { src, d } => write!(f, "and {},{}", REGISTER_NAMES[src], acc_name(d)),
1072 CmpmReg { src, d } => write!(f, "cmpm {},{}", REGISTER_NAMES[src], acc_name(d)),
1073
1074 Mpy { negate, s1, s2, d } => {
1075 write!(
1076 f,
1077 "mpy {}{},{},{}",
1078 if negate { "-" } else { "+" },
1079 REGISTER_NAMES[s1],
1080 REGISTER_NAMES[s2],
1081 acc_name(d),
1082 )
1083 }
1084 Mpyr { negate, s1, s2, d } => {
1085 write!(
1086 f,
1087 "mpyr {}{},{},{}",
1088 if negate { "-" } else { "+" },
1089 REGISTER_NAMES[s1],
1090 REGISTER_NAMES[s2],
1091 acc_name(d),
1092 )
1093 }
1094 Mac { negate, s1, s2, d } => {
1095 write!(
1096 f,
1097 "mac {}{},{},{}",
1098 if negate { "-" } else { "+" },
1099 REGISTER_NAMES[s1],
1100 REGISTER_NAMES[s2],
1101 acc_name(d),
1102 )
1103 }
1104 Macr { negate, s1, s2, d } => {
1105 write!(
1106 f,
1107 "macr {}{},{},{}",
1108 if negate { "-" } else { "+" },
1109 REGISTER_NAMES[s1],
1110 REGISTER_NAMES[s2],
1111 acc_name(d),
1112 )
1113 }
1114
1115 Undefined => write!(f, "undefined"),
1116 }
1117 }
1118}
1119
1120fn acc_name(a: Accumulator) -> &'static str {
1121 match a {
1122 Accumulator::A => "a",
1123 Accumulator::B => "b",
1124 }
1125}
1126
1127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1129#[repr(u8)]
1130pub enum ParallelMoveType {
1131 Pm0 = 0,
1133 Pm1 = 1,
1135 Pm2 = 2,
1137 Pm3 = 3,
1139 Pm4 = 4,
1141 Pm5 = 5,
1143 Pm8 = 8,
1145}
1146
1147impl ParallelMoveType {
1148 pub fn from_bits(bits: u32) -> Self {
1149 match bits {
1150 0 => Self::Pm0,
1151 1 => Self::Pm1,
1152 2 => Self::Pm2,
1153 3 => Self::Pm3,
1154 4 => Self::Pm4,
1155 5..=7 => Self::Pm5,
1156 8..=15 => Self::Pm8,
1157 _ => unreachable!(),
1158 }
1159 }
1160}
1161
1162#[derive(Debug, Clone)]
1164pub enum Instruction {
1165 Parallel {
1167 alu: ParallelAlu,
1168 move_type: ParallelMoveType,
1169 opcode: u32,
1171 },
1172
1173 AddImm {
1175 imm: u8,
1176 d: Accumulator,
1177 },
1178 AddLong {
1179 d: Accumulator,
1180 },
1181 SubImm {
1182 imm: u8,
1183 d: Accumulator,
1184 },
1185 SubLong {
1186 d: Accumulator,
1187 },
1188 CmpImm {
1189 imm: u8,
1190 d: Accumulator,
1191 },
1192 CmpLong {
1193 d: Accumulator,
1194 },
1195 CmpU {
1196 src: usize,
1197 d: Accumulator,
1198 },
1199 AndImm {
1200 imm: u8,
1201 d: Accumulator,
1202 },
1203 AndLong {
1204 d: Accumulator,
1205 },
1206 OrLong {
1207 d: Accumulator,
1208 },
1209 OrImm {
1210 imm: u8,
1211 d: Accumulator,
1212 },
1213 EorImm {
1214 imm: u8,
1215 d: Accumulator,
1216 },
1217 EorLong {
1218 d: Accumulator,
1219 },
1220 AndI {
1221 imm: u8,
1222 dest: u8,
1223 },
1224 OrI {
1225 imm: u8,
1226 dest: u8,
1227 },
1228
1229 AslImm {
1231 shift: u8,
1232 s: Accumulator,
1233 d: Accumulator,
1234 },
1235 AsrImm {
1236 shift: u8,
1237 s: Accumulator,
1238 d: Accumulator,
1239 },
1240 LslImm {
1241 shift: u8,
1242 d: Accumulator,
1243 },
1244 LsrImm {
1245 shift: u8,
1246 d: Accumulator,
1247 },
1248 AslReg {
1249 src: usize,
1250 s: Accumulator,
1251 d: Accumulator,
1252 },
1253 AsrReg {
1254 src: usize,
1255 s: Accumulator,
1256 d: Accumulator,
1257 },
1258 LslReg {
1259 src: usize,
1260 d: Accumulator,
1261 },
1262 LsrReg {
1263 src: usize,
1264 d: Accumulator,
1265 },
1266
1267 Bcc {
1269 cc: CondCode,
1270 addr: i32,
1271 },
1272 BccLong {
1273 cc: CondCode,
1274 },
1275 Bra {
1276 addr: i32,
1277 },
1278 BraLong,
1279 Bsr {
1280 addr: i32,
1281 },
1282 BsrLong,
1283 BccRn {
1284 cc: CondCode,
1285 rn: u8,
1286 },
1287 BraRn {
1288 rn: u8,
1289 },
1290 BsrRn {
1291 rn: u8,
1292 },
1293 Bscc {
1294 cc: CondCode,
1295 addr: i32,
1296 },
1297 BsccLong {
1298 cc: CondCode,
1299 },
1300 BsccRn {
1301 cc: CondCode,
1302 rn: u8,
1303 },
1304 Brkcc {
1305 cc: CondCode,
1306 },
1307 Jcc {
1308 cc: CondCode,
1309 addr: u32,
1310 },
1311 JccEa {
1312 cc: CondCode,
1313 ea_mode: u8,
1314 },
1315 Jmp {
1316 addr: u32,
1317 },
1318 JmpEa {
1319 ea_mode: u8,
1320 },
1321 Jscc {
1322 cc: CondCode,
1323 addr: u32,
1324 },
1325 JsccEa {
1326 cc: CondCode,
1327 ea_mode: u8,
1328 },
1329 Jsr {
1330 addr: u32,
1331 },
1332 JsrEa {
1333 ea_mode: u8,
1334 },
1335
1336 BchgEa {
1338 space: MemSpace,
1339 ea_mode: u8,
1340 bit_num: u8,
1341 },
1342 BchgAa {
1343 space: MemSpace,
1344 addr: u8,
1345 bit_num: u8,
1346 },
1347 BchgPp {
1348 space: MemSpace,
1349 pp_offset: u8,
1350 bit_num: u8,
1351 },
1352 BchgQq {
1353 space: MemSpace,
1354 qq_offset: u8,
1355 bit_num: u8,
1356 },
1357 BchgReg {
1358 reg_idx: u8,
1359 bit_num: u8,
1360 },
1361 BclrEa {
1362 space: MemSpace,
1363 ea_mode: u8,
1364 bit_num: u8,
1365 },
1366 BclrAa {
1367 space: MemSpace,
1368 addr: u8,
1369 bit_num: u8,
1370 },
1371 BclrPp {
1372 space: MemSpace,
1373 pp_offset: u8,
1374 bit_num: u8,
1375 },
1376 BclrQq {
1377 space: MemSpace,
1378 qq_offset: u8,
1379 bit_num: u8,
1380 },
1381 BclrReg {
1382 reg_idx: u8,
1383 bit_num: u8,
1384 },
1385 BsetEa {
1386 space: MemSpace,
1387 ea_mode: u8,
1388 bit_num: u8,
1389 },
1390 BsetAa {
1391 space: MemSpace,
1392 addr: u8,
1393 bit_num: u8,
1394 },
1395 BsetPp {
1396 space: MemSpace,
1397 pp_offset: u8,
1398 bit_num: u8,
1399 },
1400 BsetQq {
1401 space: MemSpace,
1402 qq_offset: u8,
1403 bit_num: u8,
1404 },
1405 BsetReg {
1406 reg_idx: u8,
1407 bit_num: u8,
1408 },
1409 BtstEa {
1410 space: MemSpace,
1411 ea_mode: u8,
1412 bit_num: u8,
1413 },
1414 BtstAa {
1415 space: MemSpace,
1416 addr: u8,
1417 bit_num: u8,
1418 },
1419 BtstPp {
1420 space: MemSpace,
1421 pp_offset: u8,
1422 bit_num: u8,
1423 },
1424 BtstQq {
1425 space: MemSpace,
1426 qq_offset: u8,
1427 bit_num: u8,
1428 },
1429 BtstReg {
1430 reg_idx: u8,
1431 bit_num: u8,
1432 },
1433
1434 BrclrEa {
1436 space: MemSpace,
1437 ea_mode: u8,
1438 bit_num: u8,
1439 },
1440 BrclrAa {
1441 space: MemSpace,
1442 addr: u8,
1443 bit_num: u8,
1444 },
1445 BrclrPp {
1446 space: MemSpace,
1447 pp_offset: u8,
1448 bit_num: u8,
1449 },
1450 BrclrQq {
1451 space: MemSpace,
1452 qq_offset: u8,
1453 bit_num: u8,
1454 },
1455 BrclrReg {
1456 reg_idx: u8,
1457 bit_num: u8,
1458 },
1459 BrsetEa {
1460 space: MemSpace,
1461 ea_mode: u8,
1462 bit_num: u8,
1463 },
1464 BrsetAa {
1465 space: MemSpace,
1466 addr: u8,
1467 bit_num: u8,
1468 },
1469 BrsetPp {
1470 space: MemSpace,
1471 pp_offset: u8,
1472 bit_num: u8,
1473 },
1474 BrsetQq {
1475 space: MemSpace,
1476 qq_offset: u8,
1477 bit_num: u8,
1478 },
1479 BrsetReg {
1480 reg_idx: u8,
1481 bit_num: u8,
1482 },
1483
1484 BsclrEa {
1486 space: MemSpace,
1487 ea_mode: u8,
1488 bit_num: u8,
1489 },
1490 BsclrAa {
1491 space: MemSpace,
1492 addr: u8,
1493 bit_num: u8,
1494 },
1495 BsclrPp {
1496 space: MemSpace,
1497 pp_offset: u8,
1498 bit_num: u8,
1499 },
1500 BsclrQq {
1501 space: MemSpace,
1502 qq_offset: u8,
1503 bit_num: u8,
1504 },
1505 BsclrReg {
1506 reg_idx: u8,
1507 bit_num: u8,
1508 },
1509 BssetEa {
1510 space: MemSpace,
1511 ea_mode: u8,
1512 bit_num: u8,
1513 },
1514 BssetAa {
1515 space: MemSpace,
1516 addr: u8,
1517 bit_num: u8,
1518 },
1519 BssetPp {
1520 space: MemSpace,
1521 pp_offset: u8,
1522 bit_num: u8,
1523 },
1524 BssetQq {
1525 space: MemSpace,
1526 qq_offset: u8,
1527 bit_num: u8,
1528 },
1529 BssetReg {
1530 reg_idx: u8,
1531 bit_num: u8,
1532 },
1533
1534 JclrEa {
1535 space: MemSpace,
1536 ea_mode: u8,
1537 bit_num: u8,
1538 },
1539 JclrAa {
1540 space: MemSpace,
1541 addr: u8,
1542 bit_num: u8,
1543 },
1544 JclrPp {
1545 space: MemSpace,
1546 pp_offset: u8,
1547 bit_num: u8,
1548 },
1549 JclrQq {
1550 space: MemSpace,
1551 qq_offset: u8,
1552 bit_num: u8,
1553 },
1554 JclrReg {
1555 reg_idx: u8,
1556 bit_num: u8,
1557 },
1558 JsetEa {
1559 space: MemSpace,
1560 ea_mode: u8,
1561 bit_num: u8,
1562 },
1563 JsetAa {
1564 space: MemSpace,
1565 addr: u8,
1566 bit_num: u8,
1567 },
1568 JsetPp {
1569 space: MemSpace,
1570 pp_offset: u8,
1571 bit_num: u8,
1572 },
1573 JsetQq {
1574 space: MemSpace,
1575 qq_offset: u8,
1576 bit_num: u8,
1577 },
1578 JsetReg {
1579 reg_idx: u8,
1580 bit_num: u8,
1581 },
1582 JsclrEa {
1583 space: MemSpace,
1584 ea_mode: u8,
1585 bit_num: u8,
1586 },
1587 JsclrAa {
1588 space: MemSpace,
1589 addr: u8,
1590 bit_num: u8,
1591 },
1592 JsclrPp {
1593 space: MemSpace,
1594 pp_offset: u8,
1595 bit_num: u8,
1596 },
1597 JsclrQq {
1598 space: MemSpace,
1599 qq_offset: u8,
1600 bit_num: u8,
1601 },
1602 JsclrReg {
1603 reg_idx: u8,
1604 bit_num: u8,
1605 },
1606 JssetEa {
1607 space: MemSpace,
1608 ea_mode: u8,
1609 bit_num: u8,
1610 },
1611 JssetAa {
1612 space: MemSpace,
1613 addr: u8,
1614 bit_num: u8,
1615 },
1616 JssetPp {
1617 space: MemSpace,
1618 pp_offset: u8,
1619 bit_num: u8,
1620 },
1621 JssetQq {
1622 space: MemSpace,
1623 qq_offset: u8,
1624 bit_num: u8,
1625 },
1626 JssetReg {
1627 reg_idx: u8,
1628 bit_num: u8,
1629 },
1630
1631 DoEa {
1633 space: MemSpace,
1634 ea_mode: u8,
1635 },
1636 DoAa {
1637 space: MemSpace,
1638 addr: u8,
1639 },
1640 DoImm {
1641 count: u16,
1642 },
1643 DoReg {
1644 reg_idx: u8,
1645 },
1646 DoForever,
1647 DorEa {
1648 space: MemSpace,
1649 ea_mode: u8,
1650 },
1651 DorAa {
1652 space: MemSpace,
1653 addr: u8,
1654 },
1655 DorImm {
1656 count: u16,
1657 },
1658 DorReg {
1659 reg_idx: u8,
1660 },
1661 DorForever,
1662 EndDo,
1663 RepEa {
1664 space: MemSpace,
1665 ea_mode: u8,
1666 },
1667 RepAa {
1668 space: MemSpace,
1669 addr: u8,
1670 },
1671 RepImm {
1672 count: u16,
1673 },
1674 RepReg {
1675 reg_idx: u8,
1676 },
1677
1678 MoveLongDisp {
1680 space: MemSpace,
1681 w: bool,
1682 offreg_idx: u8,
1683 numreg: u8,
1684 },
1685 MoveShortDisp {
1686 space: MemSpace,
1687 offset: u8,
1688 w: bool,
1689 offreg_idx: u8,
1690 numreg: u8,
1691 },
1692 MovecEa {
1693 ea_mode: u8,
1694 numreg: u8,
1695 w: bool,
1696 space: MemSpace,
1697 },
1698 MovecAa {
1699 addr: u8,
1700 numreg: u8,
1701 w: bool,
1702 space: MemSpace,
1703 },
1704 MovecReg {
1705 src_reg: u8,
1706 dst_reg: u8,
1707 w: bool,
1708 },
1709 MovecImm {
1710 imm: u8,
1711 dest: u8,
1712 },
1713 MovemEa {
1714 ea_mode: u8,
1715 numreg: u8,
1716 w: bool,
1717 },
1718 MovemAa {
1719 addr: u8,
1720 numreg: u8,
1721 w: bool,
1722 },
1723 Movep23 {
1724 pp_offset: u8,
1725 ea_mode: u8,
1726 w: bool,
1727 perspace: MemSpace,
1728 easpace: MemSpace,
1729 },
1730 MovepQq {
1731 qq_offset: u8,
1732 ea_mode: u8,
1733 w: bool,
1734 qqspace: MemSpace,
1735 easpace: MemSpace,
1736 },
1737 Movep1 {
1738 pp_offset: u8,
1739 ea_mode: u8,
1740 w: bool,
1741 space: MemSpace,
1742 },
1743 Movep0 {
1744 pp_offset: u8,
1745 reg_idx: u8,
1746 w: bool,
1747 space: MemSpace,
1748 },
1749 MovepQqPea {
1750 qq_offset: u8,
1751 ea_mode: u8,
1752 w: bool,
1753 space: MemSpace,
1754 },
1755 MovepQqR {
1756 qq_offset: u8,
1757 reg_idx: u8,
1758 w: bool,
1759 space: MemSpace,
1760 },
1761
1762 MulShift {
1765 op: MulShiftOp,
1766 shift: u8,
1767 src: usize,
1768 d: Accumulator,
1769 k: bool,
1770 },
1771 MpyI {
1772 k: bool,
1773 d: Accumulator,
1774 src: usize,
1775 },
1776 MpyrI {
1777 k: bool,
1778 d: Accumulator,
1779 src: usize,
1780 },
1781 MacI {
1782 k: bool,
1783 d: Accumulator,
1784 src: usize,
1785 },
1786 MacrI {
1787 k: bool,
1788 d: Accumulator,
1789 src: usize,
1790 },
1791 Dmac {
1792 ss: u8,
1793 k: bool,
1794 d: Accumulator,
1795 s1: usize,
1796 s2: usize,
1797 },
1798 MacSU {
1799 s: u8,
1800 k: bool,
1801 d: Accumulator,
1802 s1: usize,
1803 s2: usize,
1804 },
1805 MpySU {
1806 s: u8,
1807 k: bool,
1808 d: Accumulator,
1809 s1: usize,
1810 s2: usize,
1811 },
1812 Div {
1813 src: usize,
1814 d: Accumulator,
1815 },
1816
1817 Lua {
1819 ea_mode: u8,
1820 dst_reg: u8,
1821 },
1822 LuaRel {
1823 aa: u8,
1824 addr_reg: u8,
1825 dst_reg: u8,
1826 dest_is_n: bool,
1827 },
1828 LraRn {
1829 addr_reg: u8,
1830 dst_reg: u8,
1831 },
1832 LraDisp {
1833 dst_reg: u8,
1834 },
1835 Norm {
1836 rreg_idx: u8,
1837 d: Accumulator,
1838 },
1839
1840 Tcc {
1842 cc: CondCode,
1843 acc: Option<(usize, usize)>,
1844 r: Option<(u8, u8)>,
1845 },
1846
1847 Nop,
1849 Dec {
1850 d: Accumulator,
1851 },
1852 Inc {
1853 d: Accumulator,
1854 },
1855 Illegal,
1856 Reset,
1857 Rti,
1858 Rts,
1859 Stop,
1860 Wait,
1861
1862 Clb {
1864 s: Accumulator,
1865 d: Accumulator,
1866 },
1867 Normf {
1868 src: usize,
1869 d: Accumulator,
1870 },
1871 Debug,
1872 Debugcc {
1873 cc: CondCode,
1874 },
1875 Trap,
1876 Trapcc {
1877 cc: CondCode,
1878 },
1879
1880 Merge {
1882 src: usize,
1883 d: Accumulator,
1884 },
1885 ExtractReg {
1886 s1: usize,
1887 s2: Accumulator,
1888 d: Accumulator,
1889 },
1890 ExtractImm {
1891 s2: Accumulator,
1892 d: Accumulator,
1893 },
1894 ExtractuReg {
1895 s1: usize,
1896 s2: Accumulator,
1897 d: Accumulator,
1898 },
1899 ExtractuImm {
1900 s2: Accumulator,
1901 d: Accumulator,
1902 },
1903 InsertReg {
1904 s1: usize,
1905 s2: usize,
1906 d: Accumulator,
1907 },
1908 InsertImm {
1909 s2: usize,
1910 d: Accumulator,
1911 },
1912
1913 Vsl {
1915 s: Accumulator,
1916 ea_mode: u8,
1917 i_bit: u8,
1918 },
1919
1920 Pflush,
1922 Pflushun,
1923 Pfree,
1924 PlockEa {
1925 ea_mode: u8,
1926 },
1927 Plockr,
1928 PunlockEa {
1929 ea_mode: u8,
1930 },
1931 Punlockr,
1932
1933 Unimplemented {
1935 name: &'static str,
1936 opcode: u32,
1937 },
1938
1939 Unknown {
1941 opcode: u32,
1942 },
1943}
1944
1945#[cfg(test)]
1946mod tests {
1947 use super::*;
1948
1949 #[test]
1950 fn test_parallel_alu_exhaustive_roundtrip() {
1951 let undefined_bytes = [0x04, 0x08, 0x0C];
1952 for b in 0..=255u8 {
1953 let decoded = decode_parallel_alu(b);
1954 if undefined_bytes.contains(&b) {
1955 assert!(
1956 matches!(decoded, ParallelAlu::Undefined),
1957 "byte 0x{b:02X}: expected Undefined, got {decoded:?}"
1958 );
1959 assert_eq!(decoded.encode(), None);
1960 } else {
1961 assert!(
1962 !matches!(decoded, ParallelAlu::Undefined),
1963 "byte 0x{b:02X}: unexpected Undefined"
1964 );
1965 assert_eq!(
1966 decoded.encode(),
1967 Some(b),
1968 "byte 0x{b:02X}: encode roundtrip failed (decoded as {decoded:?})"
1969 );
1970 }
1971 }
1972 }
1973
1974 #[test]
1975 fn test_parallel_alu_display_all() {
1976 #[rustfmt::skip]
1980 const EXPECTED: [&str; 256] = [
1981 "move", "tfr b,a", "addr b,a", "tst a", "undefined", "cmp b,a", "subr b,a", "cmpm b,a", "undefined", "tfr a,b", "addr a,b", "tst b", "undefined", "cmp a,b", "subr a,b", "cmpm a,b", "add b,a", "rnd a", "addl b,a", "clr a", "sub b,a", "maxm a,b", "subl b,a", "not a", "add a,b", "rnd b", "addl a,b", "clr b", "sub a,b", "max a,b", "subl a,b", "not b", "add x,a", "adc x,a", "asr a", "lsr a", "sub x,a", "sbc x,a", "abs a", "ror a", "add x,b", "adc x,b", "asr b", "lsr b", "sub x,b", "sbc x,b", "abs b", "ror b", "add y,a", "adc y,a", "asl a", "lsl a", "sub y,a", "sbc y,a", "neg a", "rol a", "add y,b", "adc y,b", "asl b", "lsl b", "sub y,b", "sbc y,b", "neg b", "rol b", "add x0,a", "tfr x0,a", "or x0,a", "eor x0,a", "sub x0,a", "cmp x0,a", "and x0,a", "cmpm x0,a", "add x0,b", "tfr x0,b", "or x0,b", "eor x0,b", "sub x0,b", "cmp x0,b", "and x0,b", "cmpm x0,b", "add y0,a", "tfr y0,a", "or y0,a", "eor y0,a", "sub y0,a", "cmp y0,a", "and y0,a", "cmpm y0,a", "add y0,b", "tfr y0,b", "or y0,b", "eor y0,b", "sub y0,b", "cmp y0,b", "and y0,b", "cmpm y0,b", "add x1,a", "tfr x1,a", "or x1,a", "eor x1,a", "sub x1,a", "cmp x1,a", "and x1,a", "cmpm x1,a", "add x1,b", "tfr x1,b", "or x1,b", "eor x1,b", "sub x1,b", "cmp x1,b", "and x1,b", "cmpm x1,b", "add y1,a", "tfr y1,a", "or y1,a", "eor y1,a", "sub y1,a", "cmp y1,a", "and y1,a", "cmpm y1,a", "add y1,b", "tfr y1,b", "or y1,b", "eor y1,b", "sub y1,b", "cmp y1,b", "and y1,b", "cmpm y1,b", "mpy +x0,x0,a", "mpyr +x0,x0,a", "mac +x0,x0,a", "macr +x0,x0,a", "mpy -x0,x0,a", "mpyr -x0,x0,a", "mac -x0,x0,a", "macr -x0,x0,a", "mpy +x0,x0,b", "mpyr +x0,x0,b", "mac +x0,x0,b", "macr +x0,x0,b", "mpy -x0,x0,b", "mpyr -x0,x0,b", "mac -x0,x0,b", "macr -x0,x0,b", "mpy +y0,y0,a", "mpyr +y0,y0,a", "mac +y0,y0,a", "macr +y0,y0,a", "mpy -y0,y0,a", "mpyr -y0,y0,a", "mac -y0,y0,a", "macr -y0,y0,a", "mpy +y0,y0,b", "mpyr +y0,y0,b", "mac +y0,y0,b", "macr +y0,y0,b", "mpy -y0,y0,b", "mpyr -y0,y0,b", "mac -y0,y0,b", "macr -y0,y0,b", "mpy +x1,x0,a", "mpyr +x1,x0,a", "mac +x1,x0,a", "macr +x1,x0,a", "mpy -x1,x0,a", "mpyr -x1,x0,a", "mac -x1,x0,a", "macr -x1,x0,a", "mpy +x1,x0,b", "mpyr +x1,x0,b", "mac +x1,x0,b", "macr +x1,x0,b", "mpy -x1,x0,b", "mpyr -x1,x0,b", "mac -x1,x0,b", "macr -x1,x0,b", "mpy +y1,y0,a", "mpyr +y1,y0,a", "mac +y1,y0,a", "macr +y1,y0,a", "mpy -y1,y0,a", "mpyr -y1,y0,a", "mac -y1,y0,a", "macr -y1,y0,a", "mpy +y1,y0,b", "mpyr +y1,y0,b", "mac +y1,y0,b", "macr +y1,y0,b", "mpy -y1,y0,b", "mpyr -y1,y0,b", "mac -y1,y0,b", "macr -y1,y0,b", "mpy +x0,y1,a", "mpyr +x0,y1,a", "mac +x0,y1,a", "macr +x0,y1,a", "mpy -x0,y1,a", "mpyr -x0,y1,a", "mac -x0,y1,a", "macr -x0,y1,a", "mpy +x0,y1,b", "mpyr +x0,y1,b", "mac +x0,y1,b", "macr +x0,y1,b", "mpy -x0,y1,b", "mpyr -x0,y1,b", "mac -x0,y1,b", "macr -x0,y1,b", "mpy +y0,x0,a", "mpyr +y0,x0,a", "mac +y0,x0,a", "macr +y0,x0,a", "mpy -y0,x0,a", "mpyr -y0,x0,a", "mac -y0,x0,a", "macr -y0,x0,a", "mpy +y0,x0,b", "mpyr +y0,x0,b", "mac +y0,x0,b", "macr +y0,x0,b", "mpy -y0,x0,b", "mpyr -y0,x0,b", "mac -y0,x0,b", "macr -y0,x0,b", "mpy +x1,y0,a", "mpyr +x1,y0,a", "mac +x1,y0,a", "macr +x1,y0,a", "mpy -x1,y0,a", "mpyr -x1,y0,a", "mac -x1,y0,a", "macr -x1,y0,a", "mpy +x1,y0,b", "mpyr +x1,y0,b", "mac +x1,y0,b", "macr +x1,y0,b", "mpy -x1,y0,b", "mpyr -x1,y0,b", "mac -x1,y0,b", "macr -x1,y0,b", "mpy +y1,x1,a", "mpyr +y1,x1,a", "mac +y1,x1,a", "macr +y1,x1,a", "mpy -y1,x1,a", "mpyr -y1,x1,a", "mac -y1,x1,a", "macr -y1,x1,a", "mpy +y1,x1,b", "mpyr +y1,x1,b", "mac +y1,x1,b", "macr +y1,x1,b", "mpy -y1,x1,b", "mpyr -y1,x1,b", "mac -y1,x1,b", "macr -y1,x1,b", ];
2014
2015 for (i, expected) in EXPECTED.iter().enumerate() {
2016 assert_eq!(
2017 decode_parallel_alu(i as u8).to_string(),
2018 *expected,
2019 "byte 0x{i:02X}"
2020 );
2021 }
2022 }
2023
2024 #[test]
2025 fn test_parallel_alu_from_text_roundtrip() {
2026 for b in 0..=255u8 {
2027 let alu = decode_parallel_alu(b);
2028 if matches!(alu, ParallelAlu::Undefined) {
2029 continue;
2030 }
2031 let text = alu.to_string();
2032 let parsed = ParallelAlu::from_text(&text).unwrap_or_else(|| {
2033 panic!("from_text failed for {:?} (0x{b:02X}): \"{text}\"", alu)
2034 });
2035 assert_eq!(
2036 parsed, alu,
2037 "from_text roundtrip mismatch for 0x{b:02X}: \"{text}\" -> {parsed:?} != {alu:?}"
2038 );
2039 }
2040 }
2041}