1use std::collections::HashMap;
7use std::fmt::Write;
8
9use crate::config::{CppGuardStyle as GuardStyle, CppOptions};
10use crate::tree::DecodeNode;
11use crate::types::*;
12
13pub fn generate_cpp_code(
15 def: &ValidatedDef,
16 tree: &DecodeNode,
17 opts: &CppOptions,
18 type_maps: &HashMap<String, String>,
19) -> String {
20 let mut out = String::new();
21
22 let default_ns = to_snake_case(&def.config.name);
23 let ns = opts.namespace.as_deref().unwrap_or(&default_ns);
24 let guard_name = format!("CHIPI_{}_HPP", ns.to_ascii_uppercase());
25 let unit_bytes = def.config.width / 8;
26 let word_type = cpp_word_type(def.config.width);
27 let endian = &def.config.endian;
28 let variable_length = def.instructions.iter().any(|i| i.unit_count() > 1);
29
30 match opts.guard_style {
32 GuardStyle::Pragma => writeln!(out, "#pragma once").unwrap(),
33 GuardStyle::Ifndef => {
34 writeln!(out, "#ifndef {}", guard_name).unwrap();
35 writeln!(out, "#define {}", guard_name).unwrap();
36 }
37 }
38 writeln!(out).unwrap();
39 writeln!(
40 out,
41 "// Auto-generated by https://github.com/ioncodes/chipi"
42 )
43 .unwrap();
44 writeln!(out, "// Do not edit.").unwrap();
45 writeln!(out).unwrap();
46
47 writeln!(out, "#include <cstdint>").unwrap();
49 writeln!(out, "#include <cstddef>").unwrap();
50 writeln!(out, "#include <cstring>").unwrap();
51 writeln!(out, "#include <string>").unwrap();
52 writeln!(out, "#include <optional>").unwrap();
53 writeln!(out, "#include <format>").unwrap();
54 for inc in &opts.includes {
55 writeln!(out, "#include \"{}\"", inc).unwrap();
56 }
57 writeln!(out).unwrap();
58
59 writeln!(out, "namespace {} {{", ns).unwrap();
60 writeln!(out).unwrap();
61
62 emit_display_types(&mut out, def, type_maps);
64
65 emit_opcode_enum(&mut out, def);
67
68 emit_instruction_struct(&mut out, def, type_maps);
70
71 for sd in &def.sub_decoders {
73 emit_subdecoder(&mut out, sd, def.config.width);
74 }
75
76 emit_map_functions(&mut out, def);
78
79 emit_decode_function(
81 &mut out,
82 def,
83 tree,
84 word_type,
85 unit_bytes,
86 endian,
87 variable_length,
88 type_maps,
89 );
90
91 emit_format_function(&mut out, def, type_maps, opts);
93
94 writeln!(out, "}} // namespace {}", ns).unwrap();
95
96 if opts.guard_style == GuardStyle::Ifndef {
97 writeln!(out).unwrap();
98 writeln!(out, "#endif // {}", guard_name).unwrap();
99 }
100
101 out
102}
103
104fn cpp_word_type(width: u32) -> &'static str {
105 match width {
106 8 => "uint8_t",
107 16 => "uint16_t",
108 32 => "uint32_t",
109 _ => "uint32_t",
110 }
111}
112
113fn cpp_signed_type(base: &str) -> &'static str {
114 match base {
115 "u8" | "i8" => "int8_t",
116 "u16" | "i16" => "int16_t",
117 "u32" | "i32" => "int32_t",
118 _ => "int32_t",
119 }
120}
121
122fn cpp_type_for(base: &str) -> &'static str {
123 match base {
124 "bool" => "bool",
125 "u1" | "u2" | "u3" | "u4" | "u5" | "u6" | "u7" | "u8" => "uint8_t",
126 "i8" => "int8_t",
127 "u16" => "uint16_t",
128 "i16" => "int16_t",
129 "u32" => "uint32_t",
130 "i32" => "int32_t",
131 _ => "uint32_t",
132 }
133}
134
135fn type_bits(base: &str) -> u32 {
136 match base {
137 "u8" | "i8" => 8,
138 "u16" | "i16" => 16,
139 "u32" | "i32" => 32,
140 _ => 32,
141 }
142}
143
144fn to_snake_case(name: &str) -> String {
145 let mut result = String::new();
146 for (i, ch) in name.chars().enumerate() {
147 if ch.is_ascii_uppercase() && i > 0 {
148 result.push('_');
149 }
150 result.push(ch.to_ascii_lowercase());
151 }
152 result
153}
154
155fn to_pascal_case(name: &str) -> String {
156 let mut result = String::new();
157 let mut cap_next = true;
158 for ch in name.chars() {
159 if ch == '_' {
160 cap_next = true;
161 } else if cap_next {
162 result.push(ch.to_ascii_uppercase());
163 cap_next = false;
164 } else {
165 result.push(ch.to_ascii_lowercase());
166 }
167 }
168 result
169}
170
171fn emit_display_types(out: &mut String, def: &ValidatedDef, type_maps: &HashMap<String, String>) {
174 let mut need_signed_hex = false;
175 let mut need_hex = false;
176
177 for alias in &def.type_aliases {
178 if type_maps.contains_key(&alias.name) {
180 continue;
181 }
182 match alias.display_format {
183 Some(DisplayFormat::SignedHex) => need_signed_hex = true,
184 Some(DisplayFormat::Hex) => need_hex = true,
185 None => {}
186 }
187 }
188
189 if need_signed_hex {
190 writeln!(out, "struct SignedHex {{").unwrap();
191 writeln!(out, " int32_t value;").unwrap();
192 writeln!(out, " SignedHex() = default;").unwrap();
193 writeln!(out, " constexpr SignedHex(int32_t v) : value(v) {{}}").unwrap();
194 writeln!(
195 out,
196 " bool operator==(const SignedHex&) const = default;"
197 )
198 .unwrap();
199 writeln!(
200 out,
201 " bool operator==(int other) const {{ return value == other; }}"
202 )
203 .unwrap();
204 writeln!(
205 out,
206 " bool operator!=(int other) const {{ return value != other; }}"
207 )
208 .unwrap();
209 writeln!(
210 out,
211 " bool operator<(int other) const {{ return value < other; }}"
212 )
213 .unwrap();
214 writeln!(
215 out,
216 " bool operator<=(int other) const {{ return value <= other; }}"
217 )
218 .unwrap();
219 writeln!(
220 out,
221 " bool operator>(int other) const {{ return value > other; }}"
222 )
223 .unwrap();
224 writeln!(
225 out,
226 " bool operator>=(int other) const {{ return value >= other; }}"
227 )
228 .unwrap();
229 writeln!(
230 out,
231 " SignedHex operator-() const {{ return SignedHex(-value); }}"
232 )
233 .unwrap();
234 writeln!(out, " friend SignedHex operator-(int lhs, SignedHex rhs) {{ return SignedHex(lhs - rhs.value); }}").unwrap();
235 writeln!(out, " friend SignedHex operator+(int lhs, SignedHex rhs) {{ return SignedHex(lhs + rhs.value); }}").unwrap();
236 writeln!(out, " friend SignedHex operator+(SignedHex lhs, int rhs) {{ return SignedHex(lhs.value + rhs); }}").unwrap();
237 writeln!(out, " friend SignedHex operator-(SignedHex lhs, int rhs) {{ return SignedHex(lhs.value - rhs); }}").unwrap();
238 writeln!(out, " friend SignedHex operator*(SignedHex lhs, int rhs) {{ return SignedHex(lhs.value * rhs); }}").unwrap();
239 writeln!(out, "}};").unwrap();
240 writeln!(out).unwrap();
241 }
242
243 if need_hex {
244 writeln!(out, "struct Hex {{").unwrap();
245 writeln!(out, " uint32_t value;").unwrap();
246 writeln!(out, " Hex() = default;").unwrap();
247 writeln!(out, " constexpr Hex(uint32_t v) : value(v) {{}}").unwrap();
248 writeln!(out, " bool operator==(const Hex&) const = default;").unwrap();
249 writeln!(
250 out,
251 " bool operator==(unsigned other) const {{ return value == other; }}"
252 )
253 .unwrap();
254 writeln!(out, "}};").unwrap();
255 writeln!(out).unwrap();
256 }
257
258 writeln!(out, "}} // namespace {}", to_snake_case(&def.config.name)).unwrap();
259 writeln!(out).unwrap();
260
261 if need_signed_hex {
263 let ns = to_snake_case(&def.config.name);
264 writeln!(
265 out,
266 "template <> struct std::formatter<{}::SignedHex> : std::formatter<std::string> {{",
267 ns
268 )
269 .unwrap();
270 writeln!(
271 out,
272 " auto format({}::SignedHex v, auto& ctx) const {{",
273 ns
274 )
275 .unwrap();
276 writeln!(out, " if (v.value < 0)").unwrap();
277 writeln!(out, " return std::formatter<std::string>::format(std::format(\"-0x{{:x}}\", static_cast<unsigned>(-v.value)), ctx);").unwrap();
278 writeln!(out, " return std::formatter<std::string>::format(std::format(\"0x{{:x}}\", static_cast<unsigned>(v.value)), ctx);").unwrap();
279 writeln!(out, " }}").unwrap();
280 writeln!(out, "}};").unwrap();
281 writeln!(out).unwrap();
282 }
283
284 if need_hex {
285 let ns = to_snake_case(&def.config.name);
286 writeln!(
287 out,
288 "template <> struct std::formatter<{}::Hex> : std::formatter<std::string> {{",
289 ns
290 )
291 .unwrap();
292 writeln!(out, " auto format({}::Hex v, auto& ctx) const {{", ns).unwrap();
293 writeln!(out, " return std::formatter<std::string>::format(std::format(\"0x{{:x}}\", v.value), ctx);").unwrap();
294 writeln!(out, " }}").unwrap();
295 writeln!(out, "}};").unwrap();
296 writeln!(out).unwrap();
297 }
298
299 if need_signed_hex || need_hex {
301 writeln!(out, "namespace {} {{", to_snake_case(&def.config.name)).unwrap();
302 writeln!(out).unwrap();
303 }
304}
305
306fn emit_opcode_enum(out: &mut String, def: &ValidatedDef) {
308 writeln!(out, "enum class Opcode : uint32_t {{").unwrap();
309 for (i, instr) in def.instructions.iter().enumerate() {
310 writeln!(out, " {} = {},", to_pascal_case(&instr.name), i).unwrap();
311 }
312 writeln!(out, "}};").unwrap();
313 writeln!(out).unwrap();
314}
315
316fn emit_instruction_struct(
318 out: &mut String,
319 def: &ValidatedDef,
320 type_maps: &HashMap<String, String>,
321) {
322 writeln!(out, "struct Instruction {{").unwrap();
323 writeln!(out, " Opcode opcode;").unwrap();
324 writeln!(out, " uint32_t size; // bytes consumed").unwrap();
325 writeln!(out).unwrap();
326
327 let has_fields = def
329 .instructions
330 .iter()
331 .any(|i| !i.resolved_fields.is_empty());
332 if has_fields {
333 writeln!(out, " union {{").unwrap();
334 for instr in &def.instructions {
335 if instr.resolved_fields.is_empty() {
336 continue;
337 }
338 writeln!(out, " struct {{").unwrap();
339 for field in &instr.resolved_fields {
340 let cpp_type = field_cpp_type(field, type_maps);
341 writeln!(out, " {} {};", cpp_type, field.name).unwrap();
342 }
343 writeln!(out, " }} {};", instr.name).unwrap();
344 }
345 writeln!(out, " }};").unwrap();
346 }
347
348 writeln!(out, "}};").unwrap();
349 writeln!(out).unwrap();
350}
351
352fn field_cpp_type(field: &ResolvedField, type_maps: &HashMap<String, String>) -> String {
354 if let Some(alias) = &field.resolved_type.alias_name {
356 if let Some(mapped) = type_maps.get(alias) {
357 return mapped.clone();
358 }
359 }
360
361 if let Some(ref sd_name) = field.resolved_type.sub_decoder {
363 return format!("{}Insn", to_pascal_case(sd_name));
364 }
365
366 match field.resolved_type.display_format {
368 Some(DisplayFormat::SignedHex) => return "SignedHex".to_string(),
369 Some(DisplayFormat::Hex) => return "Hex".to_string(),
370 None => {}
371 }
372
373 cpp_type_for(&field.resolved_type.base_type).to_string()
374}
375
376fn emit_subdecoder(out: &mut String, sd: &ValidatedSubDecoder, _parent_width: u32) {
378 let type_name = format!("{}Insn", to_pascal_case(&sd.name));
379 let word_type = cpp_word_type(sd.width);
380
381 writeln!(out, "struct {} {{", type_name).unwrap();
383 for frag_name in &sd.fragment_names {
384 writeln!(out, " const char* {};", frag_name).unwrap();
385 }
386 writeln!(out, "}};").unwrap();
387 writeln!(out).unwrap();
388
389 let fn_name = format!("decode_{}", to_snake_case(&sd.name));
392 writeln!(
393 out,
394 "inline std::optional<{}> {}({} val) {{",
395 type_name, fn_name, word_type
396 )
397 .unwrap();
398
399 for (i, instr) in sd.instructions.iter().enumerate() {
400 let (mask, value) = compute_instruction_mask_value_sub(instr);
401 let keyword = if i == 0 { "if" } else { "} else if" };
402 writeln!(
403 out,
404 " {} ((val & {:#x}) == {:#x}) {{",
405 keyword, mask, value
406 )
407 .unwrap();
408
409 for frag in &instr.fragments {
413 let all_literal = frag
414 .pieces
415 .iter()
416 .all(|p| matches!(p, FormatPiece::Literal(_)));
417 if all_literal {
418 let s: String = frag
419 .pieces
420 .iter()
421 .map(|p| {
422 if let FormatPiece::Literal(lit) = p {
423 lit.as_str()
424 } else {
425 ""
426 }
427 })
428 .collect();
429 writeln!(out, " // {}.{} = \"{}\"", instr.name, frag.name, s).unwrap();
430 }
431 }
432
433 let frag_values: Vec<String> = instr
435 .fragments
436 .iter()
437 .map(|frag| {
438 let all_literal = frag
439 .pieces
440 .iter()
441 .all(|p| matches!(p, FormatPiece::Literal(_)));
442 if all_literal {
443 let s: String = frag
444 .pieces
445 .iter()
446 .map(|p| {
447 if let FormatPiece::Literal(lit) = p {
448 lit.as_str()
449 } else {
450 ""
451 }
452 })
453 .collect();
454 format!("\"{}\"", s)
455 } else {
456 "\"\"".to_string()
458 }
459 })
460 .collect();
461
462 writeln!(
463 out,
464 " return {} {{ {} }};",
465 type_name,
466 frag_values.join(", ")
467 )
468 .unwrap();
469 }
470
471 if !sd.instructions.is_empty() {
472 writeln!(out, " }}").unwrap();
473 }
474 writeln!(out, " return std::nullopt;").unwrap();
475 writeln!(out, "}}").unwrap();
476 writeln!(out).unwrap();
477}
478
479fn compute_instruction_mask_value_sub(instr: &ValidatedSubInstruction) -> (u64, u64) {
480 let mut mask: u64 = 0;
481 let mut value: u64 = 0;
482 for seg in &instr.segments {
483 if let Segment::Fixed {
484 ranges, pattern, ..
485 } = seg
486 {
487 let mut bit_idx = 0;
488 for range in ranges {
489 for i in 0..range.width() {
490 if bit_idx < pattern.len() {
491 let bit = pattern[bit_idx];
492 if bit != Bit::Wildcard {
493 let hw_bit = range.start - i;
494 mask |= 1u64 << hw_bit;
495 if bit == Bit::One {
496 value |= 1u64 << hw_bit;
497 }
498 }
499 bit_idx += 1;
500 }
501 }
502 }
503 }
504 }
505 (mask, value)
506}
507
508fn emit_map_functions(out: &mut String, def: &ValidatedDef) {
510 for map_def in &def.maps {
511 let params: Vec<String> = map_def
512 .params
513 .iter()
514 .map(|p| format!("int {}", p))
515 .collect();
516 writeln!(
517 out,
518 "inline const char* {}({}) {{",
519 map_def.name,
520 params.join(", ")
521 )
522 .unwrap();
523
524 let key_var = if map_def.params.len() == 1 {
525 map_def.params[0].clone()
526 } else {
527 String::new()
529 };
530
531 if map_def.params.len() == 1 {
532 writeln!(out, " switch ({}) {{", key_var).unwrap();
533 for entry in &map_def.entries {
534 if entry.keys.len() == 1 && entry.keys[0] == MapKey::Wildcard {
535 continue;
536 }
537 if let Some(MapKey::Value(v)) = entry.keys.first() {
538 let s = pieces_to_str(&entry.output);
539 writeln!(out, " case {}: return \"{}\";", v, s).unwrap();
540 }
541 }
542
543 let default_str = map_def
544 .entries
545 .iter()
546 .find(|e| e.keys.len() == 1 && e.keys[0] == MapKey::Wildcard)
547 .map(|e| pieces_to_str(&e.output))
548 .unwrap_or_else(|| "???".to_string());
549 writeln!(out, " default: return \"{}\";", default_str).unwrap();
550 writeln!(out, " }}").unwrap();
551 } else {
552 for entry in &map_def.entries {
554 if entry.keys.iter().any(|k| *k == MapKey::Wildcard) {
555 continue;
556 }
557 let conds: Vec<String> = entry
558 .keys
559 .iter()
560 .zip(map_def.params.iter())
561 .map(|(k, p)| {
562 if let MapKey::Value(v) = k {
563 format!("{} == {}", p, v)
564 } else {
565 "true".to_string()
566 }
567 })
568 .collect();
569 let s = pieces_to_str(&entry.output);
570 writeln!(out, " if ({}) return \"{}\";", conds.join(" && "), s).unwrap();
571 }
572 writeln!(out, " return \"???\";").unwrap();
573 }
574
575 writeln!(out, "}}").unwrap();
576 writeln!(out).unwrap();
577 }
578
579 for sd in &def.sub_decoders {
581 for map_def in &sd.maps {
582 let params: Vec<String> = map_def
583 .params
584 .iter()
585 .map(|p| format!("int {}", p))
586 .collect();
587 writeln!(
588 out,
589 "inline const char* {}({}) {{",
590 map_def.name,
591 params.join(", ")
592 )
593 .unwrap();
594 writeln!(out, " switch ({}) {{", map_def.params[0]).unwrap();
595 for entry in &map_def.entries {
596 if entry.keys.len() == 1 && entry.keys[0] == MapKey::Wildcard {
597 continue;
598 }
599 if let Some(MapKey::Value(v)) = entry.keys.first() {
600 let s = pieces_to_str(&entry.output);
601 writeln!(out, " case {}: return \"{}\";", v, s).unwrap();
602 }
603 }
604 let default_str = map_def
605 .entries
606 .iter()
607 .find(|e| e.keys.len() == 1 && e.keys[0] == MapKey::Wildcard)
608 .map(|e| pieces_to_str(&e.output))
609 .unwrap_or_else(|| "???".to_string());
610 writeln!(out, " default: return \"{}\";", default_str).unwrap();
611 writeln!(out, " }}").unwrap();
612 writeln!(out, "}}").unwrap();
613 writeln!(out).unwrap();
614 }
615 }
616}
617
618fn pieces_to_str(pieces: &[FormatPiece]) -> String {
619 let mut s = String::new();
620 for piece in pieces {
621 if let FormatPiece::Literal(lit) = piece {
622 s.push_str(lit);
623 }
624 }
625 s
626}
627
628fn emit_decode_function(
630 out: &mut String,
631 def: &ValidatedDef,
632 tree: &DecodeNode,
633 word_type: &str,
634 unit_bytes: u32,
635 endian: &ByteEndian,
636 variable_length: bool,
637 type_maps: &HashMap<String, String>,
638) {
639 writeln!(
640 out,
641 "inline std::optional<Instruction> decode(const uint8_t* data, size_t len) {{"
642 )
643 .unwrap();
644 writeln!(out, " if (len < {}) return std::nullopt;", unit_bytes).unwrap();
645
646 emit_word_read(out, "opcode", word_type, 0, unit_bytes, endian, 1);
648
649 emit_tree_cpp(
650 out,
651 tree,
652 def,
653 1,
654 word_type,
655 unit_bytes,
656 endian,
657 variable_length,
658 type_maps,
659 );
660
661 writeln!(out, "}}").unwrap();
662 writeln!(out).unwrap();
663}
664
665fn emit_word_read(
667 out: &mut String,
668 var_name: &str,
669 word_type: &str,
670 offset: u32,
671 unit_bytes: u32,
672 endian: &ByteEndian,
673 indent: usize,
674) {
675 let pad = " ".repeat(indent);
676 match (unit_bytes, endian) {
677 (1, _) => {
678 writeln!(out, "{}{} {} = data[{}];", pad, word_type, var_name, offset).unwrap();
679 }
680 (2, ByteEndian::Big) => {
681 writeln!(
682 out,
683 "{}{} {} = (static_cast<uint16_t>(data[{}]) << 8) | data[{}];",
684 pad,
685 word_type,
686 var_name,
687 offset,
688 offset + 1
689 )
690 .unwrap();
691 }
692 (2, ByteEndian::Little) => {
693 writeln!(
694 out,
695 "{}{} {} = data[{}] | (static_cast<uint16_t>(data[{}]) << 8);",
696 pad,
697 word_type,
698 var_name,
699 offset,
700 offset + 1
701 )
702 .unwrap();
703 }
704 (4, ByteEndian::Big) => {
705 writeln!(
706 out,
707 "{}{} {} = (static_cast<uint32_t>(data[{}]) << 24) | (static_cast<uint32_t>(data[{}]) << 16) | (static_cast<uint32_t>(data[{}]) << 8) | data[{}];",
708 pad, word_type, var_name, offset, offset + 1, offset + 2, offset + 3
709 ).unwrap();
710 }
711 (4, ByteEndian::Little) => {
712 writeln!(
713 out,
714 "{}{} {} = data[{}] | (static_cast<uint32_t>(data[{}]) << 8) | (static_cast<uint32_t>(data[{}]) << 16) | (static_cast<uint32_t>(data[{}]) << 24);",
715 pad, word_type, var_name, offset, offset + 1, offset + 2, offset + 3
716 ).unwrap();
717 }
718 _ => {
719 writeln!(out, "{}// unsupported width", pad).unwrap();
720 }
721 }
722}
723
724fn unit_read_expr(unit: u32, _word_type: &str, unit_bytes: u32, endian: &ByteEndian) -> String {
726 if unit == 0 {
727 return "opcode".to_string();
728 }
729 let offset = unit * unit_bytes;
730 match (unit_bytes, endian) {
731 (1, _) => format!("data[{}]", offset),
732 (2, ByteEndian::Big) => format!(
733 "(static_cast<uint16_t>(data[{}]) << 8 | data[{}])",
734 offset,
735 offset + 1
736 ),
737 (2, ByteEndian::Little) => format!(
738 "(data[{}] | static_cast<uint16_t>(data[{}]) << 8)",
739 offset,
740 offset + 1
741 ),
742 (4, ByteEndian::Big) => format!(
743 "(static_cast<uint32_t>(data[{}]) << 24 | static_cast<uint32_t>(data[{}]) << 16 | static_cast<uint32_t>(data[{}]) << 8 | data[{}])",
744 offset,
745 offset + 1,
746 offset + 2,
747 offset + 3
748 ),
749 (4, ByteEndian::Little) => format!(
750 "(data[{}] | static_cast<uint32_t>(data[{}]) << 8 | static_cast<uint32_t>(data[{}]) << 16 | static_cast<uint32_t>(data[{}]) << 24)",
751 offset,
752 offset + 1,
753 offset + 2,
754 offset + 3
755 ),
756 _ => "0".to_string(),
757 }
758}
759
760fn extract_expr(
762 var: &str,
763 ranges: &[BitRange],
764 word_type: &str,
765 unit_bytes: u32,
766 endian: &ByteEndian,
767) -> String {
768 if ranges.is_empty() {
769 return "0".to_string();
770 }
771
772 if ranges.len() == 1 {
773 let range = ranges[0];
774 let source = if range.unit == 0 {
775 var.to_string()
776 } else {
777 unit_read_expr(range.unit, word_type, unit_bytes, endian)
778 };
779 let width = range.width();
780 let shift = range.end;
781 let mask = (1u64 << width) - 1;
782 if shift == 0 {
783 format!("({} & {:#x})", source, mask)
784 } else {
785 format!("(({} >> {}) & {:#x})", source, shift, mask)
786 }
787 } else {
788 let mut parts = Vec::new();
789 let mut accumulated = 0u32;
790 for range in ranges {
791 let source = if range.unit == 0 {
792 var.to_string()
793 } else {
794 unit_read_expr(range.unit, word_type, unit_bytes, endian)
795 };
796 let width = range.width();
797 let shift = range.end;
798 let mask = (1u64 << width) - 1;
799 let extracted = if shift == 0 {
800 format!("({} & {:#x})", source, mask)
801 } else {
802 format!("(({} >> {}) & {:#x})", source, shift, mask)
803 };
804 if accumulated > 0 {
805 parts.push(format!("({} << {})", extracted, accumulated));
806 } else {
807 parts.push(extracted);
808 }
809 accumulated += width;
810 }
811 parts.join(" | ")
812 }
813}
814
815fn leaf_guard(
817 instr: &ValidatedInstruction,
818 word_type: &str,
819 unit_bytes: u32,
820 endian: &ByteEndian,
821) -> Option<String> {
822 let fixed_bits = instr.fixed_bits();
823 if fixed_bits.is_empty() {
824 return None;
825 }
826
827 let mut units_map: HashMap<u32, Vec<(u32, Bit)>> = HashMap::new();
828 for (unit, hw_bit, bit) in fixed_bits {
829 units_map.entry(unit).or_default().push((hw_bit, bit));
830 }
831
832 let mut conditions = Vec::new();
833 for (unit, bits) in &units_map {
834 let (mask, value) = compute_mask_value(bits);
835 if mask != 0 {
836 let source = if *unit == 0 {
837 "opcode".to_string()
838 } else {
839 unit_read_expr(*unit, word_type, unit_bytes, endian)
840 };
841 conditions.push(format!("({} & {:#x}) == {:#x}", source, mask, value));
842 }
843 }
844
845 if conditions.is_empty() {
846 None
847 } else {
848 Some(conditions.join(" && "))
849 }
850}
851
852fn compute_mask_value(fixed_bits: &[(u32, Bit)]) -> (u64, u64) {
853 let mut mask: u64 = 0;
854 let mut value: u64 = 0;
855 for &(bit_pos, bit_val) in fixed_bits {
856 if bit_val == Bit::Wildcard {
857 continue;
858 }
859 mask |= 1u64 << bit_pos;
860 if bit_val == Bit::One {
861 value |= 1u64 << bit_pos;
862 }
863 }
864 (mask, value)
865}
866
867fn apply_transforms(
869 extract: &str,
870 resolved: &ResolvedFieldType,
871 type_maps: &HashMap<String, String>,
872) -> String {
873 let mut expr = extract.to_string();
874
875 for transform in &resolved.transforms {
876 match transform {
877 Transform::SignExtend(n) => {
878 let signed = cpp_signed_type(&resolved.base_type);
879 let bits = type_bits(&resolved.base_type);
880 expr = format!(
881 "static_cast<{}>(static_cast<{}>(({}) << ({} - {})) >> ({} - {}))",
882 cpp_type_for(&resolved.base_type),
883 signed,
884 expr,
885 bits,
886 n,
887 bits,
888 n
889 );
890 }
891 Transform::ZeroExtend(_) => {}
892 Transform::ShiftLeft(n) => {
893 expr = format!("(({}) << {})", expr, n);
894 }
895 }
896 }
897
898 if let Some(ref sd_name) = resolved.sub_decoder {
900 let decode_fn = format!("decode_{}", to_snake_case(sd_name));
901 return format!(
902 "{}(static_cast<{}>({})).value()",
903 decode_fn,
904 cpp_word_type(type_bits(&resolved.base_type).min(32)),
905 expr
906 );
907 }
908
909 if let Some(alias) = &resolved.alias_name {
911 if let Some(mapped) = type_maps.get(alias) {
912 return format!("static_cast<{}>({})", mapped, expr);
913 }
914 }
915
916 match resolved.display_format {
918 Some(DisplayFormat::SignedHex) => {
919 return format!("SignedHex(static_cast<int32_t>({}))", expr);
920 }
921 Some(DisplayFormat::Hex) => {
922 return format!("Hex(static_cast<uint32_t>({}))", expr);
923 }
924 None => {}
925 }
926
927 if resolved.base_type == "bool" {
928 format!("({}) != 0", expr)
929 } else {
930 format!(
931 "static_cast<{}>({})",
932 cpp_type_for(&resolved.base_type),
933 expr
934 )
935 }
936}
937
938fn emit_tree_cpp(
940 out: &mut String,
941 node: &DecodeNode,
942 def: &ValidatedDef,
943 indent: usize,
944 word_type: &str,
945 unit_bytes: u32,
946 endian: &ByteEndian,
947 variable_length: bool,
948 type_maps: &HashMap<String, String>,
949) {
950 let pad = " ".repeat(indent);
951 match node {
952 DecodeNode::Leaf { instruction_index } => {
953 let instr = &def.instructions[*instruction_index];
954 if let Some(guard) = leaf_guard(instr, word_type, unit_bytes, endian) {
955 writeln!(out, "{}if ({}) {{", pad, guard).unwrap();
956 emit_return_instruction(
957 out,
958 instr,
959 indent + 1,
960 word_type,
961 unit_bytes,
962 endian,
963 variable_length,
964 type_maps,
965 );
966 writeln!(out, "{}}} else {{", pad).unwrap();
967 writeln!(out, "{} return std::nullopt;", pad).unwrap();
968 writeln!(out, "{}}}", pad).unwrap();
969 } else {
970 emit_return_instruction(
971 out,
972 instr,
973 indent,
974 word_type,
975 unit_bytes,
976 endian,
977 variable_length,
978 type_maps,
979 );
980 }
981 }
982 DecodeNode::PriorityLeaves { candidates } => {
983 for (i, &idx) in candidates.iter().enumerate() {
984 let instr = &def.instructions[idx];
985 let guard = leaf_guard(instr, word_type, unit_bytes, endian);
986 if i == 0 {
987 if let Some(g) = guard {
988 writeln!(out, "{}if ({}) {{", pad, g).unwrap();
989 emit_return_instruction(
990 out,
991 instr,
992 indent + 1,
993 word_type,
994 unit_bytes,
995 endian,
996 variable_length,
997 type_maps,
998 );
999 } else {
1000 emit_return_instruction(
1001 out,
1002 instr,
1003 indent,
1004 word_type,
1005 unit_bytes,
1006 endian,
1007 variable_length,
1008 type_maps,
1009 );
1010 break;
1011 }
1012 } else if i == candidates.len() - 1 {
1013 if let Some(g) = guard {
1014 writeln!(out, "{}}} else if ({}) {{", pad, g).unwrap();
1015 emit_return_instruction(
1016 out,
1017 instr,
1018 indent + 1,
1019 word_type,
1020 unit_bytes,
1021 endian,
1022 variable_length,
1023 type_maps,
1024 );
1025 writeln!(out, "{}}} else {{", pad).unwrap();
1026 writeln!(out, "{} return std::nullopt;", pad).unwrap();
1027 writeln!(out, "{}}}", pad).unwrap();
1028 } else {
1029 writeln!(out, "{}}} else {{", pad).unwrap();
1030 emit_return_instruction(
1031 out,
1032 instr,
1033 indent + 1,
1034 word_type,
1035 unit_bytes,
1036 endian,
1037 variable_length,
1038 type_maps,
1039 );
1040 writeln!(out, "{}}}", pad).unwrap();
1041 }
1042 } else {
1043 let g = guard.unwrap_or_else(|| "true".to_string());
1044 writeln!(out, "{}}} else if ({}) {{", pad, g).unwrap();
1045 emit_return_instruction(
1046 out,
1047 instr,
1048 indent + 1,
1049 word_type,
1050 unit_bytes,
1051 endian,
1052 variable_length,
1053 type_maps,
1054 );
1055 }
1056 }
1057 }
1058 DecodeNode::Fail => {
1059 writeln!(out, "{}return std::nullopt;", pad).unwrap();
1060 }
1061 DecodeNode::Branch {
1062 range,
1063 arms,
1064 default,
1065 } => {
1066 let ext = extract_expr("opcode", &[*range], word_type, unit_bytes, endian);
1067 writeln!(out, "{}switch ({}) {{", pad, ext).unwrap();
1068 for (value, child) in arms {
1069 writeln!(out, "{}case {:#x}: {{", pad, value).unwrap();
1070 emit_tree_cpp(
1071 out,
1072 child,
1073 def,
1074 indent + 1,
1075 word_type,
1076 unit_bytes,
1077 endian,
1078 variable_length,
1079 type_maps,
1080 );
1081 writeln!(out, "{} break;", pad).unwrap();
1082 writeln!(out, "{}}}", pad).unwrap();
1083 }
1084 writeln!(out, "{}default: {{", pad).unwrap();
1085 emit_tree_cpp(
1086 out,
1087 default,
1088 def,
1089 indent + 1,
1090 word_type,
1091 unit_bytes,
1092 endian,
1093 variable_length,
1094 type_maps,
1095 );
1096 writeln!(out, "{} break;", pad).unwrap();
1097 writeln!(out, "{}}}", pad).unwrap();
1098 writeln!(out, "{}}}", pad).unwrap();
1099 }
1100 }
1101}
1102
1103fn emit_return_instruction(
1105 out: &mut String,
1106 instr: &ValidatedInstruction,
1107 indent: usize,
1108 word_type: &str,
1109 unit_bytes: u32,
1110 endian: &ByteEndian,
1111 variable_length: bool,
1112 type_maps: &HashMap<String, String>,
1113) {
1114 let pad = " ".repeat(indent);
1115 let unit_count = instr.unit_count();
1116 let bytes_consumed = unit_count * unit_bytes;
1117 let variant = to_pascal_case(&instr.name);
1118
1119 if variable_length && unit_count > 1 {
1120 writeln!(
1121 out,
1122 "{}if (len < {}) return std::nullopt;",
1123 pad, bytes_consumed
1124 )
1125 .unwrap();
1126 }
1127
1128 if instr.resolved_fields.is_empty() {
1129 writeln!(
1130 out,
1131 "{}return Instruction {{ Opcode::{}, {} }};",
1132 pad, variant, bytes_consumed
1133 )
1134 .unwrap();
1135 } else {
1136 writeln!(out, "{}{{", pad).unwrap();
1137 writeln!(out, "{} Instruction insn{{}};", pad).unwrap();
1138 writeln!(out, "{} insn.opcode = Opcode::{};", pad, variant).unwrap();
1139 writeln!(out, "{} insn.size = {};", pad, bytes_consumed).unwrap();
1140 for field in &instr.resolved_fields {
1141 let ext = extract_expr("opcode", &field.ranges, word_type, unit_bytes, endian);
1142 let expr = apply_transforms(&ext, &field.resolved_type, type_maps);
1143 writeln!(
1144 out,
1145 "{} insn.{}.{} = {};",
1146 pad, instr.name, field.name, expr
1147 )
1148 .unwrap();
1149 }
1150 writeln!(out, "{} return insn;", pad).unwrap();
1151 writeln!(out, "{}}}", pad).unwrap();
1152 }
1153}
1154
1155fn emit_format_function(
1157 out: &mut String,
1158 def: &ValidatedDef,
1159 _type_maps: &HashMap<String, String>,
1160 _opts: &CppOptions,
1161) {
1162 writeln!(out, "inline std::string format(const Instruction& insn) {{").unwrap();
1163 writeln!(out, " switch (insn.opcode) {{").unwrap();
1164
1165 for instr in &def.instructions {
1166 let variant = to_pascal_case(&instr.name);
1167 writeln!(out, " case Opcode::{}: {{", variant).unwrap();
1168
1169 if instr.format_lines.is_empty() {
1170 writeln!(out, " return \"{}\";", instr.name).unwrap();
1171 } else {
1172 emit_format_lines_cpp(out, instr, 2);
1173 }
1174
1175 writeln!(out, " }}").unwrap();
1176 }
1177
1178 writeln!(out, " default: return \"???\";").unwrap();
1179 writeln!(out, " }}").unwrap();
1180 writeln!(out, "}}").unwrap();
1181 writeln!(out).unwrap();
1182}
1183
1184fn emit_format_lines_cpp(out: &mut String, instr: &ValidatedInstruction, indent: usize) {
1186 let pad = " ".repeat(indent);
1187
1188 if instr.format_lines.len() == 1 && instr.format_lines[0].guard.is_none() {
1189 let fl = &instr.format_lines[0];
1190 emit_std_format_call(out, &fl.pieces, instr, &pad);
1191 return;
1192 }
1193
1194 for (i, fl) in instr.format_lines.iter().enumerate() {
1195 if let Some(guard) = &fl.guard {
1196 let guard_code = guard_to_cpp(guard, instr);
1197 if i == 0 {
1198 writeln!(out, "{}if ({}) {{", pad, guard_code).unwrap();
1199 } else {
1200 writeln!(out, "{}}} else if ({}) {{", pad, guard_code).unwrap();
1201 }
1202 emit_std_format_call(out, &fl.pieces, instr, &format!("{} ", pad));
1203 } else {
1204 if i > 0 {
1205 writeln!(out, "{}}} else {{", pad).unwrap();
1206 }
1207 emit_std_format_call(out, &fl.pieces, instr, &format!("{} ", pad));
1208 }
1209 }
1210
1211 if instr.format_lines.len() > 1
1212 || instr
1213 .format_lines
1214 .first()
1215 .map_or(false, |fl| fl.guard.is_some())
1216 {
1217 writeln!(out, "{}}}", pad).unwrap();
1218 }
1219}
1220
1221fn emit_std_format_call(
1224 out: &mut String,
1225 pieces: &[FormatPiece],
1226 instr: &ValidatedInstruction,
1227 pad: &str,
1228) {
1229 let mut fmt_str = String::new();
1230 let mut args: Vec<String> = Vec::new();
1231
1232 for piece in pieces {
1233 match piece {
1234 FormatPiece::Literal(lit) => {
1235 for ch in lit.chars() {
1237 match ch {
1238 '{' => fmt_str.push_str("{{"),
1239 '}' => fmt_str.push_str("}}"),
1240 _ => fmt_str.push(ch),
1241 }
1242 }
1243 }
1244 FormatPiece::FieldRef { expr, spec } => {
1245 let cpp_expr = expr_to_cpp(expr, instr);
1246 if let Some(spec) = spec {
1248 fmt_str.push_str(&format!("{{:{}}}", translate_std_format_spec(spec)));
1249 } else {
1250 fmt_str.push_str("{}");
1251 }
1252 args.push(cpp_expr);
1253 }
1254 }
1255 }
1256
1257 if args.is_empty() {
1258 writeln!(out, "{}return \"{}\";", pad, fmt_str).unwrap();
1259 } else {
1260 writeln!(
1261 out,
1262 "{}return std::format(\"{}\", {});",
1263 pad,
1264 fmt_str,
1265 args.join(", ")
1266 )
1267 .unwrap();
1268 }
1269}
1270
1271fn translate_std_format_spec(spec: &str) -> String {
1274 spec.to_string()
1276}
1277
1278fn expr_to_cpp(expr: &FormatExpr, instr: &ValidatedInstruction) -> String {
1280 match expr {
1281 FormatExpr::Field(name) => {
1282 format!("insn.{}.{}", instr.name, name)
1283 }
1284 FormatExpr::Ternary {
1285 field,
1286 if_nonzero,
1287 if_zero,
1288 } => {
1289 let else_val = if_zero.as_deref().unwrap_or("");
1290 format!(
1291 "(insn.{}.{} ? \"{}\" : \"{}\")",
1292 instr.name, field, if_nonzero, else_val
1293 )
1294 }
1295 FormatExpr::Arithmetic { left, op, right } => {
1296 let l = expr_to_cpp(left, instr);
1297 let r = expr_to_cpp(right, instr);
1298 let op_str = match op {
1299 ArithOp::Add => "+",
1300 ArithOp::Sub => "-",
1301 ArithOp::Mul => "*",
1302 ArithOp::Div => "/",
1303 ArithOp::Mod => "%",
1304 };
1305 format!("({} {} {})", l, op_str, r)
1306 }
1307 FormatExpr::IntLiteral(val) => format!("{}", val),
1308 FormatExpr::MapCall { map_name, args } => {
1309 let arg_strs: Vec<String> = args.iter().map(|a| expr_to_cpp(a, instr)).collect();
1310 format!("{}({})", map_name, arg_strs.join(", "))
1311 }
1312 FormatExpr::BuiltinCall { func, args } => {
1313 let arg_strs: Vec<String> = args.iter().map(|a| expr_to_cpp(a, instr)).collect();
1314 match func {
1315 BuiltinFunc::RotateRight => {
1316 format!(
1317 "((static_cast<uint32_t>({}) >> {}) | (static_cast<uint32_t>({}) << (32 - {})))",
1318 arg_strs.first().map(|s| s.as_str()).unwrap_or("0"),
1319 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0"),
1320 arg_strs.first().map(|s| s.as_str()).unwrap_or("0"),
1321 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0"),
1322 )
1323 }
1324 BuiltinFunc::RotateLeft => {
1325 format!(
1326 "((static_cast<uint32_t>({}) << {}) | (static_cast<uint32_t>({}) >> (32 - {})))",
1327 arg_strs.first().map(|s| s.as_str()).unwrap_or("0"),
1328 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0"),
1329 arg_strs.first().map(|s| s.as_str()).unwrap_or("0"),
1330 arg_strs.get(1).map(|s| s.as_str()).unwrap_or("0"),
1331 )
1332 }
1333 }
1334 }
1335 FormatExpr::SubDecoderAccess { field, fragment } => {
1336 format!("insn.{}.{}.{}", instr.name, field, fragment)
1337 }
1338 }
1339}
1340
1341fn guard_to_cpp(guard: &Guard, instr: &ValidatedInstruction) -> String {
1343 let conditions: Vec<String> = guard
1344 .conditions
1345 .iter()
1346 .map(|cond| {
1347 let left = guard_operand_cpp(&cond.left, instr);
1348 let right = guard_operand_cpp(&cond.right, instr);
1349 let op = match cond.op {
1350 CompareOp::Eq => "==",
1351 CompareOp::Ne => "!=",
1352 CompareOp::Lt => "<",
1353 CompareOp::Le => "<=",
1354 CompareOp::Gt => ">",
1355 CompareOp::Ge => ">=",
1356 };
1357 format!("{} {} {}", left, op, right)
1358 })
1359 .collect();
1360 conditions.join(" && ")
1361}
1362
1363fn guard_operand_cpp(operand: &GuardOperand, instr: &ValidatedInstruction) -> String {
1364 match operand {
1365 GuardOperand::Field(name) => format!("insn.{}.{}", instr.name, name),
1366 GuardOperand::Literal(val) => format!("{}", val),
1367 GuardOperand::Expr { left, op, right } => {
1368 let l = guard_operand_cpp(left, instr);
1369 let r = guard_operand_cpp(right, instr);
1370 let op_str = match op {
1371 ArithOp::Add => "+",
1372 ArithOp::Sub => "-",
1373 ArithOp::Mul => "*",
1374 ArithOp::Div => "/",
1375 ArithOp::Mod => "%",
1376 };
1377 format!("({} {} {})", l, op_str, r)
1378 }
1379 }
1380}