1use std::collections::HashMap;
7use std::fmt::Write;
8
9use crate::tree::DecodeNode;
10use crate::types::*;
11
12fn needs_variable_length_decode(def: &ValidatedDef) -> bool {
14 def.instructions.iter().any(|i| i.unit_count() > 1)
15}
16
17pub fn generate_code(
24 def: &ValidatedDef,
25 tree: &DecodeNode,
26 type_maps: &HashMap<String, String>,
27 dispatch_overrides: &HashMap<String, crate::Dispatch>,
28) -> String {
29 let mut out = String::new();
30
31 writeln!(out, "// Auto-generated by https://github.com/ioncodes/chipi").unwrap();
32 writeln!(out, "// Do not edit.").unwrap();
33 writeln!(out).unwrap();
34 writeln!(out, "use std::fmt;").unwrap();
35 writeln!(out, "use std::marker::PhantomData;").unwrap();
36 writeln!(out).unwrap();
37
38 let mut import_paths: Vec<&str> = type_maps.values().map(|v| v.as_str()).collect();
40 import_paths.sort();
41 import_paths.dedup();
42 for path in &import_paths {
43 if path.contains("::") {
45 writeln!(out, "use {};", path).unwrap();
46 }
47 }
48 if !import_paths.is_empty() {
49 writeln!(out).unwrap();
50 }
51
52 let word_type = word_type_for_width(def.config.width);
53 let unit_bytes = def.config.width / 8;
54 let variable_length = needs_variable_length_decode(def);
55 let enum_name = format!("{}Instruction", def.config.name);
56 let trait_name = format!("{}Format", def.config.name);
57 let default_struct = format!("Default{}Format", def.config.name);
58 let display_with = "DisplayWith";
59 let endian_suffix = match def.config.endian {
60 ByteEndian::Big => "be",
61 ByteEndian::Little => "le",
62 };
63
64 generate_display_helpers(&mut out, def);
66
67 generate_map_functions(&mut out, def);
69
70 for sd in &def.sub_decoders {
72 let dispatch = dispatch_overrides
73 .get(&sd.name)
74 .copied()
75 .unwrap_or(crate::Dispatch::FnPtrLut);
76 generate_subdecoder(&mut out, sd, dispatch);
77 }
78
79 writeln!(out, "#[derive(Debug, Clone, Copy, PartialEq, Eq)]").unwrap();
81 writeln!(out, "pub enum {} {{", enum_name).unwrap();
82
83 for instr in &def.instructions {
84 let variant_name = to_pascal_case(&instr.name);
85 if instr.resolved_fields.is_empty() {
86 writeln!(out, " {},", variant_name).unwrap();
87 } else {
88 let fields: Vec<String> = instr
89 .resolved_fields
90 .iter()
91 .map(|f| {
92 let rust_type = field_rust_type_with_maps(f, &type_maps);
93 format!("{}: {}", f.name, rust_type)
94 })
95 .collect();
96 writeln!(out, " {} {{ {} }},", variant_name, fields.join(", ")).unwrap();
97 }
98 }
99
100 writeln!(out, "}}").unwrap();
101 writeln!(out).unwrap();
102
103 generate_format_trait(&mut out, def, &trait_name, type_maps);
105
106 writeln!(out, "impl {} {{", enum_name).unwrap();
108 writeln!(out, " #[inline]").unwrap();
109
110 writeln!(
112 out,
113 " pub fn decode(data: &[u8]) -> Option<(Self, usize)> {{"
114 )
115 .unwrap();
116 writeln!(
117 out,
118 " if data.len() < {} {{ return None; }}",
119 unit_bytes
120 )
121 .unwrap();
122 writeln!(
123 out,
124 " let opcode = {}::from_{}_bytes(data[0..{}].try_into().unwrap());",
125 word_type, endian_suffix, unit_bytes
126 )
127 .unwrap();
128
129 emit_tree(
130 &mut out,
131 tree,
132 def,
133 &enum_name,
134 2,
135 variable_length,
136 &word_type,
137 type_maps,
138 );
139
140 writeln!(out, " }}").unwrap();
141 writeln!(out).unwrap();
142
143 generate_write_asm(&mut out, def, &enum_name, &trait_name);
145
146 writeln!(out).unwrap();
148 writeln!(out, " #[allow(dead_code)]").unwrap();
149 writeln!(
150 out,
151 " pub fn display<F: {}>(&self) -> {}<'_, F> {{",
152 trait_name, display_with
153 )
154 .unwrap();
155 writeln!(
156 out,
157 " {} {{ insn: self, _phantom: PhantomData }}",
158 display_with
159 )
160 .unwrap();
161 writeln!(out, " }}").unwrap();
162
163 writeln!(out, "}}").unwrap();
164 writeln!(out).unwrap();
165
166 writeln!(out, "#[allow(dead_code)]").unwrap();
168 writeln!(out, "pub struct {}<'a, F: {}> {{", display_with, trait_name).unwrap();
169 writeln!(out, " insn: &'a {},", enum_name).unwrap();
170 writeln!(out, " _phantom: PhantomData<F>,").unwrap();
171 writeln!(out, "}}").unwrap();
172 writeln!(out).unwrap();
173
174 writeln!(
175 out,
176 "impl<F: {}> fmt::Display for {}<'_, F> {{",
177 trait_name, display_with
178 )
179 .unwrap();
180 writeln!(
181 out,
182 " fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{"
183 )
184 .unwrap();
185 writeln!(out, " self.insn.write_asm::<F>(f)").unwrap();
186 writeln!(out, " }}").unwrap();
187 writeln!(out, "}}").unwrap();
188 writeln!(out).unwrap();
189
190 writeln!(out, "pub struct {};", default_struct).unwrap();
192 writeln!(out, "impl {} for {} {{}}", trait_name, default_struct).unwrap();
193 writeln!(out).unwrap();
194
195 writeln!(out, "impl fmt::Display for {} {{", enum_name).unwrap();
197 writeln!(
198 out,
199 " fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{"
200 )
201 .unwrap();
202 writeln!(out, " self.write_asm::<{}>(f)", default_struct).unwrap();
203 writeln!(out, " }}").unwrap();
204 writeln!(out, "}}").unwrap();
205
206 out
207}
208
209fn emit_tree(
211 out: &mut String,
212 node: &DecodeNode,
213 def: &ValidatedDef,
214 enum_name: &str,
215 indent: usize,
216 variable_length: bool,
217 word_type: &str,
218 type_maps: &HashMap<String, String>,
219) {
220 let unit_bytes = def.config.width / 8;
221 let endian_suffix = match def.config.endian {
222 ByteEndian::Big => "be",
223 ByteEndian::Little => "le",
224 };
225 let pad = " ".repeat(indent);
226 match node {
227 DecodeNode::Leaf { instruction_index } => {
228 let instr = &def.instructions[*instruction_index];
229 if let Some(guard) = leaf_guard(instr, word_type, unit_bytes, endian_suffix) {
230 writeln!(out, "{}if {} {{", pad, guard).unwrap();
231 emit_some(
232 out,
233 instr,
234 enum_name,
235 &format!("{} ", pad),
236 variable_length,
237 word_type,
238 unit_bytes,
239 endian_suffix,
240 &type_maps,
241 );
242 writeln!(out, "{}}} else {{", pad).unwrap();
243 writeln!(out, "{} None", pad).unwrap();
244 writeln!(out, "{}}}", pad).unwrap();
245 } else {
246 emit_some(
247 out,
248 instr,
249 enum_name,
250 &pad,
251 variable_length,
252 word_type,
253 unit_bytes,
254 endian_suffix,
255 &type_maps,
256 );
257 }
258 }
259 DecodeNode::PriorityLeaves { candidates } => {
260 for (i, &idx) in candidates.iter().enumerate() {
262 let instr = &def.instructions[idx];
263 let guard = leaf_guard(instr, word_type, unit_bytes, endian_suffix);
264
265 if i == 0 {
266 if let Some(guard_expr) = guard {
268 writeln!(out, "{}if {} {{", pad, guard_expr).unwrap();
269 emit_some(
270 out,
271 instr,
272 enum_name,
273 &format!("{} ", pad),
274 variable_length,
275 word_type,
276 unit_bytes,
277 endian_suffix,
278 &type_maps,
279 );
280 } else {
281 emit_some(
283 out,
284 instr,
285 enum_name,
286 &pad,
287 variable_length,
288 word_type,
289 unit_bytes,
290 endian_suffix,
291 &type_maps,
292 );
293 break; }
295 } else if i == candidates.len() - 1 {
296 writeln!(out, "{}}} else {{", pad).unwrap();
298 if let Some(guard_expr) = guard {
299 writeln!(out, "{} if {} {{", pad, guard_expr).unwrap();
300 emit_some(
301 out,
302 instr,
303 enum_name,
304 &format!("{} ", pad),
305 variable_length,
306 word_type,
307 unit_bytes,
308 endian_suffix,
309 &type_maps,
310 );
311 writeln!(out, "{} }} else {{", pad).unwrap();
312 writeln!(out, "{} None", pad).unwrap();
313 writeln!(out, "{} }}", pad).unwrap();
314 } else {
315 emit_some(
316 out,
317 instr,
318 enum_name,
319 &format!("{} ", pad),
320 variable_length,
321 word_type,
322 unit_bytes,
323 endian_suffix,
324 &type_maps,
325 );
326 }
327 writeln!(out, "{}}}", pad).unwrap();
328 } else {
329 writeln!(
331 out,
332 "{}}} else if {} {{",
333 pad,
334 guard.unwrap_or_else(|| "true".to_string())
335 )
336 .unwrap();
337 emit_some(
338 out,
339 instr,
340 enum_name,
341 &format!("{} ", pad),
342 variable_length,
343 word_type,
344 unit_bytes,
345 endian_suffix,
346 &type_maps,
347 );
348 }
349 }
350 }
351 DecodeNode::Fail => {
352 writeln!(out, "{}None", pad).unwrap();
353 }
354 DecodeNode::Branch {
355 range,
356 arms,
357 default,
358 } => {
359 let extract_expr =
360 extract_expression("opcode", &[*range], word_type, unit_bytes, endian_suffix);
361 writeln!(out, "{}match {} {{", pad, extract_expr).unwrap();
362
363 for (value, child) in arms {
364 emit_arm(
365 out,
366 child,
367 def,
368 enum_name,
369 indent + 1,
370 &format!("{:#x}", value),
371 variable_length,
372 word_type,
373 type_maps,
374 );
375 }
376
377 emit_arm(
378 out,
379 default,
380 def,
381 enum_name,
382 indent + 1,
383 "_",
384 variable_length,
385 word_type,
386 type_maps,
387 );
388
389 writeln!(out, "{}}}", pad).unwrap();
390 }
391 }
392}
393
394fn emit_arm(
396 out: &mut String,
397 node: &DecodeNode,
398 def: &ValidatedDef,
399 enum_name: &str,
400 indent: usize,
401 pattern: &str,
402 variable_length: bool,
403 word_type: &str,
404 type_maps: &HashMap<String, String>,
405) {
406 let unit_bytes = def.config.width / 8;
407 let endian_suffix = match def.config.endian {
408 ByteEndian::Big => "be",
409 ByteEndian::Little => "le",
410 };
411 let pad = " ".repeat(indent);
412 match node {
413 DecodeNode::Fail => {
414 writeln!(out, "{}{} => None,", pad, pattern).unwrap();
415 }
416 DecodeNode::Leaf { instruction_index } => {
417 let instr = &def.instructions[*instruction_index];
418 if let Some(guard) = leaf_guard(instr, word_type, unit_bytes, endian_suffix) {
419 if pattern == "_" {
420 write!(out, "{}{} if {} => ", pad, pattern, guard).unwrap();
422 emit_some_inline(
423 out,
424 instr,
425 enum_name,
426 variable_length,
427 word_type,
428 unit_bytes,
429 endian_suffix,
430 &type_maps,
431 );
432 writeln!(out, "{}{} => None,", pad, pattern).unwrap();
433 } else {
434 write!(out, "{}{} if {} => ", pad, pattern, guard).unwrap();
435 emit_some_inline(
436 out,
437 instr,
438 enum_name,
439 variable_length,
440 word_type,
441 unit_bytes,
442 endian_suffix,
443 &type_maps,
444 );
445 }
446 } else {
447 write!(out, "{}{} => ", pad, pattern).unwrap();
448 emit_some_inline(
449 out,
450 instr,
451 enum_name,
452 variable_length,
453 word_type,
454 unit_bytes,
455 endian_suffix,
456 &type_maps,
457 );
458 }
459 }
460 DecodeNode::PriorityLeaves { candidates } => {
461 writeln!(out, "{}{} => {{", pad, pattern).unwrap();
463 let inner_pad = " ".repeat(indent + 1);
464
465 for (i, &idx) in candidates.iter().enumerate() {
466 let instr = &def.instructions[idx];
467 let guard = leaf_guard(instr, word_type, unit_bytes, endian_suffix);
468
469 if i == 0 {
470 if let Some(guard_expr) = guard {
472 writeln!(out, "{}if {} {{", inner_pad, guard_expr).unwrap();
473 emit_some(
474 out,
475 instr,
476 enum_name,
477 &format!("{} ", inner_pad),
478 variable_length,
479 word_type,
480 unit_bytes,
481 endian_suffix,
482 &type_maps,
483 );
484 } else {
485 emit_some(
487 out,
488 instr,
489 enum_name,
490 &inner_pad,
491 variable_length,
492 word_type,
493 unit_bytes,
494 endian_suffix,
495 &type_maps,
496 );
497 writeln!(out, "{}}}", pad).unwrap();
498 return;
499 }
500 } else if i == candidates.len() - 1 {
501 writeln!(out, "{}}} else {{", inner_pad).unwrap();
503 if let Some(guard_expr) = guard {
504 writeln!(out, "{} if {} {{", inner_pad, guard_expr).unwrap();
505 emit_some(
506 out,
507 instr,
508 enum_name,
509 &format!("{} ", inner_pad),
510 variable_length,
511 word_type,
512 unit_bytes,
513 endian_suffix,
514 &type_maps,
515 );
516 writeln!(out, "{} }} else {{", inner_pad).unwrap();
517 writeln!(out, "{} None", inner_pad).unwrap();
518 writeln!(out, "{} }}", inner_pad).unwrap();
519 } else {
520 emit_some(
521 out,
522 instr,
523 enum_name,
524 &format!("{} ", inner_pad),
525 variable_length,
526 word_type,
527 unit_bytes,
528 endian_suffix,
529 &type_maps,
530 );
531 }
532 writeln!(out, "{}}}", inner_pad).unwrap();
533 writeln!(out, "{}}}", pad).unwrap();
534 } else {
535 writeln!(
537 out,
538 "{}}} else if {} {{",
539 inner_pad,
540 guard.unwrap_or_else(|| "true".to_string())
541 )
542 .unwrap();
543 emit_some(
544 out,
545 instr,
546 enum_name,
547 &format!("{} ", inner_pad),
548 variable_length,
549 word_type,
550 unit_bytes,
551 endian_suffix,
552 &type_maps,
553 );
554 }
555 }
556 }
557 DecodeNode::Branch {
558 range,
559 arms,
560 default,
561 } => {
562 writeln!(out, "{}{} => {{", pad, pattern).unwrap();
563 let extract_expr =
564 extract_expression("opcode", &[*range], word_type, unit_bytes, endian_suffix);
565 let inner_pad = " ".repeat(indent + 1);
566 writeln!(out, "{}match {} {{", inner_pad, extract_expr).unwrap();
567
568 for (value, child) in arms {
569 emit_arm(
570 out,
571 child,
572 def,
573 enum_name,
574 indent + 2,
575 &format!("{:#x}", value),
576 variable_length,
577 word_type,
578 type_maps,
579 );
580 }
581
582 emit_arm(
583 out,
584 default,
585 def,
586 enum_name,
587 indent + 2,
588 "_",
589 variable_length,
590 word_type,
591 type_maps,
592 );
593
594 writeln!(out, "{}}}", inner_pad).unwrap();
595 writeln!(out, "{}}}", pad).unwrap();
596 }
597 }
598}
599
600fn leaf_guard(
604 instr: &ValidatedInstruction,
605 word_type: &str,
606 unit_bytes: u32,
607 endian_suffix: &str,
608) -> Option<String> {
609 let fixed_bits = instr.fixed_bits();
610 if fixed_bits.is_empty() {
611 return None;
612 }
613
614 let mut units_map: std::collections::HashMap<u32, Vec<(u32, Bit)>> =
616 std::collections::HashMap::new();
617 for (unit, hw_bit, bit) in fixed_bits {
618 units_map.entry(unit).or_default().push((hw_bit, bit));
619 }
620
621 let mut conditions = Vec::new();
622
623 for (unit, bits) in units_map {
624 let (mask, value) = compute_mask_value(&bits);
625 if mask != 0 {
626 let source = unit_read_expr(unit, word_type, unit_bytes, endian_suffix);
627 conditions.push(format!("{} & {:#x} == {:#x}", source, mask, value));
628 }
629 }
630
631 if conditions.is_empty() {
632 None
633 } else {
634 Some(conditions.join(" && "))
635 }
636}
637
638fn emit_some_inline(
640 out: &mut String,
641 instr: &ValidatedInstruction,
642 enum_name: &str,
643 variable_length: bool,
644 word_type: &str,
645 unit_bytes: u32,
646 endian_suffix: &str,
647 type_maps: &HashMap<String, String>,
648) {
649 let variant_name = to_pascal_case(&instr.name);
650 let unit_count = instr.unit_count();
651 let bytes_consumed = unit_count * unit_bytes;
652
653 if variable_length && unit_count > 1 {
654 let cond = format!("data.len() >= {}", bytes_consumed);
656 write!(out, "if {} {{ ", cond).unwrap();
657 }
658
659 if instr.resolved_fields.is_empty() {
660 write!(
661 out,
662 "Some(({}::{}, {}))",
663 enum_name, variant_name, bytes_consumed
664 )
665 .unwrap();
666 } else {
667 let fields: Vec<String> = instr
668 .resolved_fields
669 .iter()
670 .map(|f| {
671 let extract =
672 extract_expression("opcode", &f.ranges, word_type, unit_bytes, endian_suffix);
673 let expr = apply_transforms_with_maps(&extract, &f.resolved_type, type_maps);
674 format!("{}: {}", f.name, expr)
675 })
676 .collect();
677 write!(
678 out,
679 "Some(({}::{} {{ {} }}, {}))",
680 enum_name,
681 variant_name,
682 fields.join(", "),
683 bytes_consumed
684 )
685 .unwrap();
686 }
687
688 if variable_length && unit_count > 1 {
689 write!(out, " }} else {{ None }}").unwrap();
690 }
691 writeln!(out, ",").unwrap();
692}
693
694fn emit_some(
696 out: &mut String,
697 instr: &ValidatedInstruction,
698 enum_name: &str,
699 pad: &str,
700 variable_length: bool,
701 word_type: &str,
702 unit_bytes: u32,
703 endian_suffix: &str,
704 type_maps: &HashMap<String, String>,
705) {
706 let unit_count = instr.unit_count();
707 let bytes_consumed = unit_count * unit_bytes;
708
709 if variable_length && unit_count > 1 {
710 writeln!(out, "{}if data.len() >= {} {{", pad, bytes_consumed).unwrap();
711 let inner_pad = format!("{} ", pad);
712 emit_some_inner(
713 out,
714 instr,
715 enum_name,
716 &inner_pad,
717 word_type,
718 unit_bytes,
719 endian_suffix,
720 bytes_consumed,
721 type_maps,
722 );
723 writeln!(out, "{}}} else {{", pad).unwrap();
724 writeln!(out, "{} None", pad).unwrap();
725 writeln!(out, "{}}}", pad).unwrap();
726 } else {
727 emit_some_inner(
728 out,
729 instr,
730 enum_name,
731 pad,
732 word_type,
733 unit_bytes,
734 endian_suffix,
735 bytes_consumed,
736 type_maps,
737 );
738 }
739}
740
741fn emit_some_inner(
743 out: &mut String,
744 instr: &ValidatedInstruction,
745 enum_name: &str,
746 pad: &str,
747 word_type: &str,
748 unit_bytes: u32,
749 endian_suffix: &str,
750 bytes_consumed: u32,
751 type_maps: &HashMap<String, String>,
752) {
753 let variant_name = to_pascal_case(&instr.name);
754 if instr.resolved_fields.is_empty() {
755 writeln!(
756 out,
757 "{}Some(({}::{}, {}))",
758 pad, enum_name, variant_name, bytes_consumed
759 )
760 .unwrap();
761 } else {
762 writeln!(out, "{}Some(({}::{} {{", pad, enum_name, variant_name).unwrap();
763 for field in &instr.resolved_fields {
764 let extract = extract_expression(
765 "opcode",
766 &field.ranges,
767 word_type,
768 unit_bytes,
769 endian_suffix,
770 );
771 let expr = apply_transforms_with_maps(&extract, &field.resolved_type, type_maps);
772 writeln!(out, "{} {}: {},", pad, field.name, expr).unwrap();
773 }
774 writeln!(out, "{}}}, {}))", pad, bytes_consumed).unwrap();
775 }
776}
777
778fn compute_mask_value(fixed_bits: &[(u32, Bit)]) -> (u64, u64) {
781 let mut mask: u64 = 0;
782 let mut value: u64 = 0;
783 for &(bit_pos, bit_val) in fixed_bits {
784 if bit_val == Bit::Wildcard {
786 continue;
787 }
788 mask |= 1u64 << bit_pos;
789 if bit_val == Bit::One {
790 value |= 1u64 << bit_pos;
791 }
792 }
793 (mask, value)
794}
795
796fn unit_read_expr(unit: u32, word_type: &str, unit_bytes: u32, endian_suffix: &str) -> String {
800 if unit == 0 {
801 "opcode".to_string()
802 } else {
803 let start = unit * unit_bytes;
804 let end = start + unit_bytes;
805 format!(
806 "{}::from_{}_bytes(data[{}..{}].try_into().unwrap())",
807 word_type, endian_suffix, start, end
808 )
809 }
810}
811
812fn extract_expression(
814 var: &str,
815 ranges: &[BitRange],
816 word_type: &str,
817 unit_bytes: u32,
818 endian_suffix: &str,
819) -> String {
820 if ranges.is_empty() {
821 return "0".to_string();
822 }
823
824 if ranges.len() == 1 {
825 let range = ranges[0];
827 let source = if range.unit == 0 {
828 var.to_string()
829 } else {
830 unit_read_expr(range.unit, word_type, unit_bytes, endian_suffix)
831 };
832
833 let width = range.width();
834 let shift = range.end;
835 let mask = (1u64 << width) - 1;
836
837 if shift == 0 {
838 format!("{} & {:#x}", source, mask)
839 } else {
840 format!("({} >> {}) & {:#x}", source, shift, mask)
841 }
842 } else {
843 let mut parts = Vec::new();
845 let mut accumulated_width = 0u32;
846
847 for range in ranges {
849 let source = if range.unit == 0 {
850 var.to_string()
851 } else {
852 unit_read_expr(range.unit, word_type, unit_bytes, endian_suffix)
853 };
854
855 let width = range.width();
856 let shift = range.end;
857 let mask = (1u64 << width) - 1;
858
859 let extracted = if shift == 0 {
860 format!("({} & {:#x})", source, mask)
861 } else {
862 format!("(({} >> {}) & {:#x})", source, shift, mask)
863 };
864
865 if accumulated_width > 0 {
867 parts.push(format!("({} << {})", extracted, accumulated_width));
868 } else {
869 parts.push(extracted);
870 }
871
872 accumulated_width += width;
873 }
874
875 parts.join(" | ")
876 }
877}
878
879fn apply_transforms(extract_expr: &str, resolved: &ResolvedFieldType) -> String {
881 apply_transforms_with_maps(extract_expr, resolved, &HashMap::new())
882}
883
884fn apply_transforms_with_maps(
886 extract_expr: &str,
887 resolved: &ResolvedFieldType,
888 type_maps: &HashMap<String, String>,
889) -> String {
890 let mut expr = extract_expr.to_string();
891
892 for transform in &resolved.transforms {
893 match transform {
894 Transform::SignExtend(n) => {
895 let signed_type = signed_type_for(&resolved.base_type);
896 let bits = type_bits(&resolved.base_type);
897 expr = format!(
898 "(((({}) as {}) << ({} - {})) >> ({} - {}))",
899 expr, signed_type, bits, n, bits, n
900 );
901 }
902 Transform::ZeroExtend(_) => {
903 }
905 Transform::ShiftLeft(n) => {
906 expr = format!("(({}) << {})", expr, n);
907 }
908 }
909 }
910
911 if let Some(ref sd_name) = resolved.sub_decoder {
913 let decode_fn = format!("decode_{}", to_snake_case(sd_name));
914 return format!(
916 "{}(({}) as {}).unwrap()",
917 decode_fn, expr, resolved.base_type
918 );
919 }
920
921 let wrapper_type = resolved.alias_name.as_ref().and_then(|a| type_maps.get(a));
923
924 if let Some(wrapper) = wrapper_type {
925 let short_name = wrapper.rsplit("::").next().unwrap_or(wrapper);
926 expr = format!("{}::from(({}) as {})", short_name, expr, resolved.base_type);
927 } else if resolved.base_type == "bool" {
928 expr = format!("({}) != 0", expr);
929 } else {
930 expr = format!("({}) as {}", expr, resolved.base_type);
931 }
932
933 expr
934}
935
936fn generate_display_helpers(out: &mut String, def: &ValidatedDef) {
938 let mut need_signed_hex = false;
939 let mut need_hex = false;
940
941 for instr in &def.instructions {
942 for field in &instr.resolved_fields {
943 match field.resolved_type.display_format {
944 Some(DisplayFormat::SignedHex) => need_signed_hex = true,
945 Some(DisplayFormat::Hex) => need_hex = true,
946 None => {}
947 }
948 }
949 }
950
951 if need_signed_hex {
952 writeln!(out, "struct SignedHex<T>(T);").unwrap();
953 writeln!(out).unwrap();
954
955 for ty in &["i8", "i16", "i32"] {
956 writeln!(out, "impl fmt::Display for SignedHex<{}> {{", ty).unwrap();
957 writeln!(
958 out,
959 " fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{"
960 )
961 .unwrap();
962 writeln!(out, " if self.0 == 0 {{ write!(f, \"0\") }}").unwrap();
963 writeln!(
964 out,
965 " else if self.0 > 0 {{ write!(f, \"0x{{:X}}\", self.0) }}"
966 )
967 .unwrap();
968 writeln!(
969 out,
970 " else {{ write!(f, \"-0x{{:X}}\", (self.0 as i64).wrapping_neg()) }}"
971 )
972 .unwrap();
973 writeln!(out, " }}").unwrap();
974 writeln!(out, "}}").unwrap();
975 writeln!(out).unwrap();
976 }
977 }
978
979 if need_hex {
980 if !need_signed_hex {
981 writeln!(out, "struct SignedHex<T>(T);").unwrap();
982 writeln!(out).unwrap();
983 }
984
985 for ty in &["u8", "u16", "u32"] {
986 writeln!(out, "impl fmt::Display for SignedHex<{}> {{", ty).unwrap();
987 writeln!(
988 out,
989 " fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {{"
990 )
991 .unwrap();
992 writeln!(out, " if self.0 == 0 {{ write!(f, \"0\") }}").unwrap();
993 writeln!(out, " else {{ write!(f, \"0x{{:X}}\", self.0) }}").unwrap();
994 writeln!(out, " }}").unwrap();
995 writeln!(out, "}}").unwrap();
996 writeln!(out).unwrap();
997 }
998 }
999}
1000
1001fn generate_map_functions(out: &mut String, def: &ValidatedDef) {
1003 if def.maps.is_empty() {
1004 return;
1005 }
1006
1007 let map_param_types = infer_map_param_types(def);
1009
1010 for map in &def.maps {
1011 let has_interpolation = map.entries.iter().any(|entry| {
1012 entry
1013 .output
1014 .iter()
1015 .any(|p| matches!(p, FormatPiece::FieldRef { .. }))
1016 });
1017
1018 let param_types: Vec<String> = map
1019 .params
1020 .iter()
1021 .enumerate()
1022 .map(|(i, _)| {
1023 map_param_types
1024 .get(&map.name)
1025 .and_then(|types| types.get(i))
1026 .cloned()
1027 .unwrap_or_else(|| "i64".to_string())
1028 })
1029 .collect();
1030
1031 let return_type = if has_interpolation {
1032 "String"
1033 } else {
1034 "&'static str"
1035 };
1036
1037 let params: Vec<String> = map
1038 .params
1039 .iter()
1040 .zip(param_types.iter())
1041 .map(|(name, ty)| format!("{}: {}", name, ty))
1042 .collect();
1043
1044 writeln!(out, "#[allow(dead_code)]").unwrap();
1045 writeln!(
1046 out,
1047 "fn {}({}) -> {} {{",
1048 map.name,
1049 params.join(", "),
1050 return_type
1051 )
1052 .unwrap();
1053
1054 if map.params.len() == 1 {
1055 writeln!(out, " match {} {{", map.params[0]).unwrap();
1056 } else {
1057 let tuple: Vec<&str> = map.params.iter().map(|s| s.as_str()).collect();
1058 writeln!(out, " match ({}) {{", tuple.join(", ")).unwrap();
1059 }
1060
1061 let mut default_entry = None;
1063
1064 for entry in &map.entries {
1065 let is_all_wildcard = entry.keys.iter().all(|k| matches!(k, MapKey::Wildcard));
1066 if is_all_wildcard {
1067 default_entry = Some(entry);
1068 continue;
1069 }
1070
1071 let pattern = if map.params.len() == 1 {
1072 format_map_key(&entry.keys[0])
1073 } else {
1074 let keys: Vec<String> = entry.keys.iter().map(|k| format_map_key(k)).collect();
1075 format!("({})", keys.join(", "))
1076 };
1077
1078 let output = format_map_output(&entry.output, has_interpolation);
1079 writeln!(out, " {} => {},", pattern, output).unwrap();
1080 }
1081
1082 if let Some(entry) = default_entry {
1084 let output = format_map_output(&entry.output, has_interpolation);
1085 writeln!(out, " _ => {},", output).unwrap();
1086 } else {
1087 if has_interpolation {
1088 writeln!(out, " _ => String::from(\"???\"),").unwrap();
1089 } else {
1090 writeln!(out, " _ => \"???\",").unwrap();
1091 }
1092 }
1093
1094 writeln!(out, " }}").unwrap();
1095 writeln!(out, "}}").unwrap();
1096 writeln!(out).unwrap();
1097 }
1098}
1099
1100fn format_map_key(key: &MapKey) -> String {
1101 match key {
1102 MapKey::Value(v) => format!("{}", v),
1103 MapKey::Wildcard => "_".to_string(),
1104 }
1105}
1106
1107fn format_map_output(pieces: &[FormatPiece], has_interpolation: bool) -> String {
1108 if !has_interpolation {
1109 let mut s = String::new();
1111 for piece in pieces {
1112 if let FormatPiece::Literal(lit) = piece {
1113 s.push_str(lit);
1114 }
1115 }
1116 return format!("\"{}\"", s);
1117 }
1118
1119 let mut fmt_str = String::new();
1121 let mut args = Vec::new();
1122
1123 for piece in pieces {
1124 match piece {
1125 FormatPiece::Literal(lit) => {
1126 for ch in lit.chars() {
1128 match ch {
1129 '{' => fmt_str.push_str("{{"),
1130 '}' => fmt_str.push_str("}}"),
1131 _ => fmt_str.push(ch),
1132 }
1133 }
1134 }
1135 FormatPiece::FieldRef { expr, spec } => {
1136 if let Some(spec) = spec {
1137 fmt_str.push_str(&format!("{{:{}}}", spec));
1138 } else {
1139 fmt_str.push_str("{}");
1140 }
1141 args.push(expr_to_rust(expr, &[]));
1142 }
1143 }
1144 }
1145
1146 if args.is_empty() {
1147 format!("String::from(\"{}\")", fmt_str)
1148 } else {
1149 format!("format!(\"{}\", {})", fmt_str, args.join(", "))
1150 }
1151}
1152
1153fn infer_map_param_types(def: &ValidatedDef) -> HashMap<String, Vec<String>> {
1155 let mut result: HashMap<String, Vec<String>> = HashMap::new();
1156
1157 for instr in &def.instructions {
1159 let field_types: HashMap<&str, &ResolvedFieldType> = instr
1160 .resolved_fields
1161 .iter()
1162 .map(|f| (f.name.as_str(), &f.resolved_type))
1163 .collect();
1164
1165 for fl in &instr.format_lines {
1166 for piece in &fl.pieces {
1167 if let FormatPiece::FieldRef { expr, .. } = piece {
1168 collect_map_call_types(expr, &field_types, &mut result);
1169 }
1170 }
1171 }
1172 }
1173
1174 result
1175}
1176
1177fn infer_expr_type(
1179 expr: &FormatExpr,
1180 field_types: &HashMap<&str, &ResolvedFieldType>,
1181) -> Option<String> {
1182 match expr {
1183 FormatExpr::Field(name) => field_types
1184 .get(name.as_str())
1185 .map(|ft| ft.base_type.clone()),
1186 FormatExpr::Arithmetic { left, .. } => infer_expr_type(left, field_types),
1187 FormatExpr::IntLiteral(_) => Some("i64".to_string()),
1188 _ => None,
1189 }
1190}
1191
1192fn collect_map_call_types(
1193 expr: &FormatExpr,
1194 field_types: &HashMap<&str, &ResolvedFieldType>,
1195 result: &mut HashMap<String, Vec<String>>,
1196) {
1197 match expr {
1198 FormatExpr::MapCall { map_name, args } => {
1199 let entry = result
1200 .entry(map_name.clone())
1201 .or_insert_with(|| vec!["i64".to_string(); args.len()]);
1202
1203 for (i, arg) in args.iter().enumerate() {
1204 if i < entry.len() {
1205 if let Some(rust_type) = infer_expr_type(arg, field_types) {
1206 entry[i] = rust_type;
1207 }
1208 }
1209 }
1210
1211 for arg in args {
1213 collect_map_call_types(arg, field_types, result);
1214 }
1215 }
1216 FormatExpr::Arithmetic { left, right, .. } => {
1217 collect_map_call_types(left, field_types, result);
1218 collect_map_call_types(right, field_types, result);
1219 }
1220 FormatExpr::BuiltinCall { args, .. } => {
1221 for arg in args {
1222 collect_map_call_types(arg, field_types, result);
1223 }
1224 }
1225 FormatExpr::SubDecoderAccess { .. }
1226 | FormatExpr::Field(_)
1227 | FormatExpr::Ternary { .. }
1228 | FormatExpr::IntLiteral(_) => {}
1229 }
1230}
1231
1232fn generate_format_trait(
1234 out: &mut String,
1235 def: &ValidatedDef,
1236 trait_name: &str,
1237 type_maps: &HashMap<String, String>,
1238) {
1239 writeln!(out, "pub trait {} {{", trait_name).unwrap();
1240
1241 for instr in &def.instructions {
1242 let method_name = format!("fmt_{}", instr.name);
1243 let params = trait_method_params(&instr.resolved_fields, &type_maps);
1244
1245 if params.is_empty() {
1246 writeln!(
1247 out,
1248 " fn {}(f: &mut fmt::Formatter) -> fmt::Result {{",
1249 method_name
1250 )
1251 .unwrap();
1252 } else {
1253 writeln!(
1254 out,
1255 " fn {}({}, f: &mut fmt::Formatter) -> fmt::Result {{",
1256 method_name, params
1257 )
1258 .unwrap();
1259 }
1260
1261 generate_format_body(out, instr, 2, &type_maps);
1262
1263 writeln!(out, " }}").unwrap();
1264 }
1265
1266 writeln!(out, "}}").unwrap();
1267 writeln!(out).unwrap();
1268}
1269
1270fn trait_method_params(fields: &[ResolvedField], type_maps: &HashMap<String, String>) -> String {
1272 let mut params = Vec::new();
1273 for field in fields {
1274 let rust_type = field_rust_type_with_maps(field, type_maps);
1275 params.push(format!("{}: {}", field.name, rust_type));
1276 }
1277 params.join(", ")
1278}
1279
1280fn generate_format_body(
1282 out: &mut String,
1283 instr: &ValidatedInstruction,
1284 indent: usize,
1285 type_maps: &HashMap<String, String>,
1286) {
1287 let pad = " ".repeat(indent);
1288
1289 if instr.format_lines.is_empty() {
1290 if instr.resolved_fields.is_empty() {
1292 writeln!(out, "{}write!(f, \"{}\")", pad, instr.name).unwrap();
1293 } else {
1294 let field_names: Vec<&str> = instr
1295 .resolved_fields
1296 .iter()
1297 .map(|f| f.name.as_str())
1298 .collect();
1299 let placeholders: Vec<&str> = field_names.iter().map(|_| "{}").collect();
1300 let fmt_str = format!("{} {}", instr.name, placeholders.join(", "));
1301 let args: Vec<String> = instr
1302 .resolved_fields
1303 .iter()
1304 .map(|f| f.name.clone())
1305 .collect();
1306 writeln!(
1307 out,
1308 "{}write!(f, \"{}\", {})",
1309 pad,
1310 fmt_str,
1311 args.join(", ")
1312 )
1313 .unwrap();
1314 }
1315 return;
1316 }
1317
1318 if instr.format_lines.len() == 1 && instr.format_lines[0].guard.is_none() {
1319 emit_write_call(
1321 out,
1322 &instr.format_lines[0].pieces,
1323 &instr.resolved_fields,
1324 &pad,
1325 );
1326 return;
1327 }
1328
1329 for (i, fl) in instr.format_lines.iter().enumerate() {
1331 if let Some(guard) = &fl.guard {
1332 let guard_code = generate_guard_code(guard, &instr.resolved_fields, type_maps);
1333 if i == 0 {
1334 writeln!(out, "{}if {} {{", pad, guard_code).unwrap();
1335 } else {
1336 writeln!(out, "{}}} else if {} {{", pad, guard_code).unwrap();
1337 }
1338 emit_write_call(
1339 out,
1340 &fl.pieces,
1341 &instr.resolved_fields,
1342 &format!("{} ", pad),
1343 );
1344 } else {
1345 if i > 0 {
1347 writeln!(out, "{}}} else {{", pad).unwrap();
1348 }
1349 emit_write_call(
1350 out,
1351 &fl.pieces,
1352 &instr.resolved_fields,
1353 &format!("{} ", pad),
1354 );
1355 }
1356 }
1357
1358 if instr.format_lines.len() > 1
1359 || instr
1360 .format_lines
1361 .first()
1362 .map_or(false, |fl| fl.guard.is_some())
1363 {
1364 writeln!(out, "{}}}", pad).unwrap();
1365 }
1366}
1367
1368fn emit_write_call(out: &mut String, pieces: &[FormatPiece], fields: &[ResolvedField], pad: &str) {
1370 let mut fmt_str = String::new();
1371 let mut args = Vec::new();
1372
1373 for piece in pieces {
1374 match piece {
1375 FormatPiece::Literal(lit) => {
1376 for ch in lit.chars() {
1377 match ch {
1378 '{' => fmt_str.push_str("{{"),
1379 '}' => fmt_str.push_str("}}"),
1380 _ => fmt_str.push(ch),
1381 }
1382 }
1383 }
1384 FormatPiece::FieldRef { expr, spec } => {
1385 if let Some(spec) = spec {
1386 fmt_str.push_str(&format!("{{:{}}}", spec));
1387 args.push(expr_to_rust(expr, fields));
1388 } else if let Some(display_fmt) = resolve_display_format(expr, fields) {
1389 fmt_str.push_str("{}");
1390 let rust_expr = expr_to_rust(expr, fields);
1391 match display_fmt {
1392 DisplayFormat::SignedHex | DisplayFormat::Hex => {
1393 args.push(format!("SignedHex({})", rust_expr));
1394 }
1395 }
1396 } else {
1397 fmt_str.push_str("{}");
1398 args.push(expr_to_rust(expr, fields));
1399 }
1400 }
1401 }
1402 }
1403
1404 if args.is_empty() {
1405 writeln!(out, "{}write!(f, \"{}\")", pad, fmt_str).unwrap();
1406 } else {
1407 writeln!(
1408 out,
1409 "{}write!(f, \"{}\", {})",
1410 pad,
1411 fmt_str,
1412 args.join(", ")
1413 )
1414 .unwrap();
1415 }
1416}
1417
1418fn resolve_display_format(expr: &FormatExpr, fields: &[ResolvedField]) -> Option<DisplayFormat> {
1420 if let FormatExpr::Field(name) = expr {
1421 fields
1422 .iter()
1423 .find(|f| f.name == *name)
1424 .and_then(|f| f.resolved_type.display_format)
1425 } else {
1426 None
1427 }
1428}
1429
1430fn expr_to_rust(expr: &FormatExpr, fields: &[ResolvedField]) -> String {
1432 match expr {
1433 FormatExpr::Field(name) => {
1434 let field = fields.iter().find(|f| f.name == *name);
1435 if let Some(f) = field {
1436 if f.resolved_type.base_type == "bool" {
1437 format!("{} as u8", name)
1438 } else {
1439 name.clone()
1440 }
1441 } else {
1442 name.clone()
1443 }
1444 }
1445 FormatExpr::Ternary {
1446 field,
1447 if_nonzero,
1448 if_zero,
1449 } => {
1450 let f = fields.iter().find(|f| f.name == *field);
1451 let cond = if let Some(f) = f {
1452 if f.resolved_type.base_type == "bool" {
1453 field.clone()
1454 } else {
1455 format!("{} != 0", field)
1456 }
1457 } else {
1458 format!("{} != 0", field)
1459 };
1460
1461 let else_val = if_zero
1462 .as_deref()
1463 .map(|s| format!("\"{}\"", s))
1464 .unwrap_or_else(|| "\"\"".to_string());
1465
1466 format!(
1467 "if {} {{ \"{}\" }} else {{ {} }}",
1468 cond, if_nonzero, else_val
1469 )
1470 }
1471 FormatExpr::Arithmetic { left, op, right } => {
1472 let l = expr_to_rust(left, fields);
1473 let r = expr_to_rust(right, fields);
1474 let op_str = match op {
1475 ArithOp::Add => "+",
1476 ArithOp::Sub => "-",
1477 ArithOp::Mul => "*",
1478 ArithOp::Div => "/",
1479 ArithOp::Mod => "%",
1480 };
1481 format!("{} {} {}", l, op_str, r)
1482 }
1483 FormatExpr::IntLiteral(val) => format!("{}", val),
1484 FormatExpr::MapCall { map_name, args } => {
1485 let arg_strs: Vec<String> = args.iter().map(|a| expr_to_rust(a, fields)).collect();
1486 format!("{}({})", map_name, arg_strs.join(", "))
1487 }
1488 FormatExpr::BuiltinCall { func, args } => {
1489 let arg_strs: Vec<String> = args.iter().map(|a| expr_to_rust(a, fields)).collect();
1490 match func {
1491 BuiltinFunc::RotateRight => {
1492 format!(
1493 "({} as u32).rotate_right({} as u32)",
1494 arg_strs.get(0).map(|s| s.as_str()).unwrap_or("0"),
1495 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0")
1496 )
1497 }
1498 BuiltinFunc::RotateLeft => {
1499 format!(
1500 "({} as u32).rotate_left({} as u32)",
1501 arg_strs.get(0).map(|s| s.as_str()).unwrap_or("0"),
1502 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0")
1503 )
1504 }
1505 }
1506 }
1507 FormatExpr::SubDecoderAccess { field, fragment } => {
1508 format!("{}.{}", field, fragment)
1509 }
1510 }
1511}
1512
1513fn generate_guard_code(
1515 guard: &Guard,
1516 fields: &[ResolvedField],
1517 type_maps: &HashMap<String, String>,
1518) -> String {
1519 let conditions: Vec<String> = guard
1520 .conditions
1521 .iter()
1522 .map(|cond| {
1523 let left = guard_operand_to_rust(&cond.left, fields);
1524 let right = guard_operand_to_rust(&cond.right, fields);
1525 let op = match cond.op {
1526 CompareOp::Eq => "==",
1527 CompareOp::Ne => "!=",
1528 CompareOp::Lt => "<",
1529 CompareOp::Le => "<=",
1530 CompareOp::Gt => ">",
1531 CompareOp::Ge => ">=",
1532 };
1533
1534 let left_field = match &cond.left {
1535 GuardOperand::Field(name) => fields.iter().find(|f| f.name == *name),
1536 _ => None,
1537 };
1538
1539 if let Some(f) = left_field {
1540 let wrapper = f
1542 .resolved_type
1543 .alias_name
1544 .as_ref()
1545 .and_then(|a| type_maps.get(a));
1546 if let Some(wrapper_path) = wrapper {
1547 let short_name = wrapper_path.rsplit("::").next().unwrap_or(wrapper_path);
1548 if let GuardOperand::Literal(val) = &cond.right {
1549 return format!(
1550 "{} {} {}::from({}{})",
1551 left, op, short_name, val, f.resolved_type.base_type
1552 );
1553 }
1554 } else if f.resolved_type.base_type == "bool" {
1555 if let GuardOperand::Literal(val) = &cond.right {
1557 match (cond.op, *val) {
1558 (CompareOp::Eq, 0) => return format!("!{}", left),
1559 (CompareOp::Eq, _) => return left.clone(),
1560 (CompareOp::Ne, 0) => return left.clone(),
1561 (CompareOp::Ne, _) => return format!("!{}", left),
1562 _ => {}
1563 }
1564 }
1565 }
1566 }
1567
1568 format!("{} {} {}", left, op, right)
1569 })
1570 .collect();
1571
1572 conditions.join(" && ")
1573}
1574
1575fn guard_operand_to_rust(operand: &GuardOperand, fields: &[ResolvedField]) -> String {
1576 match operand {
1577 GuardOperand::Field(name) => name.clone(),
1578 GuardOperand::Literal(val) => format!("{}", val),
1579 GuardOperand::Expr { left, op, right } => {
1580 let l = guard_operand_to_rust(left, fields);
1581 let r = guard_operand_to_rust(right, fields);
1582 let op_str = match op {
1583 ArithOp::Add => "+",
1584 ArithOp::Sub => "-",
1585 ArithOp::Mul => "*",
1586 ArithOp::Div => "/",
1587 ArithOp::Mod => "%",
1588 };
1589 format!("({} {} {})", l, op_str, r)
1590 }
1591 }
1592}
1593
1594fn generate_write_asm(out: &mut String, def: &ValidatedDef, enum_name: &str, trait_name: &str) {
1596 writeln!(
1597 out,
1598 " pub fn write_asm<F: {}>(&self, f: &mut fmt::Formatter) -> fmt::Result {{",
1599 trait_name
1600 )
1601 .unwrap();
1602 writeln!(out, " match self {{").unwrap();
1603
1604 for instr in &def.instructions {
1605 let variant_name = to_pascal_case(&instr.name);
1606 let method_name = format!("fmt_{}", instr.name);
1607
1608 if instr.resolved_fields.is_empty() {
1609 writeln!(
1610 out,
1611 " {}::{} => F::{}(f),",
1612 enum_name, variant_name, method_name
1613 )
1614 .unwrap();
1615 } else {
1616 let field_names: Vec<String> = instr
1617 .resolved_fields
1618 .iter()
1619 .map(|f| f.name.clone())
1620 .collect();
1621 let destructure = format!(
1622 "{}::{} {{ {} }}",
1623 enum_name,
1624 variant_name,
1625 field_names.join(", ")
1626 );
1627
1628 let args: Vec<String> = instr
1629 .resolved_fields
1630 .iter()
1631 .map(|f| format!("*{}", f.name))
1632 .collect();
1633
1634 writeln!(
1635 out,
1636 " {} => F::{}({}, f),",
1637 destructure,
1638 method_name,
1639 args.join(", ")
1640 )
1641 .unwrap();
1642 }
1643 }
1644
1645 writeln!(out, " }}").unwrap();
1646 writeln!(out, " }}").unwrap();
1647}
1648
1649fn word_type_for_width(width: u32) -> &'static str {
1650 match width {
1651 8 => "u8",
1652 16 => "u16",
1653 32 => "u32",
1654 _ => "u32",
1655 }
1656}
1657
1658pub(crate) fn signed_type_for(base: &str) -> &'static str {
1659 match base {
1660 "u8" | "i8" => "i8",
1661 "u16" | "i16" => "i16",
1662 "u32" | "i32" => "i32",
1663 _ => "i32",
1664 }
1665}
1666
1667pub(crate) fn type_bits(base: &str) -> u32 {
1668 match base {
1669 "u8" | "i8" => 8,
1670 "u16" | "i16" => 16,
1671 "u32" | "i32" => 32,
1672 _ => 32,
1673 }
1674}
1675
1676fn field_rust_type_with_maps(field: &ResolvedField, type_maps: &HashMap<String, String>) -> String {
1677 if field.resolved_type.sub_decoder.is_some() {
1678 let sd_name = field.resolved_type.sub_decoder.as_ref().unwrap();
1679 format!("{}Insn", sd_name)
1680 } else if let Some(ref alias) = field.resolved_type.alias_name {
1681 if let Some(rust_type) = type_maps.get(alias) {
1682 rust_type
1684 .rsplit("::")
1685 .next()
1686 .unwrap_or(rust_type)
1687 .to_string()
1688 } else {
1689 field.resolved_type.base_type.clone()
1690 }
1691 } else {
1692 field.resolved_type.base_type.clone()
1693 }
1694}
1695
1696pub fn to_pascal_case(name: &str) -> String {
1701 let mut result = String::new();
1702 let mut capitalize_next = true;
1703
1704 for ch in name.chars() {
1705 if ch == '_' {
1706 capitalize_next = true;
1707 } else if capitalize_next {
1708 result.push(ch.to_ascii_uppercase());
1709 capitalize_next = false;
1710 } else {
1711 result.push(ch.to_ascii_lowercase());
1712 }
1713 }
1714
1715 result
1716}
1717
1718fn generate_subdecoder(out: &mut String, sd: &ValidatedSubDecoder, dispatch: crate::Dispatch) {
1720 let opcode_enum = format!("{}Opcode", sd.name);
1721 let insn_struct = format!("{}Insn", sd.name);
1722 let decode_fn = format!("decode_{}", to_snake_case(&sd.name));
1723 let word_type = word_type_for_width(sd.width);
1724 let lut_size = 1usize << sd.width;
1725 let use_inline = dispatch == crate::Dispatch::JumpTable;
1726
1727 if !sd.maps.is_empty() {
1729 for map in &sd.maps {
1730 let has_interpolation = map.entries.iter().any(|entry| {
1731 entry
1732 .output
1733 .iter()
1734 .any(|p| matches!(p, FormatPiece::FieldRef { .. }))
1735 });
1736 let return_type = if has_interpolation {
1737 "String"
1738 } else {
1739 "&'static str"
1740 };
1741 let params: Vec<String> = map
1742 .params
1743 .iter()
1744 .map(|name| format!("{}: {}", name, word_type))
1745 .collect();
1746 writeln!(out, "#[allow(dead_code)]").unwrap();
1747 writeln!(
1748 out,
1749 "fn {}({}) -> {} {{",
1750 map.name,
1751 params.join(", "),
1752 return_type
1753 )
1754 .unwrap();
1755 if map.params.len() == 1 {
1756 writeln!(out, " match {} {{", map.params[0]).unwrap();
1757 } else {
1758 let tuple: Vec<&str> = map.params.iter().map(|s| s.as_str()).collect();
1759 writeln!(out, " match ({}) {{", tuple.join(", ")).unwrap();
1760 }
1761 let mut default_entry = None;
1762 for entry in &map.entries {
1763 let is_all_wildcard = entry.keys.iter().all(|k| matches!(k, MapKey::Wildcard));
1764 if is_all_wildcard {
1765 default_entry = Some(entry);
1766 continue;
1767 }
1768 let pattern = if map.params.len() == 1 {
1769 format_map_key(&entry.keys[0])
1770 } else {
1771 let keys: Vec<String> = entry.keys.iter().map(|k| format_map_key(k)).collect();
1772 format!("({})", keys.join(", "))
1773 };
1774 let output = format_map_output(&entry.output, has_interpolation);
1775 writeln!(out, " {} => {},", pattern, output).unwrap();
1776 }
1777 if let Some(entry) = default_entry {
1778 let output = format_map_output(&entry.output, has_interpolation);
1779 writeln!(out, " _ => {},", output).unwrap();
1780 } else if has_interpolation {
1781 writeln!(out, " _ => String::from(\"???\"),").unwrap();
1782 } else {
1783 writeln!(out, " _ => \"???\",").unwrap();
1784 }
1785 writeln!(out, " }}").unwrap();
1786 writeln!(out, "}}").unwrap();
1787 writeln!(out).unwrap();
1788 }
1789 }
1790
1791 writeln!(out, "#[derive(Debug, Clone, Copy, PartialEq, Eq)]").unwrap();
1793 writeln!(out, "pub enum {} {{", opcode_enum).unwrap();
1794 for instr in &sd.instructions {
1795 writeln!(out, " {},", to_pascal_case(&instr.name)).unwrap();
1796 }
1797 writeln!(out, "}}").unwrap();
1798 writeln!(out).unwrap();
1799
1800 writeln!(out, "#[derive(Debug, Clone, Copy, PartialEq, Eq)]").unwrap();
1802 writeln!(out, "pub struct {} {{", insn_struct).unwrap();
1803 writeln!(out, " pub opcode: {},", opcode_enum).unwrap();
1804 for frag_name in &sd.fragment_names {
1805 writeln!(out, " pub {}: &'static str,", frag_name).unwrap();
1806 }
1807 writeln!(out, "}}").unwrap();
1808 writeln!(out).unwrap();
1809
1810 for instr in &sd.instructions {
1812 let handler_name = format!("_sd_{}", instr.name);
1813
1814 let has_fields = !instr.resolved_fields.is_empty();
1817
1818 if has_fields {
1819 for frag in &instr.fragments {
1821 let has_field_refs = frag
1822 .pieces
1823 .iter()
1824 .any(|p| matches!(p, FormatPiece::FieldRef { .. }));
1825 if has_field_refs {
1826 generate_prebaked_fragment_array(out, sd, instr, frag);
1828 }
1829 }
1830 }
1831
1832 if use_inline {
1834 writeln!(out, "#[inline(always)]").unwrap();
1835 }
1836 let param_name = if has_fields { "val" } else { "_val" };
1837 writeln!(
1838 out,
1839 "fn {}({}: {}) -> {} {{",
1840 handler_name, param_name, word_type, insn_struct
1841 )
1842 .unwrap();
1843
1844 for field in &instr.resolved_fields {
1846 let extract = extract_expression("val", &field.ranges, word_type, sd.width / 8, "be");
1847 let expr = apply_transforms(&extract, &field.resolved_type);
1848 writeln!(out, " let {} = {};", field.name, expr).unwrap();
1849 }
1850
1851 writeln!(out, " {} {{", insn_struct).unwrap();
1853 writeln!(
1854 out,
1855 " opcode: {}::{},",
1856 opcode_enum,
1857 to_pascal_case(&instr.name)
1858 )
1859 .unwrap();
1860
1861 for frag in &instr.fragments {
1862 let has_field_refs = frag
1863 .pieces
1864 .iter()
1865 .any(|p| matches!(p, FormatPiece::FieldRef { .. }));
1866 if has_field_refs {
1867 let array_name = prebaked_array_name(&instr.name, &frag.name);
1869 let index_expr = prebaked_index_expr(instr);
1870 writeln!(
1871 out,
1872 " {}: {}[{} as usize],",
1873 frag.name, array_name, index_expr
1874 )
1875 .unwrap();
1876 } else {
1877 let literal = pieces_to_static_str(&frag.pieces);
1879 writeln!(out, " {}: \"{}\",", frag.name, literal).unwrap();
1880 }
1881 }
1882
1883 writeln!(out, " }}").unwrap();
1884 writeln!(out, "}}").unwrap();
1885 writeln!(out).unwrap();
1886 }
1887
1888 let mut dispatch_table: Vec<Option<usize>> = vec![None; lut_size];
1891
1892 for (instr_idx, instr) in sd.instructions.iter().enumerate() {
1893 for val in 0..lut_size {
1895 let matches = instr.segments.iter().all(|seg| {
1896 if let Segment::Fixed {
1897 ranges, pattern, ..
1898 } = seg
1899 {
1900 let mut bit_idx = 0;
1901 for range in ranges {
1902 for i in 0..range.width() as usize {
1903 if bit_idx < pattern.len() {
1904 let hw_bit = range.start - i as u32;
1905 let bit_val = (val >> hw_bit) & 1;
1906 match pattern[bit_idx] {
1907 Bit::Zero if bit_val != 0 => return false,
1908 Bit::One if bit_val != 1 => return false,
1909 _ => {}
1910 }
1911 bit_idx += 1;
1912 }
1913 }
1914 }
1915 true
1916 } else {
1917 true
1918 }
1919 });
1920 if matches && dispatch_table[val].is_none() {
1921 dispatch_table[val] = Some(instr_idx);
1922 }
1923 }
1924 }
1925
1926 match dispatch {
1927 crate::Dispatch::JumpTable => {
1928 writeln!(out, "#[inline(always)]").unwrap();
1930 writeln!(
1931 out,
1932 "pub fn {}(val: {}) -> Option<{}> {{",
1933 decode_fn, word_type, insn_struct
1934 )
1935 .unwrap();
1936 writeln!(out, " match val {{").unwrap();
1937
1938 let mut i = 0;
1939 while i < lut_size {
1940 let current = dispatch_table[i];
1941 let start = i;
1942 while i < lut_size && dispatch_table[i] == current {
1943 i += 1;
1944 }
1945 let end = i - 1;
1946
1947 let handler_name = current.map(|idx| format!("_sd_{}", sd.instructions[idx].name));
1948
1949 let pattern = if start == end {
1950 format!("{:#x}", start)
1951 } else {
1952 format!("{:#x}..={:#x}", start, end)
1953 };
1954
1955 match handler_name {
1956 Some(h) => writeln!(out, " {} => Some({}(val)),", pattern, h).unwrap(),
1957 None => writeln!(out, " {} => None,", pattern).unwrap(),
1958 }
1959 }
1960
1961 writeln!(out, " }}").unwrap();
1962 writeln!(out, "}}").unwrap();
1963 writeln!(out).unwrap();
1964 }
1965 crate::Dispatch::FnPtrLut => {
1966 let handler_type = format!("fn({}) -> {}", word_type, insn_struct);
1968 let table_name = format!("_SD_{}_LUT", sd.name.to_uppercase());
1969
1970 writeln!(
1971 out,
1972 "static {}: [Option<{}>; {}] = [",
1973 table_name, handler_type, lut_size
1974 )
1975 .unwrap();
1976 for val in 0..lut_size {
1977 match dispatch_table[val] {
1978 Some(idx) => {
1979 writeln!(out, " Some(_sd_{}),", sd.instructions[idx].name).unwrap()
1980 }
1981 None => writeln!(out, " None,").unwrap(),
1982 }
1983 }
1984 writeln!(out, "];").unwrap();
1985 writeln!(out).unwrap();
1986
1987 writeln!(
1988 out,
1989 "pub fn {}(val: {}) -> Option<{}> {{",
1990 decode_fn, word_type, insn_struct
1991 )
1992 .unwrap();
1993 writeln!(out, " {}[val as usize].map(|f| f(val))", table_name).unwrap();
1994 writeln!(out, "}}").unwrap();
1995 writeln!(out).unwrap();
1996 }
1997 }
1998}
1999
2000fn generate_prebaked_fragment_array(
2002 out: &mut String,
2003 sd: &ValidatedSubDecoder,
2004 instr: &ValidatedSubInstruction,
2005 frag: &FragmentLine,
2006) {
2007 let array_name = prebaked_array_name(&instr.name, &frag.name);
2008 let total = prebaked_total_entries(instr);
2010
2011 writeln!(out, "static {}: [&str; {}] = [", array_name, total).unwrap();
2012
2013 for combo_idx in 0..total {
2014 let field_values = prebaked_field_values(instr, combo_idx);
2016 let s = evaluate_fragment_pieces(&frag.pieces, &field_values, &sd.maps);
2017 writeln!(out, " \"{}\",", s).unwrap();
2018 }
2019
2020 writeln!(out, "];").unwrap();
2021 writeln!(out).unwrap();
2022}
2023
2024fn evaluate_fragment_pieces(
2026 pieces: &[FormatPiece],
2027 field_values: &HashMap<String, i64>,
2028 maps: &[MapDef],
2029) -> String {
2030 evaluate_fragment_pieces_str(pieces, field_values, maps)
2031}
2032
2033fn evaluate_format_expr(
2035 expr: &FormatExpr,
2036 field_values: &HashMap<String, i64>,
2037 maps: &[MapDef],
2038) -> i64 {
2039 match expr {
2040 FormatExpr::Field(name) => *field_values.get(name).unwrap_or(&0),
2041 FormatExpr::IntLiteral(v) => *v,
2042 FormatExpr::Arithmetic { left, op, right } => {
2043 let l = evaluate_format_expr(left, field_values, maps);
2044 let r = evaluate_format_expr(right, field_values, maps);
2045 match op {
2046 ArithOp::Add => l + r,
2047 ArithOp::Sub => l - r,
2048 ArithOp::Mul => l * r,
2049 ArithOp::Div => {
2050 if r != 0 {
2051 l / r
2052 } else {
2053 0
2054 }
2055 }
2056 ArithOp::Mod => {
2057 if r != 0 {
2058 l % r
2059 } else {
2060 0
2061 }
2062 }
2063 }
2064 }
2065 _ => 0,
2066 }
2067}
2068
2069fn evaluate_fragment_pieces_str(
2071 pieces: &[FormatPiece],
2072 field_values: &HashMap<String, i64>,
2073 maps: &[MapDef],
2074) -> String {
2075 let mut result = String::new();
2076 for piece in pieces {
2077 match piece {
2078 FormatPiece::Literal(s) => result.push_str(s),
2079 FormatPiece::FieldRef { expr, spec } => {
2080 match expr {
2081 FormatExpr::MapCall { map_name, args } => {
2082 if let Some(map) = maps.iter().find(|m| m.name == *map_name) {
2084 let arg_vals: Vec<i64> = args
2085 .iter()
2086 .map(|a| evaluate_format_expr(a, field_values, maps))
2087 .collect();
2088 let map_result = evaluate_map(map, &arg_vals);
2089 result.push_str(&map_result);
2090 }
2091 }
2092 FormatExpr::Field(name) => {
2093 let val = *field_values.get(name).unwrap_or(&0);
2094 match spec {
2095 Some(s) if s.contains('x') || s.contains('X') => {
2096 result.push_str(&format!("{:x}", val));
2097 }
2098 _ => result.push_str(&val.to_string()),
2099 }
2100 }
2101 _ => {
2102 let val = evaluate_format_expr(expr, field_values, maps);
2103 result.push_str(&val.to_string());
2104 }
2105 }
2106 }
2107 }
2108 }
2109 result
2110}
2111
2112fn evaluate_map(map: &MapDef, keys: &[i64]) -> String {
2114 for entry in &map.entries {
2115 let matches = entry.keys.iter().zip(keys.iter()).all(|(k, v)| match k {
2116 MapKey::Value(expected) => *expected == *v,
2117 MapKey::Wildcard => true,
2118 });
2119 if matches {
2120 let mut s = String::new();
2122 for piece in &entry.output {
2123 if let FormatPiece::Literal(lit) = piece {
2124 s.push_str(lit);
2125 }
2126 }
2127 return s;
2128 }
2129 }
2130 "???".to_string()
2131}
2132
2133fn prebaked_total_entries(instr: &ValidatedSubInstruction) -> usize {
2135 let mut total = 1usize;
2136 for field in &instr.resolved_fields {
2137 let field_bits: u32 = field.ranges.iter().map(|r| r.width()).sum();
2138 total *= 1 << field_bits;
2139 }
2140 total
2141}
2142
2143fn prebaked_field_values(
2145 instr: &ValidatedSubInstruction,
2146 combo_idx: usize,
2147) -> HashMap<String, i64> {
2148 let mut values = HashMap::new();
2149 let mut remaining = combo_idx;
2150
2151 for field in instr.resolved_fields.iter().rev() {
2152 let field_bits: u32 = field.ranges.iter().map(|r| r.width()).sum();
2153 let field_range = 1 << field_bits;
2154 let val = remaining % field_range;
2155 remaining /= field_range;
2156 values.insert(field.name.clone(), val as i64);
2157 }
2158
2159 values
2160}
2161
2162fn prebaked_index_expr(instr: &ValidatedSubInstruction) -> String {
2164 if instr.resolved_fields.len() == 1 {
2165 return instr.resolved_fields[0].name.clone();
2166 }
2167
2168 let mut parts = Vec::new();
2170 let mut accumulated_bits = 0u32;
2171
2172 for field in instr.resolved_fields.iter().rev() {
2173 let field_bits: u32 = field.ranges.iter().map(|r| r.width()).sum();
2174 if accumulated_bits > 0 {
2175 parts.push(format!(
2176 "(({} as usize) << {})",
2177 field.name, accumulated_bits
2178 ));
2179 } else {
2180 parts.push(format!("({} as usize)", field.name));
2181 }
2182 accumulated_bits += field_bits;
2183 }
2184
2185 parts.reverse();
2186 parts.join(" | ")
2187}
2188
2189fn prebaked_array_name(instr_name: &str, frag_name: &str) -> String {
2191 format!(
2192 "_SD_{}_{}",
2193 instr_name.to_uppercase(),
2194 frag_name.to_uppercase()
2195 )
2196}
2197
2198fn pieces_to_static_str(pieces: &[FormatPiece]) -> String {
2200 let mut s = String::new();
2201 for piece in pieces {
2202 if let FormatPiece::Literal(lit) = piece {
2203 s.push_str(lit);
2204 }
2205 }
2206 s
2207}
2208
2209fn to_snake_case(name: &str) -> String {
2211 let mut result = String::new();
2212 for (i, ch) in name.chars().enumerate() {
2213 if ch.is_ascii_uppercase() && i > 0 {
2214 result.push('_');
2215 }
2216 result.push(ch.to_ascii_lowercase());
2217 }
2218 result
2219}
2220
2221#[cfg(test)]
2222mod tests {
2223 use super::*;
2224
2225 #[test]
2226 fn test_to_pascal_case() {
2227 assert_eq!(to_pascal_case("addi"), "Addi");
2228 assert_eq!(to_pascal_case("ld_b_c"), "LdBC");
2229 assert_eq!(to_pascal_case("ADD"), "Add");
2230 assert_eq!(to_pascal_case("nop"), "Nop");
2231 }
2232
2233 #[test]
2234 fn test_extract_expression() {
2235 let range = BitRange::new(5, 0);
2237 assert_eq!(
2238 extract_expression("opcode", &[range], "u32", 4, "be"),
2239 "opcode & 0x3f"
2240 );
2241
2242 let range = BitRange::new(31, 26);
2244 assert_eq!(
2245 extract_expression("opcode", &[range], "u32", 4, "be"),
2246 "(opcode >> 26) & 0x3f"
2247 );
2248
2249 let range = BitRange::new_in_unit(1, 15, 0);
2251 assert_eq!(
2252 extract_expression("opcode", &[range], "u16", 2, "be"),
2253 "u16::from_be_bytes(data[2..4].try_into().unwrap()) & 0xffff"
2254 );
2255
2256 let range0 = BitRange::new_in_unit(0, 7, 0); let range1 = BitRange::new_in_unit(1, 15, 8); let result = extract_expression("opcode", &[range0, range1], "u16", 2, "be");
2261 assert!(result.contains("opcode & 0xff"));
2262 assert!(result.contains("u16::from_be_bytes(data[2..4].try_into().unwrap())"));
2263 }
2264}