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 core: GeneratorCore,
9 is_rifmux: bool,
11 comp_name: String,
13 addr_width: u8,
15 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 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 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 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 if !txt.is_empty() {
219 txt.push_str(" +\n");
220 }
221 let nb_spc = l.chars().take_while(|c| c.is_whitespace()).count();
223 txt.push_str(&" ".repeat(nb_spc));
224 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}