1use serde_derive::Deserialize;
57use std::{collections::HashMap, fs, path::PathBuf, str::FromStr};
58use toml;
59use crate::{
60 cli::RifGenArgs, comp::comp_inst::Comp, generator::{
61 casing::Casing, gen_adoc::GeneratorAdoc, gen_c::GeneratorC, gen_common::GeneratorBaseSetting, gen_html::GeneratorHtml, gen_ipxact::GeneratorIpXact, gen_json::GeneratorJson, gen_latex::GeneratorLatex, gen_mif::GeneratorMif, gen_py::{GeneratorPy, PyVersion}, gen_ral::GeneratorRal, gen_sv::GeneratorSv, gen_svd::GeneratorSvd, gen_vhdl::GeneratorVhdl, trait_doc::GeneratorDoc, trait_hw::GeneratorHw, trait_sw::GeneratorSw
62 }, parser::{parser_expr::ParamValues, ParserCfg, RifGenSrc, RsvdKeywordSel}, rifgen::{Interface, SuffixInfo}
63};
64
65#[derive(Debug, Clone, PartialEq)]
66pub enum RifGenTarget {
67 Sv,
69 Ral,
71 Vhdl,
73 C,
75 Py,
77 Html,
79 Latex,
81 Mif,
83 Svd,
85 Json,
87 Adoc,
89 IpXact,
91 Custom(String),
93}
94
95impl From<&str> for RifGenTarget {
96
97 fn from(s: &str) -> Self {
98 let s_lc = s.to_lowercase();
99 match s_lc.as_ref() {
100 "sv" => RifGenTarget::Sv,
101 "ral" => RifGenTarget::Ral,
102 "vhdl" => RifGenTarget::Vhdl,
103 "c" => RifGenTarget::C,
104 "py" => RifGenTarget::Py,
105 "html" => RifGenTarget::Html,
106 "tex" | "latex" => RifGenTarget::Latex,
107 "mif" => RifGenTarget::Mif,
108 "svd" => RifGenTarget::Svd,
109 "json" => RifGenTarget::Json,
110 "adoc" => RifGenTarget::Adoc,
111 "ipxact" => RifGenTarget::IpXact,
112 _ => RifGenTarget::Custom(s_lc),
113 }
114 }
115}
116
117impl std::fmt::Display for RifGenTarget {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 match self {
120 RifGenTarget::Sv => write!(f, "SystemVerilog"),
121 RifGenTarget::Ral => write!(f, "UVM Register Abstraction Layer"),
122 RifGenTarget::Vhdl => write!(f, "VHDL"),
123 RifGenTarget::C => write!(f, "C"),
124 RifGenTarget::Py => write!(f, "Python"),
125 RifGenTarget::Html => write!(f, "HTML"),
126 RifGenTarget::Latex => write!(f, "LaTeX"),
127 RifGenTarget::Mif => write!(f, "Framemaker MIF"),
128 RifGenTarget::Svd => write!(f, "SVD"),
129 RifGenTarget::Json => write!(f, "JSON"),
130 RifGenTarget::Adoc => write!(f, "AsciiDoctor"),
131 RifGenTarget::IpXact => write!(f, "IpXact"),
132 RifGenTarget::Custom(n) => write!(f, "'{n}'"),
133 }
134 }
135}
136
137impl<'de> serde::Deserialize<'de> for RifGenTarget {
138 fn deserialize<D: serde::Deserializer<'de> >(d: D) -> Result<Self, D::Error> {
139 let s = String::deserialize(d)?;
140 Ok(RifGenTarget::from(s.as_ref()))
141 }
142}
143
144impl RifGenTarget {
145 pub fn custom_name(&self) -> Option<String> {
146 if let RifGenTarget::Custom(n) = self {
147 Some(n.to_owned())
148 } else {
149 None
150 }
151 }
152}
153
154#[derive(Deserialize, Debug, Default)]
206#[serde(default)]
207pub struct YarigCfg {
208 pub filename: String,
210 pub path: Option<String>,
212 pub include: Vec<String>,
214 pub gen_inc: Vec<String>,
216 pub subdir: Option<String>,
218 pub local: Vec<String>,
220 pub targets: Vec<RifGenTarget>,
222 pub public: bool,
224 pub interface: Option<Interface>,
226 pub parameters: HashMap<String,isize>,
228 pub outputs: HashMap<String,String>,
230 pub auto_legacy: bool,
232 pub suffix_rtl_only: bool,
234 pub suffixes: HashMap<String, SuffixInfo>,
236 pub casing: Option<Casing>,
238 pub keywords: RsvdKeywordSel,
240 pub html : CfgHtml,
242 pub adoc : CfgAdoc,
243 pub c : CfgC,
244 pub ral: CfgRal,
245 pub rtl: CfgRtl,
246 pub py : CfgPy,
247 pub json : CfgJson,
248 pub svd: CfgSvd,
249 pub ipxact: CfgIpXact,
250 pub mif: CfgMif,
251 pub latex: CfgLatex,
252}
253
254#[derive(Deserialize, Debug, Clone, Default)]
256#[serde(deny_unknown_fields)]
257pub struct CfgHtml {
258 pub css: Option<String>,
260 pub split: Option<bool>,
262 pub casing: Option<Casing>,
264 pub subdir: Option<String>,
266}
267
268#[derive(Deserialize, Debug, Clone, Default)]
270#[serde(deny_unknown_fields)]
271pub struct CfgAdoc {
272 pub split: Option<bool>,
274 pub gen_inc: Option<Vec<String>>,
276 pub local: Option<Vec<String>>,
278 pub casing: Option<Casing>,
280 pub subdir: Option<String>,
282}
283
284#[derive(Deserialize, Debug, Clone, Default)]
286#[serde(deny_unknown_fields)]
287pub struct CfgLatex {
288 pub casing: Option<Casing>,
290 pub split: Option<bool>,
292 pub subdir: Option<String>,
294}
295
296#[derive(Deserialize, Debug, Clone, Default)]
298#[serde(deny_unknown_fields)]
299pub struct CfgC {
300 pub base_offset: Option<String>,
302 pub gen_inc: Option<Vec<String>>,
304 pub local: Option<Vec<String>>,
306 pub subdir: Option<String>,
308}
309
310#[derive(Deserialize, Debug, Clone, Default)]
312#[serde(deny_unknown_fields)]
313pub struct CfgRtl {
314 pub nb_pipe: Option<u8>,
316 pub gen_inc: Option<Vec<String>>,
318 pub local: Option<Vec<String>>,
320 pub const_reg: Option<bool>,
322 pub const_field: Option<bool>,
324 pub subdir: Option<String>,
326}
327
328#[derive(Deserialize, Debug, Clone, Default)]
330#[serde(deny_unknown_fields)]
331pub struct CfgRal {
332 pub class: Option<String>,
334 pub macro_name: Option<String>,
336 pub gen_inc: Option<Vec<String>>,
338 pub local: Option<Vec<String>>,
340 pub imports: Option<HashMap<String,String>>,
342 pub subdir: Option<String>,
344}
345
346#[derive(Deserialize, Debug, Clone, Default)]
348#[serde(deny_unknown_fields)]
349pub struct CfgPy {
350 pub class: Option<String>,
352 pub version: Option<PyVersion>,
354 pub init_file: Option<bool>,
356 pub gen_inc: Option<Vec<String>>,
358 pub local: Option<Vec<String>>,
360 pub subdir: Option<String>,
362 pub regmap_dir: Option<String>,
364}
365
366#[derive(Deserialize, Debug, Clone, Default)]
368#[serde(deny_unknown_fields)]
369pub struct CfgJson {
370 pub gen_inc: Option<Vec<String>>,
372 pub local: Option<Vec<String>>,
374 pub subdir: Option<String>,
376}
377
378#[derive(Deserialize, Debug, Clone, Default)]
380#[serde(deny_unknown_fields)]
381pub struct CfgSvd {
382 pub vendor: Option<String>,
384 pub version: Option<String>,
386}
387
388#[derive(Deserialize, Debug, Clone, Default)]
390#[serde(deny_unknown_fields)]
391pub struct CfgIpXact {
392 pub vendor: Option<String>,
394 pub library: Option<String>,
396 pub version: Option<String>,
398 pub subdir: Option<String>,
400}
401
402#[derive(Deserialize, Debug, Clone, Default)]
404#[serde(deny_unknown_fields)]
405pub struct CfgMif {
406 pub split : Option<bool>,
408 pub anchor : Option<String>,
410 pub h2 : Option<String>,
412 pub h3 : Option<String>,
414 pub table_title : Option<String>,
416 pub table_heading : Option<String>,
418 pub table_cell : Option<String>,
420 pub table_kind_rifmux : Option<String>,
422 pub table_kind_mapping : Option<String>,
424 pub table_kind_reg : Option<String>,
426 pub width_3col : Option<[f32;3]>,
428 pub width_4col : Option<[f32;4]>,
430 pub width_5col : Option<[f32;5]>,
432 pub gen_inc: Option<Vec<String>>,
434 pub local: Option<Vec<String>>,
436 pub casing: Option<Casing>,
438 pub subdir: Option<String>,
440}
441
442impl FromStr for YarigCfg {
443 type Err = String;
444
445 fn from_str(s: &str) -> Result<Self, Self::Err> {
446 toml::from_str(s).map_err(|e| format!("Error parsing configuration: {:?}", e.message()))
447 }
448}
449
450impl YarigCfg {
451
452 pub fn from_file<T : Into<PathBuf>>(path: T) -> Result<YarigCfg,String> {
467 let path: PathBuf = path.into();
468 let s = fs::read_to_string(&path)
469 .map_err(|e| format!("Error opening {path:?} : {e:?}"))?;
470 let mut cfg = Self::from_str(&s)?;
471 if let Some(d) = path.parent() {
472 if let Ok(d) = fs::canonicalize(d) {
473 cfg.path = d.to_str().map(str::to_string);
474 }
475 }
476 Ok(cfg)
477 }
478
479 pub fn from_cli(args: RifGenArgs) -> Result<YarigCfg,String> {
494 let mut cfg = if let Some(cfg_path) = &args.cfg {
495 YarigCfg::from_file(cfg_path)?
496 } else {
497 YarigCfg::default()
498 };
499 cfg.update_with_cli(args);
500 Ok(cfg)
501 }
502
503 pub fn update_with_cli(&mut self, args: RifGenArgs) {
504 if let Some(fname) = args.rif {self.filename = fname.to_owned()};
505 if !args.include.is_empty() {self.include = args.include.clone()};
506 if !args.gen_inc.is_empty() {self.gen_inc = args.gen_inc.clone()};
507 if !args.targets.is_empty() {self.targets = args.targets.to_owned()};
508 if args.public {self.public = true};
509 if args.auto_legacy {self.auto_legacy = true};
510 if args.check {self.targets.clear();}
512 else if !args.targets.is_empty() {self.targets = args.targets.to_owned()};
513 if !args.parameters.is_empty() {self.parameters.extend(args.parameters)};
515 if let Some(suffix) = args.suffix {self.suffixes.insert("".to_owned(), suffix);};
516 if args.py_version.is_some() {self.py.version = args.py_version};
517 if args.casing.is_some() {self.casing = args.casing};
518 if args.subdir.is_some() {self.subdir = args.subdir.clone()};
519 if args.interface.is_some() {self.interface = args.interface};
520 if args.suffix_rtl_only {self.suffix_rtl_only = true;}
521 if args.rtl_const_reg {self.rtl.const_reg = Some(true);}
522 if args.rtl_const_field {self.rtl.const_field = Some(true);}
523 if args.keyword_rename {self.keywords.error = false;}
524 if args.targets.contains(&RifGenTarget::Sv) {self.keywords.sv = true;}
525 if args.targets.contains(&RifGenTarget::Vhdl) {self.keywords.vhdl = true;}
526
527 for t in args.split.iter() {
528 match t {
529 RifGenTarget::Html => self.html.split = Some(true),
530 RifGenTarget::Adoc => self.adoc.split = Some(true),
531 RifGenTarget::Mif => self.mif.split = Some(true),
532 _ => eprintln!("Split target {t} not supported ! Expecting html, adoc, mif."),
533 }
534 }
535
536 let outputs = [
538 ("c" , args.output_c),
539 ("py" , args.output_py),
540 ("doc", args.output_doc),
541 ("json", args.output_json),
542 ("rtl", args.output_rtl),
543 ("sim", args.output_sim)];
544 for (k,v) in outputs.iter() {
545 if let Some(path) = v {
546 self.outputs.insert(k.to_string(), path.to_owned());
547 }
548 }
549 }
550
551 pub fn get_output_path(&self, target: &RifGenTarget) -> (PathBuf, Option<String>, String) {
553 let (keys,def) = match target {
554 RifGenTarget::C => (["c", "sw"],"c"),
555 RifGenTarget::Html => (["html", "doc"],"doc"),
556 RifGenTarget::Mif => (["mif", "doc"], "doc"),
557 RifGenTarget::Latex => (["latex", "doc"], "doc"),
558 RifGenTarget::Sv => (["sv", "rtl"], "rtl"),
559 RifGenTarget::Vhdl => (["vhdl", "rtl"], "rtl"),
560 RifGenTarget::Ral => (["ral", "sim"], "sim"),
561 RifGenTarget::Py => (["py", "sw"], "py"),
562 RifGenTarget::Json => (["json", "doc"], "doc"),
563 RifGenTarget::Adoc => (["adoc", "doc"], "doc"),
564 RifGenTarget::Svd => (["svd", "sw"], "sw"),
565 RifGenTarget::IpXact => (["ipxact", "sw"], "sw"),
566 RifGenTarget::Custom(n) => ([n.as_str(),n.as_str()], n.as_str()),
567 };
568 self.get_output_path_kd(&keys, def)
569 }
570
571 pub fn get_output_path_kd(&self, keys: &[&str], def: &str) -> (PathBuf, Option<String>, String) {
573 let mut path = format!("./{def}");
574 for k in keys.iter() {
575 if let Some(p) = self.outputs.get(*k) {
576 path = p.to_owned();
577 break;
578 }
579 }
580 let is_rel = path.starts_with('.') || !path.contains('/');
581 let path_buf : PathBuf = match (&self.path, is_rel) {
582 (Some(cwd), true) => [cwd, &path].iter().collect(),
583 _ => path.clone().into()
584 };
585
586 match (path_buf.extension().is_some(),path_buf.file_name()) {
587 (true, Some(name)) => {
588 let fname = name.to_string_lossy().to_string();
589 let parent = path_buf.parent().unwrap_or(&path_buf).to_path_buf();
590 (parent, Some(fname), path)
591 }
592 _ => (path_buf, None, path)
593 }
594 }
595
596 pub fn get_local(&self, target: &RifGenTarget) -> Option<&Vec<String>> {
597 let local = match target {
598 RifGenTarget::C => self.c.local.as_ref(),
599 RifGenTarget::Mif => self.mif.local.as_ref(),
600 RifGenTarget::Sv |
601 RifGenTarget::Vhdl => self.rtl.local.as_ref(),
602 RifGenTarget::Ral => self.ral.local.as_ref(),
603 RifGenTarget::Py => self.py.local.as_ref(),
604 RifGenTarget::Adoc => self.adoc.local.as_ref(),
605 _ => None
606 };
607 if local.is_none() {
608 Some(&self.local)
609 } else {
610 local
611 }
612 }
613
614 pub fn get_subdir(&self, target: &RifGenTarget) -> Option<&String> {
615 let subdir = match target {
616 RifGenTarget::Html => self.html.subdir.as_ref(),
617 RifGenTarget::Adoc => self.adoc.subdir.as_ref(),
618 RifGenTarget::C => self.c.subdir.as_ref(),
619 RifGenTarget::Ral => self.ral.subdir.as_ref(),
620 RifGenTarget::Sv |
621 RifGenTarget::Vhdl => self.rtl.subdir.as_ref(),
622 RifGenTarget::Py => self.py.subdir.as_ref(),
623 RifGenTarget::Json => self.json.subdir.as_ref(),
624 RifGenTarget::IpXact => self.ipxact.subdir.as_ref(),
625 RifGenTarget::Mif => self.mif.subdir.as_ref(),
626 RifGenTarget::Latex => self.latex.subdir.as_ref(),
627 _ => None
628 };
629 if subdir.is_none() {
630 self.subdir.as_ref()
631 } else {
632 subdir
633 }
634 }
635
636 pub fn gen_all(&self) -> Result<(Comp, HashMap<String, PathBuf>), String> {
660
661 let mut params = ParamValues::new();
662 self.parameters.iter().for_each(
663 |(k,v)| params.insert(k.to_owned(), *v)
664 );
665 let mut rif_path : PathBuf = self.filename.clone().into();
667 if !rif_path.exists() && rif_path.is_relative() && self.path.is_some() {
668 rif_path = [self.path.as_ref().unwrap(), &self.filename].iter().collect();
669 }
670 let parser_cfg = ParserCfg::new(self.keywords, self.auto_legacy);
671 let rif_src = RifGenSrc::from_file(&rif_path, &self.include, &parser_cfg)
672 .map_err(|e| format!("Parsing Error : {e}"))?;
673 let mut rif_obj = Comp::compile(&rif_src, &self.suffixes, ¶ms)
674 .map_err(|e| format!("Compilation failed: {e}"))?;
675 let no_suffixes = HashMap::new();
678 if self.suffix_rtl_only {
679 rif_obj.set_suffixes(&no_suffixes);
680 }
681 if let Some(intf) = &self.interface {
683 rif_obj.set_interface(intf);
684 }
685 let base_setting = GeneratorBaseSetting::new(self.casing, self.public, &self.gen_inc, &self.subdir);
687 for target in self.targets.iter() {
688 let mut setting = base_setting.clone();
689 let out = self.get_output_path(target);
690 setting.set_output((out.0, out.1));
691 if let Some(local) = self.get_local(target) {
692 setting.set_locals(target, local, &rif_src.paths, &out.2);
693 }
694 if let Some(subdir) = self.get_subdir(target) {
695 setting.subdir = Some(subdir.clone());
696 }
697 match target {
698 RifGenTarget::C => {
699 let mut g = GeneratorC::new(setting, self.c.clone());
700 g.gen_all(&rif_obj).map_err(|e| format!("C generation failed: {e}"))?;
701 },
702 RifGenTarget::Html => {
703 if let Some(split) = self.html.split {setting.split = split;}
704 let mut g = GeneratorHtml::new(setting, self.html.clone());
705 g.gen_all(&rif_obj).map_err(|e| format!("Html generation failed: {e}"))?;
706 }
707 RifGenTarget::Mif => {
708 let mut g = GeneratorMif::new(setting, self.mif.clone());
709 g.gen_all(&rif_obj).map_err(|e| format!("MIF generation failed: {e}"))?;
710 }
711 RifGenTarget::Latex => {
712 if let Some(split) = self.latex.split {setting.split = split;}
713 if let Some(casing) = self.latex.casing {setting.casing = casing;}
714 let mut g = GeneratorLatex::new(setting);
715 g.gen_all(&rif_obj).map_err(|e| format!("Latex generation failed: {e}"))?;
716 }
717 RifGenTarget::Sv => {
718 if self.suffix_rtl_only {
719 rif_obj.set_suffixes(&self.suffixes);
720 }
721 let mut g = GeneratorSv::new(setting, self.rtl.clone());
722 g.gen_all(&rif_obj).map_err(|e| format!("SystemVerilog generation failed: {e}"))?;
723 if self.suffix_rtl_only {
724 rif_obj.set_suffixes(&no_suffixes);
725 }
726 }
727 RifGenTarget::Vhdl => {
728 if self.suffix_rtl_only {
729 rif_obj.set_suffixes(&self.suffixes);
730 }
731 let mut g = GeneratorVhdl::new(setting, self.rtl.clone());
732 g.gen_all(&rif_obj).map_err(|e| format!("VHDL generation failed: {e}"))?;
733 if self.suffix_rtl_only {
734 rif_obj.set_suffixes(&no_suffixes);
735 }
736 }
737 RifGenTarget::Ral => {
738 let mut g = GeneratorRal::new(setting, self.ral.clone());
739 g.gen_all(&rif_obj).map_err(|e| format!("RAL generation failed: {e}"))?;
740 }
741 RifGenTarget::Py => {
742 let mut g = GeneratorPy::new(setting, self.py.clone());
743 g.gen_all(&rif_obj).map_err(|e| format!("Python generation failed: {e}"))?;
744 }
745 RifGenTarget::Json => {
746 let mut g = GeneratorJson::new(setting);
747 g.gen_all(&rif_obj).map_err(|e| format!("JSON generation failed: {e}"))?;
748 }
749 RifGenTarget::Adoc => {
750 let mut g = GeneratorAdoc::new(setting, self.adoc.clone());
751 g.gen_all(&rif_obj).map_err(|e| format!("AsciiDoctor generation failed: {e}"))?;
752 }
753 RifGenTarget::Svd => {
754 let mut g = GeneratorSvd::new(setting, self.svd.clone());
755 g.gen_all(&rif_obj).map_err(|e| format!("SVD generation failed: {e}"))?;
756 }
757 RifGenTarget::IpXact => {
758 let mut g = GeneratorIpXact::new(setting, self.ipxact.clone());
759 g.gen_all(&rif_obj).map_err(|e| format!("IP XACT generation failed: {e}"))?;
760 }
761 _ => {},
762 }
763 }
764 Ok((rif_obj, rif_src.paths))
765 }
766
767}