1macro_rules! op_constructor {
198 ($doc:literal $Op:ident $op:ident[$ra:ident : RegId]) => {
199 #[doc = $doc]
200 pub fn $op<A: CheckRegId>($ra: A) -> Instruction {
201 $Op::new($ra.check()).into()
202 }
203
204 #[cfg(feature = "typescript")]
205 const _: () = {
206 use super::*;
207
208 #[wasm_bindgen::prelude::wasm_bindgen]
209 #[doc = $doc]
210 pub fn $op($ra: u8) -> typescript::Instruction {
211 crate::op::$op($ra).into()
212 }
213 };
214 };
215 ($doc:literal $Op:ident $op:ident[$ra:ident : RegId $rb:ident : RegId]) => {
216 #[doc = $doc]
217 pub fn $op<A: CheckRegId, B: CheckRegId>($ra: A, $rb: B) -> Instruction {
218 $Op::new($ra.check(), $rb.check()).into()
219 }
220
221 #[cfg(feature = "typescript")]
222 const _: () = {
223 use super::*;
224
225 #[wasm_bindgen::prelude::wasm_bindgen]
226 #[doc = $doc]
227 pub fn $op($ra: u8, $rb: u8) -> typescript::Instruction {
228 crate::op::$op($ra, $rb).into()
229 }
230 };
231 };
232 (
233 $doc:literal
234 $Op:ident
235 $op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId]
236 ) => {
237 #[doc = $doc]
238 pub fn $op<A: CheckRegId, B: CheckRegId, C: CheckRegId>(
239 $ra: A,
240 $rb: B,
241 $rc: C,
242 ) -> Instruction {
243 $Op::new($ra.check(), $rb.check(), $rc.check()).into()
244 }
245
246 #[cfg(feature = "typescript")]
247 const _: () = {
248 use super::*;
249
250 #[wasm_bindgen::prelude::wasm_bindgen]
251 #[doc = $doc]
252 pub fn $op($ra: u8, $rb: u8, $rc: u8) -> typescript::Instruction {
253 crate::op::$op($ra, $rb, $rc).into()
254 }
255 };
256 };
257 (
258 $doc:literal
259 $Op:ident
260 $op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId $rd:ident : RegId]
261 ) => {
262 #[doc = $doc]
263 pub fn $op<A: CheckRegId, B: CheckRegId, C: CheckRegId, D: CheckRegId>(
264 $ra: A,
265 $rb: B,
266 $rc: C,
267 $rd: D,
268 ) -> Instruction {
269 $Op::new($ra.check(), $rb.check(), $rc.check(), $rd.check()).into()
270 }
271
272 #[cfg(feature = "typescript")]
273 const _: () = {
274 use super::*;
275
276 #[wasm_bindgen::prelude::wasm_bindgen]
277 #[doc = $doc]
278 pub fn $op($ra: u8, $rb: u8, $rc: u8, $rd: u8) -> typescript::Instruction {
279 crate::op::$op($ra, $rb, $rc, $rd).into()
280 }
281 };
282 };
283 (
284 $doc:literal
285 $Op:ident
286 $op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId $imm:ident : Imm06]
287 ) => {
288 #[doc = $doc]
289 pub fn $op<A: CheckRegId, B: CheckRegId, C: CheckRegId>(
290 $ra: A,
291 $rb: B,
292 $rc: C,
293 $imm: u8,
294 ) -> Instruction {
295 $Op::new($ra.check(), $rb.check(), $rc.check(), check_imm06($imm)).into()
296 }
297
298 #[cfg(feature = "typescript")]
299 const _: () = {
300 use super::*;
301
302 #[wasm_bindgen::prelude::wasm_bindgen]
303 #[doc = $doc]
304 pub fn $op($ra: u8, $rb: u8, $rc: u8, $imm: u8) -> typescript::Instruction {
305 crate::op::$op($ra, $rb, $rc, $imm).into()
306 }
307 };
308 };
309 (
310 $doc:literal
311 $Op:ident
312 $op:ident[$ra:ident : RegId $rb:ident : RegId $imm:ident : Imm12]
313 ) => {
314 #[doc = $doc]
315 pub fn $op<A: CheckRegId, B: CheckRegId>(
316 $ra: A,
317 $rb: B,
318 $imm: u16,
319 ) -> Instruction {
320 $Op::new($ra.check(), $rb.check(), check_imm12($imm)).into()
321 }
322
323 #[cfg(feature = "typescript")]
324 const _: () = {
325 use super::*;
326
327 #[wasm_bindgen::prelude::wasm_bindgen]
328 #[doc = $doc]
329 pub fn $op($ra: u8, $rb: u8, $imm: u16) -> typescript::Instruction {
330 crate::op::$op($ra, $rb, $imm).into()
331 }
332 };
333 };
334 ($doc:literal $Op:ident $op:ident[$ra:ident : RegId $imm:ident : Imm18]) => {
335 #[doc = $doc]
336 pub fn $op<A: CheckRegId>($ra: A, $imm: u32) -> Instruction {
337 $Op::new($ra.check(), check_imm18($imm)).into()
338 }
339
340 #[cfg(feature = "typescript")]
341 const _: () = {
342 use super::*;
343
344 #[wasm_bindgen::prelude::wasm_bindgen]
345 #[doc = $doc]
346 pub fn $op($ra: u8, $imm: u32) -> typescript::Instruction {
347 crate::op::$op($ra, $imm).into()
348 }
349 };
350 };
351 ($doc:literal $Op:ident $op:ident[$imm:ident : Imm24]) => {
352 #[doc = $doc]
353 pub fn $op($imm: u32) -> Instruction {
354 $Op::new(check_imm24($imm)).into()
355 }
356
357 #[cfg(feature = "typescript")]
358 const _: () = {
359 use super::*;
360
361 #[wasm_bindgen::prelude::wasm_bindgen]
362 #[doc = $doc]
363 pub fn $op($imm: u32) -> typescript::Instruction {
364 crate::op::$op($imm).into()
365 }
366 };
367 };
368 ($doc:literal $Op:ident $op:ident[]) => {
369 #[doc = $doc]
370 pub fn $op() -> Instruction {
371 $Op::new().into()
372 }
373
374 #[cfg(feature = "typescript")]
375 const _: () = {
376 use super::*;
377
378 #[wasm_bindgen::prelude::wasm_bindgen]
379 #[doc = $doc]
380 pub fn $op() -> typescript::Instruction {
381 crate::op::$op().into()
382 }
383 };
384 };
385}
386
387macro_rules! op_new {
389 ($Op:ident $ra:ident : RegId) => {
391 impl $Op {
392 pub fn new($ra: RegId) -> Self {
394 Self(pack::bytes_from_ra($ra))
395 }
396 }
397
398 #[cfg(feature = "typescript")]
399 #[wasm_bindgen::prelude::wasm_bindgen]
400 impl $Op {
401 #[wasm_bindgen(constructor)]
402 pub fn new_typescript($ra: RegId) -> Self {
404 Self::new($ra)
405 }
406 }
407 };
408 ($Op:ident $ra:ident : RegId $rb:ident : RegId) => {
409 impl $Op {
410 pub fn new($ra: RegId, $rb: RegId) -> Self {
412 Self(pack::bytes_from_ra_rb($ra, $rb))
413 }
414 }
415
416 #[cfg(feature = "typescript")]
417 #[wasm_bindgen::prelude::wasm_bindgen]
418 impl $Op {
419 #[wasm_bindgen(constructor)]
420 pub fn new_typescript($ra: RegId, $rb: RegId) -> Self {
422 Self::new($ra, $rb)
423 }
424 }
425 };
426 ($Op:ident $ra:ident : RegId $rb:ident : RegId $rc:ident : RegId) => {
427 impl $Op {
428 pub fn new($ra: RegId, $rb: RegId, $rc: RegId) -> Self {
430 Self(pack::bytes_from_ra_rb_rc($ra, $rb, $rc))
431 }
432 }
433
434 #[cfg(feature = "typescript")]
435 #[wasm_bindgen::prelude::wasm_bindgen]
436 impl $Op {
437 #[wasm_bindgen(constructor)]
438 pub fn new_typescript($ra: RegId, $rb: RegId, $rc: RegId) -> Self {
440 Self::new($ra, $rb, $rc)
441 }
442 }
443 };
444 (
445 $Op:ident $ra:ident : RegId $rb:ident : RegId $rc:ident : RegId $rd:ident : RegId
446 ) => {
447 impl $Op {
448 pub fn new($ra: RegId, $rb: RegId, $rc: RegId, $rd: RegId) -> Self {
450 Self(pack::bytes_from_ra_rb_rc_rd($ra, $rb, $rc, $rd))
451 }
452 }
453
454 #[cfg(feature = "typescript")]
455 #[wasm_bindgen::prelude::wasm_bindgen]
456 impl $Op {
457 #[wasm_bindgen(constructor)]
458 pub fn new_typescript(
460 $ra: RegId,
461 $rb: RegId,
462 $rc: RegId,
463 $rd: RegId,
464 ) -> Self {
465 Self::new($ra, $rb, $rc, $rd)
466 }
467 }
468 };
469 (
470 $Op:ident
471 $ra:ident : RegId
472 $rb:ident : RegId
473 $rc:ident : RegId
474 $imm:ident : Imm06
475 ) => {
476 impl $Op {
477 pub fn new($ra: RegId, $rb: RegId, $rc: RegId, $imm: Imm06) -> Self {
479 Self(pack::bytes_from_ra_rb_rc_imm06($ra, $rb, $rc, $imm))
480 }
481 }
482
483 #[cfg(feature = "typescript")]
484 #[wasm_bindgen::prelude::wasm_bindgen]
485 impl $Op {
486 #[wasm_bindgen(constructor)]
487 pub fn new_typescript(
489 $ra: RegId,
490 $rb: RegId,
491 $rc: RegId,
492 $imm: Imm06,
493 ) -> Self {
494 Self::new($ra, $rb, $rc, $imm)
495 }
496 }
497 };
498 ($Op:ident $ra:ident : RegId $rb:ident : RegId $imm:ident : Imm12) => {
499 impl $Op {
500 pub fn new($ra: RegId, $rb: RegId, $imm: Imm12) -> Self {
502 Self(pack::bytes_from_ra_rb_imm12($ra, $rb, $imm))
503 }
504 }
505
506 #[cfg(feature = "typescript")]
507 #[wasm_bindgen::prelude::wasm_bindgen]
508 impl $Op {
509 #[wasm_bindgen(constructor)]
510 pub fn new_typescript($ra: RegId, $rb: RegId, $imm: Imm12) -> Self {
512 Self::new($ra, $rb, $imm)
513 }
514 }
515 };
516 ($Op:ident $ra:ident : RegId $imm:ident : Imm18) => {
517 impl $Op {
518 pub fn new($ra: RegId, $imm: Imm18) -> Self {
520 Self(pack::bytes_from_ra_imm18($ra, $imm))
521 }
522 }
523
524 #[cfg(feature = "typescript")]
525 #[wasm_bindgen::prelude::wasm_bindgen]
526 impl $Op {
527 #[wasm_bindgen(constructor)]
528 pub fn new_typescript($ra: RegId, $imm: Imm18) -> Self {
530 Self::new($ra, $imm)
531 }
532 }
533 };
534 ($Op:ident $imm:ident : Imm24) => {
535 impl $Op {
536 pub fn new($imm: Imm24) -> Self {
538 Self(pack::bytes_from_imm24($imm))
539 }
540 }
541
542 #[cfg(feature = "typescript")]
543 #[wasm_bindgen::prelude::wasm_bindgen]
544 impl $Op {
545 #[wasm_bindgen(constructor)]
546 pub fn new_typescript($imm: Imm24) -> Self {
548 Self::new($imm)
549 }
550 }
551 };
552 ($Op:ident) => {
553 impl $Op {
554 #[allow(clippy::new_without_default)]
556 pub fn new() -> Self {
557 Self([0; 3])
558 }
559 }
560
561 #[cfg(feature = "typescript")]
562 #[wasm_bindgen::prelude::wasm_bindgen]
563 impl $Op {
564 #[wasm_bindgen(constructor)]
565 #[allow(clippy::new_without_default)]
567 pub fn new_typescript() -> Self {
568 Self::new()
569 }
570 }
571 };
572}
573
574macro_rules! op_accessors {
576 ($Op:ident $ra:ident: RegId) => {
577 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
578 impl $Op {
579 pub fn ra(&self) -> RegId {
581 unpack::ra_from_bytes(self.0)
582 }
583 }
584 };
585 ($Op:ident $ra:ident: RegId $rb:ident: RegId) => {
586 op_accessors!($Op ra: RegId);
587
588 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
589 impl $Op {
590 pub fn rb(&self) -> RegId {
592 unpack::rb_from_bytes(self.0)
593 }
594 }
595 };
596 ($Op:ident $ra:ident: RegId $rb:ident: RegId $rc:ident: RegId) => {
597 op_accessors!($Op $ra: RegId $rb: RegId);
598
599 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
600 impl $Op {
601 pub fn rc(&self) -> RegId {
603 unpack::rc_from_bytes(self.0)
604 }
605 }
606 };
607 ($Op:ident $ra:ident: RegId $rb:ident: RegId $rc:ident: RegId $rd:ident: RegId) => {
608 op_accessors!($Op $ra: RegId $rb: RegId $rc: RegId);
609
610 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
611 impl $Op {
612 pub fn rd(&self) -> RegId {
614 unpack::rd_from_bytes(self.0)
615 }
616 }
617 };
618 ($Op:ident $ra:ident: RegId $rb:ident: RegId $rc:ident: RegId $imm:ident: Imm06) => {
619 op_accessors!($Op $ra: RegId rb: RegId $rc: RegId);
620
621 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
622 impl $Op {
623 pub fn imm06(&self) -> Imm06 {
625 unpack::imm06_from_bytes(self.0)
626 }
627 }
628 };
629 ($Op:ident $ra:ident: RegId $rb:ident: RegId $imm:ident: Imm12) => {
630 op_accessors!($Op $ra: RegId $rb: RegId);
631
632 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
633 impl $Op {
634 pub fn imm12(&self) -> Imm12 {
636 unpack::imm12_from_bytes(self.0)
637 }
638 }
639 };
640 ($Op:ident $ra:ident: RegId $imm:ident: Imm18) => {
641 op_accessors!($Op $ra: RegId);
642
643 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
644 impl $Op {
645 pub fn imm18(&self) -> Imm18 {
647 unpack::imm18_from_bytes(self.0)
648 }
649 }
650 };
651 ($Op:ident $ra:ident: Imm24) => {
652 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
653 impl $Op {
654 pub fn imm24(&self) -> Imm24 {
656 unpack::imm24_from_bytes(self.0)
657 }
658 }
659 };
660 ($Op:ident) => {};
661}
662
663macro_rules! op_unpack {
665 (RegId) => {
666 pub fn unpack(self) -> RegId {
668 unpack::ra_from_bytes(self.0)
669 }
670 };
671 (RegId RegId) => {
672 pub fn unpack(self) -> (RegId, RegId) {
674 unpack::ra_rb_from_bytes(self.0)
675 }
676 };
677 (RegId RegId RegId) => {
678 pub fn unpack(self) -> (RegId, RegId, RegId) {
680 unpack::ra_rb_rc_from_bytes(self.0)
681 }
682 };
683 (RegId RegId RegId RegId) => {
684 pub fn unpack(self) -> (RegId, RegId, RegId, RegId) {
686 unpack::ra_rb_rc_rd_from_bytes(self.0)
687 }
688 };
689 (RegId RegId RegId Imm06) => {
690 pub fn unpack(self) -> (RegId, RegId, RegId, Imm06) {
692 unpack::ra_rb_rc_imm06_from_bytes(self.0)
693 }
694 };
695 (RegId RegId Imm12) => {
696 pub fn unpack(self) -> (RegId, RegId, Imm12) {
698 unpack::ra_rb_imm12_from_bytes(self.0)
699 }
700 };
701 (RegId Imm18) => {
702 pub fn unpack(self) -> (RegId, Imm18) {
704 unpack::ra_imm18_from_bytes(self.0)
705 }
706 };
707 (Imm24) => {
708 pub fn unpack(self) -> Imm24 {
710 unpack::imm24_from_bytes(self.0)
711 }
712 };
713 () => {};
714}
715
716macro_rules! op_reserved_part {
720 (RegId) => {
721 pub(crate) fn reserved_part_is_zero(self) -> bool {
722 let (_, imm) = unpack::ra_imm18_from_bytes(self.0);
723 imm.0 == 0
724 }
725 };
726 (RegId RegId) => {
727 pub(crate) fn reserved_part_is_zero(self) -> bool {
728 let (_, _, imm) = unpack::ra_rb_imm12_from_bytes(self.0);
729 imm.0 == 0
730 }
731 };
732 (RegId RegId RegId) => {
733 pub(crate) fn reserved_part_is_zero(self) -> bool {
734 let (_, _, _, imm) = unpack::ra_rb_rc_imm06_from_bytes(self.0);
735 imm.0 == 0
736 }
737 };
738 (RegId RegId RegId RegId) => {
739 pub(crate) fn reserved_part_is_zero(self) -> bool {
740 true
741 }
742 };
743 (RegId RegId RegId Imm06) => {
744 pub(crate) fn reserved_part_is_zero(self) -> bool {
745 true
746 }
747 };
748 (RegId RegId Imm12) => {
749 pub(crate) fn reserved_part_is_zero(self) -> bool {
750 true
751 }
752 };
753 (RegId Imm18) => {
754 pub(crate) fn reserved_part_is_zero(self) -> bool {
755 true
756 }
757 };
758 (Imm24) => {
759 pub(crate) fn reserved_part_is_zero(self) -> bool {
760 true
761 }
762 };
763 () => {
764 pub(crate) fn reserved_part_is_zero(self) -> bool {
765 self.0 == [0; 3]
766 }
767 };
768}
769
770macro_rules! op_reg_ids {
772 (RegId) => {
773 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
774 let ra = self.unpack();
775 [Some(ra), None, None, None]
776 }
777 };
778 (RegId RegId) => {
779 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
780 let (ra, rb) = self.unpack();
781 [Some(ra), Some(rb), None, None]
782 }
783 };
784 (RegId RegId RegId) => {
785 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
786 let (ra, rb, rc) = self.unpack();
787 [Some(ra), Some(rb), Some(rc), None]
788 }
789 };
790 (RegId RegId RegId RegId) => {
791 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
792 let (ra, rb, rc, rd) = self.unpack();
793 [Some(ra), Some(rb), Some(rc), Some(rd)]
794 }
795 };
796 (RegId RegId RegId Imm06) => {
797 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
798 let (ra, rb, rc, _) = self.unpack();
799 [Some(ra), Some(rb), Some(rc), None]
800 }
801 };
802 (RegId RegId Imm12) => {
803 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
804 let (ra, rb, _) = self.unpack();
805 [Some(ra), Some(rb), None, None]
806 }
807 };
808 (RegId Imm18) => {
809 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
810 let (ra, _) = self.unpack();
811 [Some(ra), None, None, None]
812 }
813 };
814 ($($rest:tt)*) => {
815 pub(super) fn reg_ids(&self) -> [Option<RegId>; 4] {
816 [None; 4]
817 }
818 };
819}
820
821#[cfg(test)]
824macro_rules! op_test_construct_fn {
825 (RegId) => {
826 pub fn test_construct(
829 ra: RegId,
830 _rb: RegId,
831 _rc: RegId,
832 _rd: RegId,
833 _imm: u32,
834 ) -> Self {
835 Self(pack::bytes_from_ra(ra))
836 }
837 };
838 (RegId RegId) => {
839 pub fn test_construct(
842 ra: RegId,
843 rb: RegId,
844 _rc: RegId,
845 _rd: RegId,
846 _imm: u32,
847 ) -> Self {
848 Self(pack::bytes_from_ra_rb(ra, rb))
849 }
850 };
851 (RegId RegId RegId) => {
852 pub fn test_construct(
855 ra: RegId,
856 rb: RegId,
857 rc: RegId,
858 _rd: RegId,
859 _imm: u32,
860 ) -> Self {
861 Self(pack::bytes_from_ra_rb_rc(ra, rb, rc))
862 }
863 };
864 (RegId RegId RegId RegId) => {
865 pub fn test_construct(
868 ra: RegId,
869 rb: RegId,
870 rc: RegId,
871 rd: RegId,
872 _imm: u32,
873 ) -> Self {
874 Self(pack::bytes_from_ra_rb_rc_rd(ra, rb, rc, rd))
875 }
876 };
877 (RegId RegId RegId Imm06) => {
878 pub fn test_construct(
881 ra: RegId,
882 rb: RegId,
883 rc: RegId,
884 _rd: RegId,
885 imm: u32,
886 ) -> Self {
887 Self(pack::bytes_from_ra_rb_rc_imm06(
888 ra,
889 rb,
890 rc,
891 Imm06::from(imm as u8),
892 ))
893 }
894 };
895 (RegId RegId Imm12) => {
896 pub fn test_construct(
899 ra: RegId,
900 rb: RegId,
901 _rc: RegId,
902 _rd: RegId,
903 imm: u32,
904 ) -> Self {
905 Self(pack::bytes_from_ra_rb_imm12(
906 ra,
907 rb,
908 Imm12::from(imm as u16),
909 ))
910 }
911 };
912 (RegId Imm18) => {
913 pub fn test_construct(
916 ra: RegId,
917 _rb: RegId,
918 _rc: RegId,
919 _rd: RegId,
920 imm: u32,
921 ) -> Self {
922 Self(pack::bytes_from_ra_imm18(ra, Imm18::from(imm)))
923 }
924 };
925 (Imm24) => {
926 pub fn test_construct(
929 _ra: RegId,
930 _rb: RegId,
931 _rc: RegId,
932 _rd: RegId,
933 imm: u32,
934 ) -> Self {
935 Self(pack::bytes_from_imm24(Imm24::from(imm)))
936 }
937 };
938 () => {
939 #[allow(clippy::new_without_default)]
942 pub fn test_construct(
943 _ra: RegId,
944 _rb: RegId,
945 _rc: RegId,
946 _rd: RegId,
947 _imm: u32,
948 ) -> Self {
949 Self([0; 3])
950 }
951 };
952}
953
954macro_rules! op_debug_fmt {
956 ($Op:ident[$ra:ident : RegId]) => {
957 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
958 let ra = self.unpack();
959 f.debug_struct(stringify!($Op))
960 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
961 .finish()
962 }
963 };
964 ($Op:ident[$ra:ident : RegId $rb:ident : RegId]) => {
965 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
966 let (ra, rb) = self.unpack();
967 f.debug_struct(stringify!($Op))
968 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
969 .field(stringify!($rb), &format_args!("{:#02x}", u8::from(rb)))
970 .finish()
971 }
972 };
973 ($Op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId]) => {
974 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
975 let (ra, rb, rc) = self.unpack();
976 f.debug_struct(stringify!($Op))
977 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
978 .field(stringify!($rb), &format_args!("{:#02x}", u8::from(rb)))
979 .field(stringify!($rc), &format_args!("{:#02x}", u8::from(rc)))
980 .finish()
981 }
982 };
983 (
984 $Op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId $rd:ident : RegId]
985 ) => {
986 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
987 let (ra, rb, rc, rd) = self.unpack();
988 f.debug_struct(stringify!($Op))
989 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
990 .field(stringify!($rb), &format_args!("{:#02x}", u8::from(rb)))
991 .field(stringify!($rc), &format_args!("{:#02x}", u8::from(rc)))
992 .field(stringify!($rd), &format_args!("{:#02x}", u8::from(rd)))
993 .finish()
994 }
995 };
996 (
997 $Op:ident[$ra:ident : RegId $rb:ident : RegId $rc:ident : RegId $imm:ident : Imm06]
998 ) => {
999 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1000 let (ra, rb, rc, imm) = self.unpack();
1001 f.debug_struct(stringify!($Op))
1002 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
1003 .field(stringify!($rb), &format_args!("{:#02x}", u8::from(rb)))
1004 .field(stringify!($rc), &format_args!("{:#02x}", u8::from(rc)))
1005 .field(stringify!($imm), &u8::from(imm))
1006 .finish()
1007 }
1008 };
1009 ($Op:ident[$ra:ident : RegId $rb:ident : RegId $imm:ident : Imm12]) => {
1010 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1011 let (ra, rb, imm) = self.unpack();
1012 f.debug_struct(stringify!($Op))
1013 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
1014 .field(stringify!($rb), &format_args!("{:#02x}", u8::from(rb)))
1015 .field(stringify!($imm), &u16::from(imm))
1016 .finish()
1017 }
1018 };
1019 ($Op:ident[$ra:ident : RegId $imm:ident : Imm18]) => {
1020 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1021 let (ra, imm) = self.unpack();
1022 f.debug_struct(stringify!($Op))
1023 .field(stringify!($ra), &format_args!("{:#02x}", u8::from(ra)))
1024 .field(stringify!($imm), &u32::from(imm))
1025 .finish()
1026 }
1027 };
1028 ($Op:ident[$imm:ident : Imm24]) => {
1029 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1030 let imm = self.unpack();
1031 f.debug_struct(stringify!($Op))
1032 .field(stringify!($imm), &u32::from(imm))
1033 .finish()
1034 }
1035 };
1036 ($Op:ident[]) => {
1037 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1038 f.debug_struct(stringify!($Op)).finish()
1039 }
1040 };
1041}
1042
1043macro_rules! decl_op_struct {
1045 ($doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*] $($rest:tt)*) => {
1046 #[doc = $doc]
1047 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
1048 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1049 #[cfg_attr(feature = "typescript", wasm_bindgen::prelude::wasm_bindgen)]
1050 pub struct $Op(pub (super) [u8; 3]);
1051 decl_op_struct!($($rest)*);
1052 };
1053 () => {};
1054}
1055
1056macro_rules! impl_instructions {
1059 (decl_opcode_enum $($doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*])*) => {
1061 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1063 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1064 #[repr(u8)]
1065 pub enum Opcode {
1066 $(
1067 #[doc = $doc]
1068 $Op = $ix,
1069 )*
1070 }
1071 };
1072
1073 (decl_instruction_enum $($doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*])*) => {
1075 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
1083 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1084 pub enum Instruction {
1085 $(
1086 #[doc = $doc]
1087 $Op(op::$Op),
1088 )*
1089 }
1090 };
1091
1092 (impl_opcode_test_construct $doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*] $($rest:tt)*) => {
1094 #[cfg(test)]
1095 #[allow(clippy::cast_possible_truncation)]
1096 impl crate::_op::$Op {
1097 op_test_construct_fn!($($field)*);
1098 }
1099 impl_instructions!(impl_opcode_test_construct $($rest)*);
1100 };
1101 (impl_opcode_test_construct) => {};
1102
1103 (tests $doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*] $($rest:tt)*) => {
1105 op_test!($Op $op [$($field)*]);
1106 impl_instructions!(tests $($rest)*);
1107 };
1108 (tests) => {};
1109
1110 (impl_op $doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*] $($rest:tt)*) => {
1112 impl $Op {
1113 pub const OPCODE: Opcode = Opcode::$Op;
1115 }
1116
1117 op_new!($Op $($fname: $field)*);
1118 op_accessors!($Op $($fname: $field)*);
1119
1120 impl $Op {
1121 op_unpack!($($field)*);
1122 op_reserved_part!($($field)*);
1123 op_reg_ids!($($field)*);
1124 }
1125
1126 op_constructor!($doc $Op $op [$($fname: $field)*]);
1127
1128 impl From<$Op> for [u8; 3] {
1129 fn from($Op(arr): $Op) -> Self {
1130 arr
1131 }
1132 }
1133
1134 impl From<$Op> for [u8; 4] {
1135 fn from($Op([a, b, c]): $Op) -> Self {
1136 [$Op::OPCODE as u8, a, b, c]
1137 }
1138 }
1139
1140 impl From<$Op> for u32 {
1141 fn from(op: $Op) -> Self {
1142 u32::from_be_bytes(op.into())
1143 }
1144 }
1145
1146 impl From<$Op> for Instruction {
1147 fn from(op: $Op) -> Self {
1148 Instruction::$Op(op)
1149 }
1150 }
1151
1152 #[cfg(feature = "typescript")]
1153 impl From<$Op> for typescript::Instruction {
1154 fn from(opcode: $Op) -> Self {
1155 typescript::Instruction::new(opcode.into())
1156 }
1157 }
1158
1159 impl core::fmt::Debug for $Op {
1160 op_debug_fmt!($Op [$($fname: $field)*]);
1161 }
1162
1163 impl_instructions!(impl_op $($rest)*);
1164 };
1165 (impl_op) => {};
1166
1167 (impl_opcode $($doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*])*) => {
1169 impl core::convert::TryFrom<u8> for Opcode {
1170 type Error = InvalidOpcode;
1171 fn try_from(u: u8) -> Result<Self, Self::Error> {
1172 match u {
1173 $(
1174 $ix => Ok(Opcode::$Op),
1175 )*
1176 _ => Err(InvalidOpcode),
1177 }
1178 }
1179 }
1180
1181 impl Opcode {
1182 #[cfg(test)]
1184 pub fn test_construct(self, ra: RegId, rb: RegId, rc: RegId, rd: RegId, imm: u32) -> Instruction {
1185 match self {
1186 $(
1187 Self::$Op => Instruction::$Op(crate::_op::$Op::test_construct(ra, rb, rc, rd, imm)),
1188 )*
1189 }
1190 }
1191 }
1192 };
1193
1194 (impl_instruction $($doc:literal $ix:literal $Op:ident $op:ident [$($fname:ident: $field:ident)*])*) => {
1196 impl Instruction {
1197 pub fn opcode(&self) -> Opcode {
1199 match self {
1200 $(
1201 Self::$Op(_) => Opcode::$Op,
1202 )*
1203 }
1204 }
1205
1206 pub fn reg_ids(&self) -> [Option<RegId>; 4] {
1208 match self {
1209 $(
1210 Self::$Op(op) => op.reg_ids(),
1211 )*
1212 }
1213 }
1214 }
1215
1216 impl From<Instruction> for [u8; 4] {
1217 fn from(inst: Instruction) -> Self {
1218 match inst {
1219 $(
1220 Instruction::$Op(op) => op.into(),
1221 )*
1222 }
1223 }
1224 }
1225
1226 #[cfg(feature = "typescript")]
1227 impl From<Instruction> for typescript::Instruction {
1228 fn from(inst: Instruction) -> Self {
1229 typescript::Instruction::new(inst)
1230 }
1231 }
1232
1233 impl core::convert::TryFrom<[u8; 4]> for Instruction {
1234 type Error = InvalidOpcode;
1235 fn try_from([op, a, b, c]: [u8; 4]) -> Result<Self, Self::Error> {
1236 match Opcode::try_from(op)? {
1237 $(
1238 Opcode::$Op => Ok(Self::$Op({
1239 let op = op::$Op([a, b, c]);
1240 if !op.reserved_part_is_zero() {
1241 return Err(InvalidOpcode);
1242 }
1243 op
1244 })),
1245 )*
1246 }
1247 }
1248 }
1249
1250 impl core::fmt::Debug for Instruction {
1251 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
1252 match self {
1253 $(
1254 Self::$Op(op) => op.fmt(f),
1255 )*
1256 }
1257 }
1258 }
1259 };
1260
1261 ($($tts:tt)*) => {
1264 mod _op {
1265 use super::*;
1266 decl_op_struct!($($tts)*);
1267 impl_instructions!(impl_op $($tts)*);
1268 }
1269 impl_instructions!(decl_opcode_enum $($tts)*);
1270 impl_instructions!(decl_instruction_enum $($tts)*);
1271 impl_instructions!(impl_opcode $($tts)*);
1272 impl_instructions!(impl_instruction $($tts)*);
1273 impl_instructions!(impl_opcode_test_construct $($tts)*);
1274
1275
1276 #[cfg(test)]
1277 mod opcode_tests {
1278 use super::*;
1279 impl_instructions!(tests $($tts)*);
1280 }
1281 };
1282}
1283
1284#[macro_export]
1286macro_rules! enum_try_from {
1287 (
1288 $(#[$meta:meta])* $vis:vis enum $name:ident {
1289 $($(#[$vmeta:meta])* $vname:ident $(= $val:expr)?,)*
1290 },
1291 $from:ident
1292 ) => {
1293 $(#[$meta])*
1294 $vis enum $name {
1295 $($(#[$vmeta])* $vname $(= $val)?,)*
1296 }
1297
1298 impl core::convert::TryFrom<$from> for $name {
1299 type Error = $crate::PanicReason;
1300
1301 fn try_from(v: $from) -> Result<Self, Self::Error> {
1302 match v {
1303 $(x if x == $name::$vname as $from => Ok($name::$vname),)*
1304 _ => Err($crate::PanicReason::InvalidMetadataIdentifier),
1305 }
1306 }
1307 }
1308 }
1309}
1310
1311#[cfg(test)]
1312macro_rules! op_test {
1314 ($Op:ident $op:ident[RegId]) => {
1315 #[test]
1316 fn $op() {
1317 crate::macros::test_reserved_part(Opcode::$Op, true, false, false, false);
1318 }
1319 };
1320 ($Op:ident $op:ident[RegId RegId]) => {
1321 #[test]
1322 fn $op() {
1323 crate::macros::test_reserved_part(Opcode::$Op, true, true, false, false);
1324 }
1325 };
1326 ($Op:ident $op:ident[RegId RegId RegId]) => {
1327 #[test]
1328 fn $op() {
1329 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, false);
1330 }
1331 };
1332 ($Op:ident $op:ident[RegId RegId RegId RegId]) => {
1333 #[test]
1334 fn $op() {
1335 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, true);
1336 }
1337 };
1338 ($Op:ident $op:ident[RegId RegId RegId Imm06]) => {
1339 #[test]
1340 fn $op() {
1341 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, true);
1342 }
1343 };
1344 ($Op:ident $op:ident[RegId RegId Imm12]) => {
1345 #[test]
1346 fn $op() {
1347 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, true);
1348 }
1349 };
1350 ($Op:ident $op:ident[RegId Imm18]) => {
1351 #[test]
1352 fn $op() {
1353 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, true);
1354 }
1355 };
1356 ($Op:ident $op:ident[Imm24]) => {
1357 #[test]
1358 fn $op() {
1359 crate::macros::test_reserved_part(Opcode::$Op, true, true, true, true);
1360 }
1361 };
1362 ($Op:ident $op:ident[]) => {
1363 #[test]
1364 fn $op() {
1365 crate::macros::test_reserved_part(Opcode::$Op, false, false, false, false);
1366 }
1367 };
1368}
1369
1370#[cfg(test)]
1371fn bytes(a: u8, b: u8, c: u8, d: u8) -> [u8; 3] {
1372 use crate::RegId;
1373 crate::pack::bytes_from_ra_rb_rc_rd(
1374 RegId::new(a),
1375 RegId::new(b),
1376 RegId::new(c),
1377 RegId::new(d),
1378 )
1379}
1380
1381#[cfg(test)]
1382pub(crate) fn test_reserved_part(
1383 opcode: crate::Opcode,
1384 zero_should_pass: bool,
1385 first_should_pass: bool,
1386 second_should_pass: bool,
1387 third_should_pass: bool,
1388) {
1389 use crate::Instruction;
1390
1391 let [a, b, c] = bytes(0, 0, 0, 0);
1393 Instruction::try_from([opcode as u8, a, b, c]).unwrap();
1394 let [a, b, c] = bytes(1, 0, 0, 0);
1395 let zero_is_error = Instruction::try_from([opcode as u8, a, b, c]).is_ok();
1396 assert_eq!(
1397 zero_should_pass, zero_is_error,
1398 "Opcode: {opcode:?} failed zero"
1399 );
1400
1401 let [a, b, c] = bytes(0, 0, 0, 0);
1403 Instruction::try_from([opcode as u8, a, b, c]).unwrap();
1404 let [a, b, c] = bytes(0, 1, 0, 0);
1405 let first_is_error = Instruction::try_from([opcode as u8, a, b, c]).is_ok();
1406 assert_eq!(
1407 first_should_pass, first_is_error,
1408 "Opcode: {opcode:?} failed first"
1409 );
1410
1411 let [a, b, c] = bytes(0, 0, 0, 0);
1413 Instruction::try_from([opcode as u8, a, b, c]).unwrap();
1414 let [a, b, c] = bytes(0, 0, 1, 0);
1415 let second_is_error = Instruction::try_from([opcode as u8, a, b, c]).is_ok();
1416 assert_eq!(
1417 second_should_pass, second_is_error,
1418 "Opcode: {opcode:?} failed second"
1419 );
1420
1421 let [a, b, c] = bytes(0, 0, 0, 0);
1423 Instruction::try_from([opcode as u8, a, b, c]).unwrap();
1424 let [a, b, c] = bytes(0, 0, 0, 1);
1425 let third_is_error = Instruction::try_from([opcode as u8, a, b, c]).is_ok();
1426 assert_eq!(
1427 third_should_pass, third_is_error,
1428 "Opcode: {opcode:?} failed third"
1429 );
1430}