yarig/generator/
gen_adoc.rs

1use crate::{comp::comp_inst::RifInst, generator::casing::ToCasing, rifgen::EnumDef};
2
3use super::{casing::Casing, gen_common::{GeneratorBase, GeneratorBaseSetting, GeneratorCore}, trait_doc::{CellKind, GeneratorDoc, LinkKind, TableKind}};
4
5#[allow(dead_code)]
6pub struct GeneratorAdoc {
7    /// Base structure of all generators
8    core: GeneratorCore,
9    /// Flag when current document is for a RIFMux
10    is_rifmux: bool,
11    /// Name of the current component
12    comp_name: String,
13    /// Current compoment address width
14    addr_width: u8,
15    /// Flag when current RIF has multiple pages
16    multipage: bool,
17}
18
19#[allow(dead_code)]
20impl GeneratorAdoc {
21
22    pub fn new(setting: GeneratorBaseSetting) -> Self {
23        GeneratorAdoc {
24            core: GeneratorCore::new(0,setting),
25            addr_width: 8,
26            comp_name: "".to_owned(),
27            is_rifmux: false,
28            multipage: false,
29        }
30    }
31}
32
33impl GeneratorBase for GeneratorAdoc {
34
35    const EXT : &'static str = "adoc";
36
37    fn core(&self) -> &GeneratorCore {
38        &self.core
39    }
40
41    fn core_mut(&mut self) -> &mut GeneratorCore {
42        &mut self.core
43    }
44
45}
46
47impl GeneratorDoc for GeneratorAdoc {
48    const HAS_LAYOUT : bool = false;
49    const SHOW_TYPE  : bool = false;
50    const SHOW_RESET : bool = false;
51    const SHOW_SINGLE_REG : bool = false;
52    const SHOW_UNUSED : bool = true;
53
54    fn set_rif_info(&mut self, name: &str, addr_w: u8, _data_w: u8, nb_page: usize) {
55        self.addr_width = addr_w;
56        self.comp_name = name.to_owned();
57        self.multipage = nb_page > 1;
58    }
59
60    fn write_rif_title(&mut self, idx_rif: (&str,usize), desc: &str) {
61        // println!("Title RIF {} : {} | rifmux={}", idx_rif.1, idx_rif.0, self.is_rifmux);
62        if idx_rif.1 > 0 && self.is_rifmux {
63            self.write("=");
64        }
65        self.write("= ");
66        if idx_rif.1 == 0 || (!self.is_rifmux && idx_rif.1 == 1) {
67            self.write("[[top]]");
68        }
69        self.write(&format!("[[{}]]", idx_rif.0));
70        if desc.is_empty() {
71            self.write(&idx_rif.0.to_casing(Casing::Title));
72        } else {
73            self.write(desc);
74        }
75        self.write("\n\n");
76        // Function is first called with index 0 when it is a rifmux
77        if idx_rif.1==0 {
78            self.is_rifmux = true;
79        }
80    }
81
82    fn write_page_title(&mut self, idx_rif: (&str,usize), idx_page: (&str, usize), desc: (&str, Option<&str>)) {
83        if self.multipage {
84            self.write(&format!("\n=== [[{}.{}]]", idx_rif.0, idx_page.0));
85            let name = self.sanitize(idx_page.0);
86            if desc.0.is_empty() {
87                self.write(&name);
88            } else {
89                self.write(&format!("{} ({name})", desc.0));
90            }
91        } else if !desc.0.is_empty() {
92            self.write(&self.sanitize(desc.0));
93            self.write("\n");
94        }
95        if let Some(desc_detail) = desc.1 {
96            self.write_info(&self.sanitize(desc_detail));
97            self.write("\n");
98        }
99    }
100
101    fn write_reg_title(&mut self, idx_rif: (&str,usize), _idx_page: (&str, usize), idx_reg: (&str, usize), desc: &str, base_addr: Option<u64>) {
102        self.write("\n");
103        if self.is_rifmux {
104            self.write("=");
105        }
106        if self.multipage {
107            self.write("=");
108        }
109        self.write("=== ");
110        self.write(&format!("[[{}.{}]]", idx_rif.0, idx_reg.0));
111        let name = self.sanitize(idx_reg.0);
112        if desc.is_empty() {
113            self.write(&name);
114        } else {
115            self.write(&format!("{desc} ({name})"));
116        }
117        if let Some(addr) = base_addr {
118            let w = ((self.addr_width+3) >> 2) as usize;
119            self.write(&format!(" @ 0x{addr:0w$x}"));
120        }
121        self.write("\n");
122    }
123
124    fn write_reg_summary_header(&mut self, _rif: &RifInst) {
125        self.write("\n");
126        if self.is_rifmux {
127            self.write("=");
128        }
129        self.write("== Address mapping\n");
130    }
131
132    fn write_table_title(&mut self, kind: TableKind, title: &str, id: &str) {
133        let caption = match kind {
134            TableKind::Page => {
135                if self.multipage {
136                    format!("{} registers address mapping", title.to_casing(Casing::Title))
137                } else {
138                    "Registers address mapping".to_owned()
139                }
140            }
141            TableKind::Field => format!("Register {}.{title}", self.comp_name),
142            _ => self.sanitize(title)
143        };
144
145        self.write(".");
146        self.write(&caption);
147        self.write("\n[grid=rows,frame=none]\n");
148        self.write("[%header, cols=\"");
149        match kind {
150            TableKind::Rifmux  => self.write("2,4,9"),
151            TableKind::RifInst => self.write("2,4,9"),
152            TableKind::Page    => self.write("2,4,9"),
153            TableKind::RegInst => self.write("2,3,2,9"),
154            TableKind::Field   => self.write("1,3,1,2,8"),
155            _  => self.write("}"),
156        }
157        self.write("\"]\n");
158        if !id.is_empty() {
159            self.write(&format!("[[{id}]]\n"));
160        }
161        self.write("|===\n");
162    }
163
164    fn write_table_footer(&mut self, _kind: TableKind) {
165        self.write("|===\n\n");
166    }
167
168    fn write_reg_detail_header(&mut self, _rif: &RifInst) {
169        self.write("\n");
170        if self.is_rifmux {
171            self.write("=");
172        }
173        self.write("== Registers definition\n");
174    }
175
176    fn write_table_cell(&mut self, kind: (TableKind, CellKind), span: usize, txt: &str, id: &str, _tip: Option<String>) {
177        // Call sanitize on non-description cell (already caled on description)
178        let txt = if kind.1!=CellKind::Desc {self.sanitize(txt)} else {txt.to_owned()};
179        if span > 1 {
180            self.write(&format!("{span}+a|{txt}"));
181        } else if kind.0==TableKind::FieldRsvd && txt.is_empty() {
182            match kind.1 {
183                CellKind::Inst => self.write("^|-"),
184                CellKind::Desc => self.write("e|Reserved"),
185                _s => {}
186            }
187        } else {
188            let has_link = kind.1==CellKind::Inst && !id.is_empty()
189                && (kind.0==TableKind::Rifmux || kind.0==TableKind::RifInst || kind.0==TableKind::Page);
190            if kind.1 == CellKind::Desc || has_link {
191                self.write("a");
192            }
193            self.write("|");
194            if has_link {
195                self.write(&format!("<<{id},{txt}>>"));
196            } else {
197                self.write(&txt);
198            }
199        }
200        self.write("\n");
201    }
202
203    fn enum_def_desc(&mut self, def: &EnumDef) -> String {
204        let mut desc = String::with_capacity(def.len() * 16);
205        desc.push_str("\n\n");
206        for entry in &def.values {
207            let entry_name = self.sanitize(&entry.name);
208            let entry_desc = self.sanitize(entry.description.get());
209            desc.push_str(&format!(" * {} - {entry_name} : {entry_desc}\n", entry.value));
210        }
211        desc
212    }
213
214    fn sanitize(&self, raw: &str) -> String {
215        let mut txt = String::with_capacity(raw.len());
216        for l in raw.split('\n') {
217            // Insert a line return after each line
218            if !txt.is_empty() {
219                txt.push_str(" +\n");
220            }
221            // Replace starting indentation by non-breaking space
222            let nb_spc = l.chars().take_while(|c| c.is_whitespace()).count();
223            txt.push_str(&" ".repeat(nb_spc));
224            //
225            if let Some(note) = l.strip_prefix("Note: ") {
226                txt.push_str("\nNOTE: ");
227                txt.push_str(note.trim());
228            }
229            else if let Some(note) = l.strip_prefix("Tip: ") {
230                txt.push_str("\nTIP: ");
231                txt.push_str(note.trim());
232            }
233            else if let Some(note) = l.strip_prefix("Important: ") {
234                txt.push_str("\nIMPORTANT: ");
235                txt.push_str(note.trim());
236            }
237            else if let Some(note) = l.strip_prefix("Note: ") {
238                txt.push_str("\nWARNING: ");
239                txt.push_str(note.trim());
240            }
241            else if let Some(note) = l.strip_prefix("Caution: ") {
242                txt.push_str("\nCAUTION: ");
243                txt.push_str(note.trim());
244            } else {
245                txt.push_str(l.trim());
246            }
247        }
248        txt
249    }
250
251    fn write_info(&mut self, info: &str) {
252        self.write(info);
253        self.write("\n\n");
254    }
255
256    fn add_link(&mut self, kind: LinkKind, id: &str) {
257        match kind {
258            LinkKind::Top   => self.write(&format!("<<{id},Back to Top>>\n")),
259            LinkKind::Page  => self.write(&format!("<<{id},Back to register summary>>\n")),
260            LinkKind::Field => {},
261        }
262    }
263
264}