diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2016-05-16 00:08:52 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2016-05-25 00:11:07 +0100 |
commit | e62203aac1876987e52f3be9db079bd4ad133b28 (patch) | |
tree | 8d12b01ca6e4790c5ef3e9da04ee646093a2008e /utils/regtools/headergen_v2.cpp | |
parent | 00a3658e5a5fdca7c0d4dc532c5721efb8418ee5 (diff) | |
download | rockbox-e62203aac1876987e52f3be9db079bd4ad133b28.tar.gz rockbox-e62203aac1876987e52f3be9db079bd4ad133b28.zip |
regtools: add headergen_v2
This new header generator works differently from the previous one:
- it uses the new format
- the generated macro follow a different style (see below)
- the generated macro are highly documented!
- it supports SCT-style platform or RMW-style ones
Compared to the old style, the new one generate a big set of macros per
register/field/enum (loosely related to iohw.h from Embedded C spec). The user
then calls generic (names are customizable) macros to perform operations:
reg_read(REG_A)
reg_read(REG_B(3))
reg_read_field(REG_A, FIELD_X)
reg_read_field(REG_B(3), COOL_FIELD)
reg_write(REG_A, 0x42)
reg_write_field(REG_A, FIELD_X(1), FIELD_Y(3), IRQ_V(FIQ))
reg_write_fielc(REG_B(3), COOL_FIELD_V(I_AM_COOL), BLA(42))
the following use RMW or SET/CLR variants, depending on target:
reg_set_field(REG_A, FLAG_U, FLAG_V)
reg_clr_field(REG_A, FIELD_X, FIELD_Y, IRQ)
reg_clr_field(REG_B(3), COOL_FIELD, BLA)
the following does clear followed by set, on SET/CLR targets:
reg_cs(REG_A, 0xff, 0x42)
reg_cs(REG_B(3), 0xaa, 0x55)
reg_cs_field(REG_A, FIELD_X(1), FIELD_Y(3), IRQ_V(FIQ))
reg_cs_field(REG_B(3), COOL_FIELD_V(I_AM_COOL))
The generator code is pretty long but has lots of documentation and lots of
macro names can be customized.
Change-Id: I5d6c5ec2406e58b5da11a5240c3a409a5bb5239a
Diffstat (limited to 'utils/regtools/headergen_v2.cpp')
-rw-r--r-- | utils/regtools/headergen_v2.cpp | 1991 |
1 files changed, 1991 insertions, 0 deletions
diff --git a/utils/regtools/headergen_v2.cpp b/utils/regtools/headergen_v2.cpp new file mode 100644 index 0000000000..bc056aaeb5 --- /dev/null +++ b/utils/regtools/headergen_v2.cpp | |||
@@ -0,0 +1,1991 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2015 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "soc_desc.hpp" | ||
22 | #include <cstdio> | ||
23 | #include <cstdlib> | ||
24 | #include <algorithm> | ||
25 | #include <map> | ||
26 | #include <sstream> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <getopt.h> | ||
30 | #include <fstream> | ||
31 | #include <set> | ||
32 | |||
33 | using namespace soc_desc; | ||
34 | |||
35 | #define HEADERGEN_VERSION "3.0.0" | ||
36 | |||
37 | /** | ||
38 | * Useful stuff | ||
39 | */ | ||
40 | |||
41 | std::string tolower(const std::string s) | ||
42 | { | ||
43 | std::string res = s; | ||
44 | for(size_t i = 0; i < s.size(); i++) | ||
45 | res[i] = ::tolower(res[i]); | ||
46 | return res; | ||
47 | } | ||
48 | |||
49 | std::string toupper(const std::string& s) | ||
50 | { | ||
51 | std::string res = s; | ||
52 | for(size_t i = 0; i < s.size(); i++) | ||
53 | res[i] = ::toupper(res[i]); | ||
54 | return res; | ||
55 | } | ||
56 | |||
57 | template< typename T > | ||
58 | std::string to_str(const T& v) | ||
59 | { | ||
60 | std::ostringstream oss; | ||
61 | oss << v; | ||
62 | return oss.str(); | ||
63 | } | ||
64 | |||
65 | template< typename T > | ||
66 | std::string to_hex(const T& v) | ||
67 | { | ||
68 | std::ostringstream oss; | ||
69 | oss << "0x" << std::hex << v; | ||
70 | return oss.str(); | ||
71 | } | ||
72 | |||
73 | std::string strsubst(const std::string& str, const std::string& pattern, | ||
74 | const std::string& subst) | ||
75 | { | ||
76 | std::string res = str; | ||
77 | size_t pos = 0; | ||
78 | while((pos = res.find(pattern, pos)) != std::string::npos) | ||
79 | { | ||
80 | res.replace(pos, pattern.size(), subst); | ||
81 | pos += subst.size(); | ||
82 | } | ||
83 | return res; | ||
84 | } | ||
85 | |||
86 | void print_context(const error_context_t& ctx) | ||
87 | { | ||
88 | for(size_t j = 0; j < ctx.count(); j++) | ||
89 | { | ||
90 | error_t e = ctx.get(j); | ||
91 | switch(e.level()) | ||
92 | { | ||
93 | case error_t::INFO: printf("[INFO]"); break; | ||
94 | case error_t::WARNING: printf("[WARN]"); break; | ||
95 | case error_t::FATAL: printf("[FATAL]"); break; | ||
96 | default: printf("[UNK]"); break; | ||
97 | } | ||
98 | if(e.location().size() != 0) | ||
99 | printf(" %s:", e.location().c_str()); | ||
100 | printf(" %s\n", e.message().c_str()); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | void print_inst(node_inst_t inst, bool end = true) | ||
105 | { | ||
106 | if(!inst.is_root()) | ||
107 | { | ||
108 | print_inst(inst.parent(), false); | ||
109 | printf(".%s", inst.name().c_str()); | ||
110 | if(inst.is_indexed()) | ||
111 | printf("[%u]", (unsigned)inst.index()); | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | printf("%s", inst.soc().get()->name.c_str()); | ||
116 | } | ||
117 | if(end) | ||
118 | printf("\n"); | ||
119 | } | ||
120 | |||
121 | void create_dir(const std::string& path) | ||
122 | { | ||
123 | mkdir(path.c_str(), 0755); | ||
124 | } | ||
125 | |||
126 | void create_alldir(const std::string& prefix, const std::string& path) | ||
127 | { | ||
128 | size_t p = path.find('/'); | ||
129 | if(p == std::string::npos) | ||
130 | return; | ||
131 | create_dir(prefix + "/" + path.substr(0, p)); | ||
132 | create_alldir(prefix + "/" + path.substr(0, p), path.substr(p + 1)); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * Printer utils | ||
137 | */ | ||
138 | |||
139 | struct limited_column_context_t | ||
140 | { | ||
141 | limited_column_context_t(size_t nr_col = 80) | ||
142 | :m_nr_col(nr_col), m_prevent_wordcut(true) {} | ||
143 | void set_prefix(const std::string& prefix) { m_prefix = prefix; } | ||
144 | void add(const std::string& text) | ||
145 | { | ||
146 | for(size_t i = 0; i < text.size();) | ||
147 | { | ||
148 | size_t offset = 0; | ||
149 | if(m_cur_line.size() == 0) | ||
150 | m_cur_line = m_prefix; | ||
151 | size_t len = std::min(text.size() - i, m_nr_col - m_cur_line.size()); | ||
152 | // prevent word cut | ||
153 | if(m_prevent_wordcut && !isspace(text[i + len - 1]) && | ||
154 | i + len < text.size() && !isspace(text[i + len])) | ||
155 | { | ||
156 | size_t pos = text.find_last_of(" \t\n\v\r\f", i + len - 1); | ||
157 | if(pos == std::string::npos || pos < i) | ||
158 | len = 0; | ||
159 | else | ||
160 | len = pos - i + 1; | ||
161 | } | ||
162 | size_t pos = text.find('\n', i); | ||
163 | if(pos != std::string::npos && pos <= i + len) | ||
164 | { | ||
165 | offset = 1; | ||
166 | len = pos - i; | ||
167 | } | ||
168 | m_cur_line += text.substr(i, len); | ||
169 | // len == 0 means we need a new line | ||
170 | if(m_cur_line.size() == m_nr_col || len == 0) | ||
171 | { | ||
172 | m_lines.push_back(m_cur_line); | ||
173 | m_cur_line = ""; | ||
174 | } | ||
175 | i += len + offset; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | std::ostream& print(std::ostream& oss) | ||
180 | { | ||
181 | for(size_t i = 0; i < m_lines.size(); i++) | ||
182 | oss << m_lines[i] << "\n"; | ||
183 | if(m_cur_line.size() != 0) | ||
184 | oss << m_cur_line << "\n"; | ||
185 | return oss; | ||
186 | } | ||
187 | |||
188 | std::string str() | ||
189 | { | ||
190 | std::ostringstream oss; | ||
191 | print(oss); | ||
192 | return oss.str(); | ||
193 | } | ||
194 | |||
195 | std::vector< std::string > m_lines; | ||
196 | std::string m_cur_line; | ||
197 | std::string m_prefix; | ||
198 | size_t m_nr_col; | ||
199 | bool m_prevent_wordcut; | ||
200 | }; | ||
201 | |||
202 | struct define_align_context_t | ||
203 | { | ||
204 | define_align_context_t():m_max_name(0) {} | ||
205 | void add(const std::string& name, const std::string& val) | ||
206 | { | ||
207 | m_lines.push_back(std::make_pair(name, val)); | ||
208 | m_max_name = std::max(m_max_name, name.size()); | ||
209 | } | ||
210 | |||
211 | void add_raw(const std::string& line) | ||
212 | { | ||
213 | m_lines.push_back(std::make_pair("", line)); | ||
214 | } | ||
215 | |||
216 | std::ostream& print(std::ostream& oss) | ||
217 | { | ||
218 | std::string define = "#define "; | ||
219 | size_t align = define.size() + m_max_name + 1; | ||
220 | align = ((align + 3) / 4) * 4; | ||
221 | |||
222 | for(size_t i = 0; i < m_lines.size(); i++) | ||
223 | { | ||
224 | std::string name = m_lines[i].first; | ||
225 | // raw entry ? | ||
226 | if(name.size() != 0) | ||
227 | { | ||
228 | name.insert(name.end(), align - define.size() - name.size(), ' '); | ||
229 | oss << define << name << m_lines[i].second << "\n"; | ||
230 | } | ||
231 | else | ||
232 | oss << m_lines[i].second; | ||
233 | } | ||
234 | return oss; | ||
235 | } | ||
236 | |||
237 | size_t m_max_name; | ||
238 | std::vector< std::pair< std::string, std::string > > m_lines; | ||
239 | }; | ||
240 | |||
241 | limited_column_context_t print_description(const std::string& desc, const std::string& prefix) | ||
242 | { | ||
243 | limited_column_context_t ctx; | ||
244 | if(desc.size() == 0) | ||
245 | return ctx; | ||
246 | ctx.set_prefix(prefix); | ||
247 | ctx.add(desc); | ||
248 | return ctx; | ||
249 | } | ||
250 | |||
251 | void print_copyright(std::ostream& fout, const std::vector< soc_ref_t >& socs) | ||
252 | { | ||
253 | fout << "\ | ||
254 | /***************************************************************************\n\ | ||
255 | * __________ __ ___.\n\ | ||
256 | * Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\ | ||
257 | * Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\ | ||
258 | * Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\ | ||
259 | * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\ | ||
260 | * \\/ \\/ \\/ \\/ \\/\n\ | ||
261 | * This file was automatically generated by headergen, DO NOT EDIT it.\n\ | ||
262 | * headergen version: " HEADERGEN_VERSION "\n"; | ||
263 | for(size_t i = 0; i < socs.size(); i++) | ||
264 | { | ||
265 | soc_t& s = *socs[i].get(); | ||
266 | if(!s.version.empty()) | ||
267 | fout << " * " << s.name << " version: " << s.version << "\n"; | ||
268 | if(!s.author.empty()) | ||
269 | { | ||
270 | fout << " * " << s.name << " authors:"; | ||
271 | for(size_t j = 0; j < s.author.size(); j++) | ||
272 | { | ||
273 | if(j != 0) | ||
274 | fout << ","; | ||
275 | fout << " " << s.author[j]; | ||
276 | } | ||
277 | fout << "\n"; | ||
278 | } | ||
279 | } | ||
280 | fout << "\ | ||
281 | *\n\ | ||
282 | * Copyright (C) 2015 by the authors\n\ | ||
283 | *\n\ | ||
284 | * This program is free software; you can redistribute it and/or\n\ | ||
285 | * modify it under the terms of the GNU General Public License\n\ | ||
286 | * as published by the Free Software Foundation; either version 2\n\ | ||
287 | * of the License, or (at your option) any later version.\n\ | ||
288 | *\n\ | ||
289 | * This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\ | ||
290 | * KIND, either express or implied.\n\ | ||
291 | *\n\ | ||
292 | ****************************************************************************/\n"; | ||
293 | } | ||
294 | |||
295 | void print_guard(std::ostream& fout, const std::string& guard, bool begin) | ||
296 | { | ||
297 | if(begin) | ||
298 | { | ||
299 | fout << "#ifndef " << guard << "\n"; | ||
300 | fout << "#define " << guard << "\n"; | ||
301 | } | ||
302 | else | ||
303 | fout << "\n#endif /* " << guard << "*/\n"; | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * Generator interface | ||
308 | */ | ||
309 | |||
310 | class abstract_generator | ||
311 | { | ||
312 | public: | ||
313 | /// set output directory (default is current directory) | ||
314 | void set_output_dir(const std::string& dir); | ||
315 | /// add a SoC to the list | ||
316 | void add_soc(const soc_t& soc); | ||
317 | /// generate headers, returns true on success | ||
318 | virtual bool generate(error_context_t& ctx) = 0; | ||
319 | protected: | ||
320 | std::vector< soc_t > m_soc; /// list of socs | ||
321 | std::string m_outdir; /// output directory path | ||
322 | }; | ||
323 | |||
324 | void abstract_generator::set_output_dir(const std::string& dir) | ||
325 | { | ||
326 | m_outdir = dir; | ||
327 | } | ||
328 | |||
329 | void abstract_generator::add_soc(const soc_t& soc) | ||
330 | { | ||
331 | m_soc.push_back(soc); | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * Common Generator | ||
336 | * | ||
337 | * This generator is an abstract class which can generate register headers while | ||
338 | * giving the user a lot of control on how the macros are named and generated. | ||
339 | * | ||
340 | * The first thing the generator will want to know is whether you want to generate | ||
341 | * selector headers or not. Selector headers are used when generating headers from | ||
342 | * several SoCs: the selector will include the right header based on some user-defined | ||
343 | * logic. For example, imagine you have two socs vsoc1000 and vsoc2000, you could | ||
344 | * generate the following files and directories: | ||
345 | * | ||
346 | * regs/ | ||
347 | * regs-vsoc.h [selector] | ||
348 | * vsoc1000/ | ||
349 | * regs-vsoc.h [vsoc1000 header] | ||
350 | * vsoc2000/ | ||
351 | * regs-vsoc.h [vsoc2000 header] | ||
352 | * | ||
353 | * The generator will call has_selectors() to determine if it should generate | ||
354 | * selector files or not. If it returns true, it will call selector_soc_dir() | ||
355 | * for each of the socs to know in which subdirectory it should include the headers. | ||
356 | * The generator will create one macro per soc, which name is given by | ||
357 | * selector_soc_macro() and it will finally include the select header YOU will | ||
358 | * have to write, which name is given by selector_include_header() | ||
359 | * The selector file will typically look like this: | ||
360 | * | ||
361 | * [regs-vsoc.h] | ||
362 | * #define VSOC1000_INCLUDE "vsoc1000/regs-vsoc.h" // returned by selector_soc_macro(vsoc1000) | ||
363 | * #define VSOC2000_INCLUDE "vsoc2000/regs-vsoc.h" // returned by selector_soc_macro(vsoc2000) | ||
364 | * #include "regs-select.h" // returned by selector_include_header() | ||
365 | * | ||
366 | * NOTE: it may happen that some header only exists in some soc (for example | ||
367 | * in vsoc2000 but not in vsoc1000), in this case the macros will only be | ||
368 | * generated for the socs in which it exists. | ||
369 | * NOTE: and this is *VERY* important: the register selector file MUST NOT | ||
370 | * be protected by include guards since it will included several times, once | ||
371 | * for each register file. | ||
372 | * | ||
373 | * The generator will create one set of files per soc. For each register, it | ||
374 | * will call register_header() to determine in which file you want the register | ||
375 | * to be put. You can put everything in one file, or one register per file, | ||
376 | * that's entirely up to you. Here is an example: | ||
377 | * | ||
378 | * register_header(vsoc1000.cpu.ctrl) -> "regs-cpu.h" | ||
379 | * register_header(vsoc1000.cpu.reset) -> "regs-cpu.h" | ||
380 | * register_header(vsoc1000.cop.ctrl) -> "regs-cop.h" | ||
381 | * register_header(vsoc1000.cop.magic) -> "regs-magic.h" | ||
382 | * | ||
383 | * regs-cpu.h: | ||
384 | * vsoc1000.cpu.ctrl | ||
385 | * vsoc1000.cpu.reset | ||
386 | * regs-cop.h: | ||
387 | * vsoc1000.cop.ctrl | ||
388 | * regs-magic.h | ||
389 | * vsoc1000.cop.magic | ||
390 | * | ||
391 | * Once the list of register files is determine, it will begin generating each | ||
392 | * file. A register header is always protected from double inclusion by an | ||
393 | * include guard. You can tweak the name by redefining header_include_guard() | ||
394 | * or keep the default behaviour which generates something like this: | ||
395 | * | ||
396 | * #ifndef __HEADERGEN_REGS_CPU_H__ | ||
397 | * #define __HEADERGEN_REGS_CPU_H__ | ||
398 | * ... | ||
399 | * #endif | ||
400 | * | ||
401 | * NOTE: the tool will also generate a copyright header which contains the Rockbox | ||
402 | * logo, a list of soc names and version, and authors in the description file. | ||
403 | * This part cannot be customised at the moment. | ||
404 | * | ||
405 | * In order to list all registers, the generator will recursively enumerate all | ||
406 | * nodes and instances. When a instance is of RANGE type, the generator can generate | ||
407 | * two types of macros: | ||
408 | * - one for each instance | ||
409 | * - one with an index parameter | ||
410 | * The generator will ask you if you want to generate one for each instance by | ||
411 | * calling register_flag(RF_GENERATE_ALL_INST) and if you want to generate a | ||
412 | * parametrized one by calling register_flag(RF_GENERATE_PARAM_INST). You can | ||
413 | * generate either one or both (or none). | ||
414 | * | ||
415 | * register_flag(vsoc.int.enable, RF_GENERATE_ALL_INST) -> true | ||
416 | * => will generate vsoc.int.enable[1], vsoc.int.enable[2], ... | ||
417 | * register_flag(vsoc.int.enable, RF_GENERATE_PARAM_INST) -> true | ||
418 | * => will generate vsoc.int.enable[n] | ||
419 | * | ||
420 | * This process will give a list of pseudo-instances: these are register instances | ||
421 | * where some ranges have a given index and some ranges are parametric. The generator | ||
422 | * will create one set of macro per pseudo-instance. The exact list of macros | ||
423 | * generated is the following: | ||
424 | * - ADDR: this macro will contain the address of the register (possibly parametrized) | ||
425 | * - TYPE: this macro will contain the type of the register (width, access) | ||
426 | * - NAME: this macro expands to the name of the register (useful for fields and other variants) | ||
427 | * - INDEX: this macro expands to the index of the register (or empty is not indexed) | ||
428 | * - VAR: this macros expands to a fake variable that can be read/written | ||
429 | * - for each field F: | ||
430 | * - BP: this macro contains the bit position of F | ||
431 | * - BM: this macro contains the bit mask of F | ||
432 | * - for each field enum value V: | ||
433 | * - BV: this macro contains the value of V (not shifted to the position) | ||
434 | * - BF: this macro generate the mask for a value: (((v) << pos) & mask) | ||
435 | * - BFV: same as BF but the parameter is the name of an enum value | ||
436 | * - BFM: this macro is like BF but ignores value returns mask | ||
437 | * - BFMV: like BFV but returns masks like BFM | ||
438 | * The generator will also create the following macros for each variant: | ||
439 | * - ADDR: same as ADDR but with offset | ||
440 | * - TYPE: same as TYPE but depends on variant | ||
441 | * - NAME: same as NAME (ie same fields) | ||
442 | * - INDEX: same as INDEX | ||
443 | * | ||
444 | * In order to generate the macro name, the generate relies on you providing detailled | ||
445 | * information. Given an pseudo-instance I and a macro type MT, the generator | ||
446 | * will always call type_xfix(MT) to know which prefix/suffix you want for the | ||
447 | * macro and generate names of the form: | ||
448 | * type_xfix(MT, true)basename(I)type_xfix(MT, false) | ||
449 | * The basename() functions will call inst_prefix() for each each instance on the | ||
450 | * pseudo-instance path, and then instance_name() to know the name. You can | ||
451 | * (and must) create a different name for parametrised instances. The basename | ||
452 | * looks like this for pseudo-inst i1.i2.i3....in: | ||
453 | * instance_name(i1)inst_prefix(i1.i2)instance_name(i1.i2)...inst_name(i1.i2...in) | ||
454 | * For field macros, the process is the same with an extra prefix returned by | ||
455 | * field_prefix() and you can select the field name with field_name() to obtain | ||
456 | * for example for field F in I: | ||
457 | * type_xfix(MT,true)basename(I)field_prefix()field_name(I.F)type_xfix(MT,false) | ||
458 | * For field enum macros, there is an extra prefix given by enum_prefix() | ||
459 | * and the enum name is given by enum_name() | ||
460 | * For variants, the basename is surrounded by prefix/suffix given by variant_xfix(): | ||
461 | * variant_xfix(var, true)basename(I)variant_xfix(var, false) | ||
462 | * | ||
463 | * Let's illustrate this on example | ||
464 | * type_xfix(MT_REG_ADDR, true) -> "RA_x" | ||
465 | * type_xfix(MT_REG_ADDR, false) -> "x_AR" | ||
466 | * instance_name(vsoc1000.cpu) -> "CPU" | ||
467 | * inst_prefix(vsoc1000.cpu.ctrl) -> "_" | ||
468 | * instance_name(vsoc1000.cpu.ctrl) -> "CTRL" | ||
469 | * => RA_xCPU_CTRLx_AR | ||
470 | * type_xfix(MT_FIELD_BF, true) -> "BF_" | ||
471 | * type_xfix(MT_FIELD_BF, false) -> "" | ||
472 | * field_prefix() -> "__" | ||
473 | * field_name(vsoc1000.cpu.ctrl.speed) -> "SPEED" | ||
474 | * => BF_CPU_CTRL__SPEED | ||
475 | * variant_xfix("set", true) -> "VAR_" | ||
476 | * variant_xfix("set", false) -> "_SET" | ||
477 | * => HW_VAR_CPU_CTRL_SET | ||
478 | * | ||
479 | * The generator will also create a macro header file, it will call macro_header() | ||
480 | * once to know the name of this file. | ||
481 | * The macro header contains useful macro to read, write and manipulate registers | ||
482 | * and fields. You must implement the macro_header_macro() method to let the | ||
483 | * generator know the name of each macro. Note that the macro header macros | ||
484 | * depend on the specific naming of the other macros, which are given by | ||
485 | * type_xfix() and field_prefix() most notably. The exact list of generated macros | ||
486 | * is the following: | ||
487 | * - BF_OR: field ORing (see details below) | ||
488 | * - BF_OM: mask ORing (same as BF_OR but except field value is the mask) | ||
489 | * | ||
490 | * The BF_OR macro is one of the most important and useful macro. It allows for | ||
491 | * compact ORing of register field, both for immediate values or value names. | ||
492 | * For this macro to work properly, there are constraints that the generator | ||
493 | * must satisfy. Notably, type_xfix(MT_FIELD_BF, true) == type_xfix(MT_FIELD_BFV, true) | ||
494 | * and similarly for MT_FIELD_BM | ||
495 | * The general format is as follows: | ||
496 | * | ||
497 | * BF_OR(<reg>, <f1>, <f2>, ...) expands to BF(<reg>,<f1>) | BF(<reg>,<f2>) | ... | ||
498 | * BM_OR(<reg>, <f1>, <f2>, ...) expands to BM(<reg>,<f1>) | BM(<reg>,<f2>) | ... | ||
499 | * | ||
500 | * Typical usages of this macro will be of the form: | ||
501 | * | ||
502 | * BF_OR(<reg>, <f1>(<v1>), <f2>(<v2>), <f3name>(<v3name>), ...) | ||
503 | * BM_OR(<reg>, <f1>, <f2>, <f3>, ...) | ||
504 | * | ||
505 | * | ||
506 | * Let's illustrate this on example. | ||
507 | * type_xfix(MT_FIELD_BF, true) -> "BF_" | ||
508 | * type_xfix(MT_FIELD_BFV, true) -> "BF_" | ||
509 | * type_xfix(MT_FIELD_BF, false) -> "BF_" | ||
510 | * type_xfix(MT_FIELD_BF, false) -> "_V" | ||
511 | * field_prefix() -> "__" | ||
512 | * enum_prefix() -> "___" | ||
513 | * macro_header_macro(MMM_BF_OR) -> "BF_OR" | ||
514 | * => BF_OR(<reg>, <f1>, <f2>, ...) expands to BF_<reg>__<f1> | BF_<reg>__<f2> | ... | ||
515 | * => BF_OR(CPU_CTRL, DIVIDER(1), PRIO_V(HIGH), SPEED(100)) | ||
516 | * expands to | ||
517 | * BF_CPU_CTRL__DIVIDER(1) | BF_CPU_CTRL__DIVIDER_V(HIGH) | BF_CPU_CTRL__SPEED(1000) | ||
518 | * expands to | ||
519 | * BF_CPU_CTRL__DIVIDER(1) | BF_CPU_CTRL__DIVIDER(BV_CPU_CTRL__DIVIDER___HIGH) | BF_CPU_CTRL__SPEED(1000) | ||
520 | * and so on... | ||
521 | * | ||
522 | */ | ||
523 | class common_generator : public abstract_generator | ||
524 | { | ||
525 | struct pseudo_node_inst_t | ||
526 | { | ||
527 | node_inst_t inst; | ||
528 | std::vector< bool > parametric; | ||
529 | }; | ||
530 | public: | ||
531 | virtual bool generate(error_context_t& ctx); | ||
532 | private: | ||
533 | void gather_files(const pseudo_node_inst_t& inst, const std::string& prefix, | ||
534 | std::map< std::string, std::vector< pseudo_node_inst_t > >& map); | ||
535 | void print_inst(const pseudo_node_inst_t& inst, bool end = true); // debug | ||
536 | std::vector< soc_ref_t > list_socs(const std::vector< pseudo_node_inst_t >& list); | ||
537 | bool generate_register(std::ostream& os, const pseudo_node_inst_t& reg); | ||
538 | bool generate_macro_header(error_context_t& ectx); | ||
539 | protected: | ||
540 | /// return true to generate selector files | ||
541 | virtual bool has_selectors() const = 0; | ||
542 | /// [selector only] return the directory name for the soc | ||
543 | virtual std::string selector_soc_dir(const soc_ref_t& ref) const = 0; | ||
544 | /// [selector only] return the header to include to select betweens socs | ||
545 | virtual std::string selector_include_header() const = 0; | ||
546 | /// [selector only] return the name of the macro to emit for each soc | ||
547 | virtual std::string selector_soc_macro(const soc_ref_t& ref) const = 0; | ||
548 | /// return the relative filename in which to put the register | ||
549 | virtual std::string register_header(const node_inst_t& inst) const = 0; | ||
550 | /// return the include guard for a file (default does its best) | ||
551 | virtual std::string header_include_guard(const std::string& filename); | ||
552 | /// return the name of the macros header to generate | ||
553 | virtual std::string macro_header() const = 0; | ||
554 | /// macro from macro header | ||
555 | enum macro_name_t | ||
556 | { | ||
557 | MN_REG_READ, /// register read | ||
558 | MN_FIELD_READ, /// register's field read | ||
559 | MN_FIELD_READX, /// register value field read | ||
560 | MN_REG_WRITE, /// register write | ||
561 | MN_REG_CLEAR_SET, /// register clear then set | ||
562 | MN_FIELD_WRITE, /// register's field(s) write | ||
563 | MN_FIELD_WRITEX, /// register's field(s) write | ||
564 | MN_FIELD_OVERWRITE, /// register full write | ||
565 | MN_FIELD_SET, /// register's field(s) set | ||
566 | MN_FIELD_CLEAR, /// register's field(s) clear | ||
567 | MN_FIELD_TOG, /// register's field(s) toggle | ||
568 | MN_FIELD_CLEAR_SET, /// register's field(s) clear then set | ||
569 | MN_FIELD_OR, /// field ORing | ||
570 | MN_FIELD_OR_MASK, /// field ORing but in fact mask ORing | ||
571 | MN_MASK_OR, /// mask ORing | ||
572 | MN_GET_VARIANT, /// get register variant | ||
573 | MN_VARIABLE, /// return variable-like for register | ||
574 | }; | ||
575 | /// return macro name defined in the macro header | ||
576 | virtual std::string macro_name(macro_name_t macro) const = 0; | ||
577 | /// flag to consider | ||
578 | enum register_flag_t | ||
579 | { | ||
580 | RF_GENERATE_ALL_INST, /// for range instance, generate one macro set per instance ? | ||
581 | RF_GENERATE_PARAM_INST, /// for range instance, generate a parametrised macro set ? | ||
582 | }; | ||
583 | /** tweak instance generaton and its children | ||
584 | * NOTE: for range flags, although the instance will be numbered, the index is | ||
585 | * to be ignored */ | ||
586 | virtual bool register_flag(const node_inst_t& inst, register_flag_t flag) const = 0; | ||
587 | /// prefix/suffix type | ||
588 | enum macro_type_t | ||
589 | { | ||
590 | MT_REG_ADDR, /// register address | ||
591 | MT_REG_TYPE, /// register type | ||
592 | MT_REG_NAME, /// register prefix for fields | ||
593 | MT_REG_INDEX, /// register index/indices | ||
594 | MT_REG_VAR, /// variable-like macro | ||
595 | MT_FIELD_BP, /// bit position of a field | ||
596 | MT_FIELD_BM, /// bit mask of a field | ||
597 | MT_FIELD_BV, /// bit value of a field enum | ||
598 | MT_FIELD_BF, /// bit field value: (v << pos) & mask | ||
599 | MT_FIELD_BFM, /// ignore value and return mask | ||
600 | MT_FIELD_BFV, /// bit field enum value: (enum_v << pos) & mask | ||
601 | MT_FIELD_BFMV, /// ignore value and return mask | ||
602 | MT_IO_TYPE, /// register io type | ||
603 | }; | ||
604 | /// register access types | ||
605 | enum access_type_t | ||
606 | { | ||
607 | AT_RO, /// read-only: write are disallowed | ||
608 | AT_RW, /// read-write: read/writes are allowed, field write by generated a RMW | ||
609 | AT_WO, /// write-only: read are disallowed, field write will set other fields to 0 | ||
610 | }; | ||
611 | /// register operation | ||
612 | enum register_op_t | ||
613 | { | ||
614 | RO_VAR, /// variable-like | ||
615 | RO_READ, /// read | ||
616 | RO_WRITE, /// write | ||
617 | RO_RMW, /// read-modify-write | ||
618 | }; | ||
619 | /// return type prefix/suffix for register macro | ||
620 | virtual std::string type_xfix(macro_type_t type, bool prefix) const = 0; | ||
621 | /// return variant prefix/suffix | ||
622 | virtual std::string variant_xfix(const std::string& variant, bool prefix) const = 0; | ||
623 | /// return instance prefix in macro name | ||
624 | virtual std::string inst_prefix(const node_inst_t& inst) const = 0; | ||
625 | /// return field prefix in field macro names | ||
626 | virtual std::string field_prefix() const = 0; | ||
627 | /// return field enum prefix in field macro names | ||
628 | virtual std::string enum_prefix() const = 0; | ||
629 | /// return the field enum name in field macro names | ||
630 | virtual std::string enum_name(const enum_ref_t& enum_) const = 0; | ||
631 | /// return instance name in macro, default is instance name then index if any | ||
632 | virtual std::string instance_name(const node_inst_t& inst, bool parametric) const; | ||
633 | /// return field name in macro, default is field name | ||
634 | virtual std::string field_name(const field_ref_t& field) const; | ||
635 | /// return the complete macro name with prefix, default uses all the other functions | ||
636 | virtual std::string macro_basename(const pseudo_node_inst_t& inst) const; | ||
637 | /// return the complete macro name with prefix, default uses macro_basename() | ||
638 | virtual std::string macro_basename(const pseudo_node_inst_t& inst, macro_type_t type) const; | ||
639 | /// generate address string for a register instance, and fill the parametric | ||
640 | /// argument list, default does it the obvious way and parameters are _n1, _n2, ... | ||
641 | virtual std::string register_address(const pseudo_node_inst_t& reg, | ||
642 | std::vector< std::string >& params) const; | ||
643 | /// return access type for a variant and a given register access | ||
644 | /// NOTE variant with the unspecified access type will be promoted to register access | ||
645 | virtual access_type_t register_access(const std::string& variant, access_t access) const = 0; | ||
646 | /// return register type name | ||
647 | virtual std::string register_type_name(access_type_t access, int width) const; | ||
648 | /// get register operation name | ||
649 | virtual std::string register_op_name(register_op_t op) const; | ||
650 | /// register operation prefix | ||
651 | virtual std::string register_op_prefix() const; | ||
652 | /// generate a macro pasting that is safe even when macro is empty | ||
653 | /// ie: safe_macro_paste(false, "A") -> ##A | ||
654 | /// ie: safe_macro_paste(false, "A") -> | ||
655 | std::string safe_macro_paste(bool left, const std::string& macro) const; | ||
656 | /// generate SCT macros using register variant ? | ||
657 | virtual bool has_sct() const = 0; | ||
658 | /// return the associated SCT variant (only if RF_GENERATE_SCT) | ||
659 | /// empty means don't generate | ||
660 | virtual std::string sct_variant(macro_name_t name) const = 0; | ||
661 | }; | ||
662 | |||
663 | std::string common_generator::instance_name(const node_inst_t& inst, bool parametric) const | ||
664 | { | ||
665 | std::ostringstream oss; | ||
666 | oss << inst.name(); | ||
667 | if(inst.is_indexed() && !parametric) | ||
668 | oss << inst.index(); | ||
669 | return oss.str(); | ||
670 | } | ||
671 | |||
672 | std::string common_generator::field_name(const field_ref_t& field) const | ||
673 | { | ||
674 | return field.get()->name; | ||
675 | } | ||
676 | |||
677 | std::string common_generator::macro_basename(const pseudo_node_inst_t& inst_) const | ||
678 | { | ||
679 | pseudo_node_inst_t inst = inst_; | ||
680 | std::string str; | ||
681 | while(!inst.inst.is_root()) | ||
682 | { | ||
683 | str = instance_name(inst.inst, inst.parametric.back()) + str; | ||
684 | inst.inst = inst.inst.parent(); | ||
685 | inst.parametric.pop_back(); | ||
686 | if(!inst.inst.is_root()) | ||
687 | str = inst_prefix(inst.inst) + str; | ||
688 | } | ||
689 | return str; | ||
690 | } | ||
691 | |||
692 | std::string common_generator::macro_basename(const pseudo_node_inst_t& inst, macro_type_t type) const | ||
693 | { | ||
694 | return type_xfix(type, true) + macro_basename(inst); | ||
695 | } | ||
696 | |||
697 | void common_generator::print_inst(const pseudo_node_inst_t& inst, bool end) | ||
698 | { | ||
699 | if(!inst.inst.is_root()) | ||
700 | { | ||
701 | pseudo_node_inst_t p = inst; | ||
702 | p.inst = p.inst.parent(); | ||
703 | p.parametric.pop_back(); | ||
704 | print_inst(p, false); | ||
705 | printf(".%s", inst.inst.name().c_str()); | ||
706 | if(inst.inst.is_indexed()) | ||
707 | { | ||
708 | if(inst.parametric.back()) | ||
709 | printf("[]"); | ||
710 | else | ||
711 | printf("[%u]", (unsigned)inst.inst.index()); | ||
712 | } | ||
713 | } | ||
714 | else | ||
715 | { | ||
716 | printf("%s", inst.inst.soc().get()->name.c_str()); | ||
717 | } | ||
718 | if(end) | ||
719 | printf("\n"); | ||
720 | } | ||
721 | |||
722 | std::string common_generator::register_type_name(access_type_t access, int width) const | ||
723 | { | ||
724 | std::ostringstream oss; | ||
725 | oss << width << "_"; | ||
726 | switch(access) | ||
727 | { | ||
728 | case AT_RO: oss << "RO"; break; | ||
729 | case AT_RW: oss << "RW"; break; | ||
730 | case AT_WO: oss << "WO"; break; | ||
731 | default: oss << "error"; break; | ||
732 | } | ||
733 | return type_xfix(MT_IO_TYPE, true) + oss.str() + type_xfix(MT_IO_TYPE, false); | ||
734 | } | ||
735 | |||
736 | std::string common_generator::register_op_name(register_op_t op) const | ||
737 | { | ||
738 | switch(op) | ||
739 | { | ||
740 | case RO_VAR: return "VAR"; | ||
741 | case RO_READ: return "RD"; | ||
742 | case RO_WRITE: return "WR"; | ||
743 | case RO_RMW: return "RMW"; | ||
744 | default: return "<op>"; | ||
745 | } | ||
746 | } | ||
747 | |||
748 | std::string common_generator::register_op_prefix() const | ||
749 | { | ||
750 | return "_"; | ||
751 | } | ||
752 | |||
753 | std::string common_generator::safe_macro_paste(bool left, const std::string& macro) const | ||
754 | { | ||
755 | if(macro.size() == 0) | ||
756 | return ""; | ||
757 | return left ? "##" + macro : macro + "##"; | ||
758 | } | ||
759 | |||
760 | void common_generator::gather_files(const pseudo_node_inst_t& inst, const std::string& prefix, | ||
761 | std::map< std::string, std::vector< pseudo_node_inst_t > >& map) | ||
762 | { | ||
763 | if(inst.inst.node().reg().valid()) | ||
764 | map[prefix + register_header(inst.inst)].push_back(inst); | ||
765 | // if asked, generate one for each instance | ||
766 | std::vector< node_inst_t > list = inst.inst.children(); | ||
767 | for(size_t i = 0; i < list.size(); i++) | ||
768 | { | ||
769 | pseudo_node_inst_t c = inst; | ||
770 | c.inst = list[i]; | ||
771 | if(!list[i].is_indexed() || register_flag(inst.inst, RF_GENERATE_ALL_INST)) | ||
772 | { | ||
773 | c.parametric.push_back(false); | ||
774 | gather_files(c, prefix, map); | ||
775 | c.parametric.pop_back(); | ||
776 | } | ||
777 | if(list[i].is_indexed() && register_flag(list[i], RF_GENERATE_PARAM_INST)) | ||
778 | { | ||
779 | bool first = list[i].index() == list[i].get()->range.first; | ||
780 | if(first) | ||
781 | { | ||
782 | c.parametric.push_back(true); | ||
783 | gather_files(c, prefix, map); | ||
784 | } | ||
785 | } | ||
786 | } | ||
787 | } | ||
788 | |||
789 | std::vector< soc_ref_t > common_generator::list_socs(const std::vector< pseudo_node_inst_t >& list) | ||
790 | { | ||
791 | std::set< soc_ref_t > socs; | ||
792 | std::vector< pseudo_node_inst_t >::const_iterator it = list.begin(); | ||
793 | for(; it != list.end(); ++it) | ||
794 | socs.insert(it->inst.soc()); | ||
795 | std::vector< soc_ref_t > soc_list; | ||
796 | for(std::set< soc_ref_t >::iterator jt = socs.begin(); jt != socs.end(); ++jt) | ||
797 | soc_list.push_back(*jt); | ||
798 | return soc_list; | ||
799 | } | ||
800 | |||
801 | std::string common_generator::header_include_guard(const std::string& filename) | ||
802 | { | ||
803 | std::string guard = "__HEADERGEN_" + toupper(filename) + "__"; | ||
804 | for(size_t i = 0; i < guard.size(); i++) | ||
805 | if(!isalnum(guard[i])) | ||
806 | guard[i] = '_'; | ||
807 | return guard; | ||
808 | } | ||
809 | |||
810 | std::string common_generator::register_address(const pseudo_node_inst_t& reg, | ||
811 | std::vector< std::string >& params) const | ||
812 | { | ||
813 | std::ostringstream oss; | ||
814 | unsigned counter = 1; | ||
815 | oss << "("; | ||
816 | for(size_t i = 0; i < reg.parametric.size(); i++) | ||
817 | { | ||
818 | if(i != 0) | ||
819 | oss << " + "; | ||
820 | node_inst_t ninst = reg.inst.parent(reg.parametric.size() - i - 1); | ||
821 | instance_t& inst = *ninst.get(); | ||
822 | if(reg.parametric[i]) | ||
823 | params.push_back("_n" + to_str(counter++)); | ||
824 | if(inst.type == instance_t::RANGE) | ||
825 | { | ||
826 | if(inst.range.type == range_t::STRIDE) | ||
827 | { | ||
828 | if(reg.parametric[i]) | ||
829 | { | ||
830 | oss << to_hex(inst.range.base) << " + "; | ||
831 | oss << "(" << params.back() << ") * " << to_hex(inst.range.stride); | ||
832 | } | ||
833 | else | ||
834 | oss << to_hex(inst.range.base + ninst.index() * inst.range.stride); | ||
835 | } | ||
836 | else if(inst.range.type == range_t::FORMULA) | ||
837 | { | ||
838 | if(!reg.parametric[i]) | ||
839 | { | ||
840 | soc_word_t res; | ||
841 | std::map< std::string, soc_word_t > vars; | ||
842 | vars[inst.range.variable] = ninst.index(); | ||
843 | error_context_t ctx; | ||
844 | if(!evaluate_formula(inst.range.formula, vars, res, "", ctx)) | ||
845 | oss << "#error cannot evaluate formula"; | ||
846 | else | ||
847 | oss << to_hex(res); | ||
848 | } | ||
849 | else | ||
850 | oss << strsubst(inst.range.formula, inst.range.variable, | ||
851 | "(" + params.back() + ")"); | ||
852 | } | ||
853 | else if(inst.range.type == range_t::LIST) | ||
854 | { | ||
855 | if(reg.parametric[i]) | ||
856 | { | ||
857 | oss << "("; | ||
858 | for(size_t j = 0; j + 1 < inst.range.list.size(); j++) | ||
859 | { | ||
860 | oss << "(" << params.back() << ") == " << (inst.range.first + j) | ||
861 | << " ? " << to_hex(inst.range.list[j]) << " : "; | ||
862 | } | ||
863 | oss << to_hex(inst.range.list.back()) << ")"; | ||
864 | } | ||
865 | else | ||
866 | oss << to_hex(inst.range.list[ninst.index() - inst.range.first]); | ||
867 | } | ||
868 | else | ||
869 | { | ||
870 | return "#error unknown range type"; | ||
871 | } | ||
872 | } | ||
873 | else if(inst.type == instance_t::SINGLE) | ||
874 | oss << to_hex(inst.addr); | ||
875 | else | ||
876 | return "#error unknown instance type"; | ||
877 | } | ||
878 | oss << ")"; | ||
879 | return oss.str(); | ||
880 | } | ||
881 | |||
882 | bool common_generator::generate_register(std::ostream& os, const pseudo_node_inst_t& reg) | ||
883 | { | ||
884 | os << "\n"; | ||
885 | define_align_context_t ctx; | ||
886 | std::vector< std::string > params; | ||
887 | std::string addr = register_address(reg, params); | ||
888 | std::string basename = macro_basename(reg); | ||
889 | std::string param_str; | ||
890 | std::string param_str_no_paren; | ||
891 | std::string param_str_no_paren_comma; | ||
892 | if(params.size() > 0) | ||
893 | { | ||
894 | for(size_t i = 0; i < params.size(); i++) | ||
895 | param_str_no_paren += (i == 0 ? "" : ",") + params[i]; | ||
896 | param_str = "(" + param_str_no_paren + ")"; | ||
897 | param_str_no_paren_comma = param_str_no_paren + ","; | ||
898 | } | ||
899 | std::string bp_prefix = macro_basename(reg, MT_FIELD_BP) + field_prefix(); | ||
900 | std::string bm_prefix = macro_basename(reg, MT_FIELD_BM) + field_prefix(); | ||
901 | std::string bf_prefix = macro_basename(reg, MT_FIELD_BF) + field_prefix(); | ||
902 | std::string bfm_prefix = macro_basename(reg, MT_FIELD_BFM) + field_prefix(); | ||
903 | std::string bfv_prefix = macro_basename(reg, MT_FIELD_BFV) + field_prefix(); | ||
904 | std::string bfmv_prefix = macro_basename(reg, MT_FIELD_BFMV) + field_prefix(); | ||
905 | |||
906 | register_ref_t regr = reg.inst.node().reg(); | ||
907 | /* handle register the same way as variants */ | ||
908 | std::vector< std::string > var_prefix; | ||
909 | std::vector< std::string > var_suffix; | ||
910 | std::vector< std::string > var_addr; | ||
911 | std::vector< access_type_t > var_access; | ||
912 | var_prefix.push_back(""); | ||
913 | var_suffix.push_back(""); | ||
914 | var_access.push_back(register_access("", regr.get()->access)); | ||
915 | var_addr.push_back(addr); | ||
916 | std::vector< variant_ref_t > variants = regr.variants(); | ||
917 | for(size_t i = 0; i < variants.size(); i++) | ||
918 | { | ||
919 | var_prefix.push_back(variant_xfix(variants[i].type(), true)); | ||
920 | var_suffix.push_back(variant_xfix(variants[i].type(), false)); | ||
921 | var_addr.push_back("(" + type_xfix(MT_REG_ADDR, true) + basename + | ||
922 | type_xfix(MT_REG_ADDR, false) + param_str + " + " + | ||
923 | to_hex(variants[i].offset()) + ")"); | ||
924 | access_t acc = variants[i].get()->access; | ||
925 | if(acc == UNSPECIFIED) | ||
926 | acc = regr.get()->access; // fallback to register access | ||
927 | var_access.push_back(register_access(variants[i].type(), acc)); | ||
928 | } | ||
929 | |||
930 | for(size_t i = 0; i < var_prefix.size(); i++) | ||
931 | { | ||
932 | std::string var_basename = var_prefix[i] + basename + var_suffix[i]; | ||
933 | std::string macro_var = type_xfix(MT_REG_VAR, true) + var_basename + | ||
934 | type_xfix(MT_REG_VAR, false); | ||
935 | std::string macro_addr = type_xfix(MT_REG_ADDR, true) + var_basename + | ||
936 | type_xfix(MT_REG_ADDR, false); | ||
937 | std::string macro_type = type_xfix(MT_REG_TYPE, true) + var_basename + | ||
938 | type_xfix(MT_REG_TYPE, false); | ||
939 | std::string macro_prefix = type_xfix(MT_REG_NAME, true) + var_basename + | ||
940 | type_xfix(MT_REG_NAME, false); | ||
941 | std::string macro_index = type_xfix(MT_REG_INDEX, true) + var_basename + | ||
942 | type_xfix(MT_REG_INDEX, false); | ||
943 | /* print VAR macro */ | ||
944 | ctx.add(macro_var + param_str, macro_name(MN_VARIABLE) + "(" + var_basename + param_str + ")"); | ||
945 | /* print ADDR macro */ | ||
946 | ctx.add(macro_addr + param_str, var_addr[i]); | ||
947 | /* print TYPE macro */ | ||
948 | ctx.add(macro_type + param_str, register_type_name(var_access[i], regr.get()->width)); | ||
949 | /* print PREFIX macro */ | ||
950 | ctx.add(macro_prefix + param_str, basename); | ||
951 | /* print INDEX macro */ | ||
952 | ctx.add(macro_index + param_str, param_str); | ||
953 | } | ||
954 | /* print fields */ | ||
955 | std::vector< field_ref_t > fields = regr.fields(); | ||
956 | for(size_t i = 0; i < fields.size(); i++) | ||
957 | { | ||
958 | /* print BP macro: pos */ | ||
959 | std::string fname = field_name(fields[i]); | ||
960 | ctx.add(bp_prefix + fname + type_xfix(MT_FIELD_BP, false), | ||
961 | to_str(fields[i].get()->pos)); | ||
962 | /* print BM macro: mask */ | ||
963 | ctx.add(bm_prefix + fname + type_xfix(MT_FIELD_BM, false), | ||
964 | to_hex(fields[i].get()->bitmask())); | ||
965 | std::vector< enum_ref_t > enums = fields[i].enums(); | ||
966 | std::string bv_prefix = macro_basename(reg, MT_FIELD_BV) + field_prefix() | ||
967 | + fname + enum_prefix(); | ||
968 | /* print BV macros: enum_v */ | ||
969 | for(size_t j = 0; j < enums.size(); j++) | ||
970 | ctx.add(bv_prefix + enum_name(enums[j]) + type_xfix(MT_FIELD_BV, false), | ||
971 | to_hex(enums[j].get()->value)); | ||
972 | /* print BF macro: (((v) & mask) << pos) */ | ||
973 | ctx.add(bf_prefix + fname + type_xfix(MT_FIELD_BF, false) + "(v)", | ||
974 | "(((v) & " + to_hex(fields[i].get()->unshifted_bitmask()) + ") << " + | ||
975 | to_str(fields[i].get()->pos) + ")"); | ||
976 | /* print BFM macro: masl */ | ||
977 | ctx.add(bfm_prefix + fname + type_xfix(MT_FIELD_BFM, false) + "(v)", | ||
978 | bm_prefix + fname + type_xfix(MT_FIELD_BM, false)); | ||
979 | /* print BFV macro: ((enum_v) << pos) & mask) */ | ||
980 | ctx.add(bfv_prefix + fname + type_xfix(MT_FIELD_BFV, false) + "(e)", | ||
981 | bf_prefix + fname + type_xfix(MT_FIELD_BF, false) + "(" + | ||
982 | bv_prefix + "##e)"); | ||
983 | /* print BFMV macro: masl */ | ||
984 | ctx.add(bfmv_prefix + fname + type_xfix(MT_FIELD_BFMV, false) + "(v)", | ||
985 | bm_prefix + fname + type_xfix(MT_FIELD_BM, false)); | ||
986 | } | ||
987 | |||
988 | ctx.print(os); | ||
989 | return true; | ||
990 | } | ||
991 | |||
992 | bool common_generator::generate_macro_header(error_context_t& ectx) | ||
993 | { | ||
994 | std::ofstream fout((m_outdir + "/" + macro_header()).c_str()); | ||
995 | if(!fout) | ||
996 | { | ||
997 | printf("Cannot create '%s'\n", (m_outdir + "/" + macro_header()).c_str()); | ||
998 | return false; | ||
999 | } | ||
1000 | print_copyright(fout, std::vector< soc_ref_t >()); | ||
1001 | std::string guard = header_include_guard(macro_header()); | ||
1002 | print_guard(fout, guard, true); | ||
1003 | fout << "\n"; | ||
1004 | |||
1005 | /* print variadic OR macros: | ||
1006 | * __VAR_OR1(prefix, suffix) expands to prefix##suffix | ||
1007 | * and more n>=2, using multiple layers of macros: | ||
1008 | * __VAR_ORn(pre, s01, s02, ..., sn) expands to pre##s01 | .. | pre##sn */ | ||
1009 | std::string var_or = "__VAR_OR"; | ||
1010 | const int MAX_N = 13; | ||
1011 | |||
1012 | fout << "#define " << var_or << "1(prefix, suffix) \\\n"; | ||
1013 | fout << " (prefix##suffix)\n"; | ||
1014 | for(int n = 2; n <= MAX_N; n++) | ||
1015 | { | ||
1016 | fout << "#define " << var_or << n << "(pre"; | ||
1017 | for(int j = 1; j <= n; j++) | ||
1018 | fout << ", s" << j; | ||
1019 | fout << ") \\\n"; | ||
1020 | /* dichotmoty: expands ORn using ORj and ORk where j=n/2 and k=n-j */ | ||
1021 | int half = n / 2; | ||
1022 | fout << " (" << var_or << half << "(pre"; | ||
1023 | for(int j = 1; j <= half; j++) | ||
1024 | fout << ", s" << j; | ||
1025 | fout << ") | " << var_or << (n - half) << "(pre"; | ||
1026 | for(int j = half + 1; j <= n; j++) | ||
1027 | fout << ", s" << j; | ||
1028 | fout << "))\n"; | ||
1029 | } | ||
1030 | fout << "\n"; | ||
1031 | |||
1032 | /* print macro to compute number of arguments */ | ||
1033 | std::string var_nargs = "__VAR_NARGS"; | ||
1034 | |||
1035 | fout << "#define " << var_nargs << "(...) " << var_nargs << "_(__VA_ARGS__"; | ||
1036 | for(int i = MAX_N; i >= 1; i--) | ||
1037 | fout << ", " << i; | ||
1038 | fout << ")\n"; | ||
1039 | fout << "#define " << var_nargs << "_("; | ||
1040 | for(int i = 1; i <= MAX_N; i++) | ||
1041 | fout << "_" << i << ", "; | ||
1042 | fout << "N, ...) N\n\n"; | ||
1043 | |||
1044 | /* print macro for variadic register macros */ | ||
1045 | std::string var_expand = "__VAR_EXPAND"; | ||
1046 | |||
1047 | fout << "#define " << var_expand << "(macro, prefix, ...) " | ||
1048 | << var_expand << "_(macro, " << var_nargs << "(__VA_ARGS__), prefix, __VA_ARGS__)\n"; | ||
1049 | fout << "#define " << var_expand << "_(macro, cnt, prefix, ...) " | ||
1050 | << var_expand << "__(macro, cnt, prefix, __VA_ARGS__)\n"; | ||
1051 | fout << "#define " << var_expand << "__(macro, cnt, prefix, ...) " | ||
1052 | << var_expand << "___(macro##cnt, prefix, __VA_ARGS__)\n"; | ||
1053 | fout << "#define " << var_expand << "___(macro, prefix, ...) " | ||
1054 | << "macro(prefix, __VA_ARGS__)\n\n"; | ||
1055 | |||
1056 | /* print type macros */ | ||
1057 | define_align_context_t ctx; | ||
1058 | access_type_t at[3] = { AT_RO, AT_RW, AT_WO }; | ||
1059 | int width[3] = { 8, 16, 32 }; | ||
1060 | for(int i = 0; i < 3; i++) | ||
1061 | { | ||
1062 | for(int j = 0; j < 3; j++) | ||
1063 | { | ||
1064 | std::string io_type = register_type_name(at[i], width[j]); | ||
1065 | ctx.add(io_type + "(op, name, ...)", io_type + register_op_prefix() + "##op(name, __VA_ARGS__)"); | ||
1066 | // read | ||
1067 | std::ostringstream oss; | ||
1068 | std::string reg_addr = safe_macro_paste(false, type_xfix(MT_REG_ADDR, true)) | ||
1069 | + "name" + safe_macro_paste(true, type_xfix(MT_REG_ADDR, false)); | ||
1070 | if(at[i] == AT_RO) | ||
1071 | oss << "(*(const volatile uint" << width[j] << "_t *)(" << reg_addr << "))"; | ||
1072 | else if(at[i] == AT_RW) | ||
1073 | oss << "(*(volatile uint" << width[j] << "_t *)(" << reg_addr << "))"; | ||
1074 | else | ||
1075 | oss << "({_Static_assert(0, #name \" is write-only\"); 0;})"; | ||
1076 | ctx.add(io_type + register_op_prefix() + register_op_name(RO_READ) + "(name, ...)", | ||
1077 | oss.str()); | ||
1078 | // write | ||
1079 | oss.str(""); | ||
1080 | if(at[i] != AT_RO) | ||
1081 | oss << "(*(volatile uint" << width[j] << "_t *)(" << reg_addr << ")) = (val)"; | ||
1082 | else | ||
1083 | oss << "_Static_assert(0, #name \" is read-only\")"; | ||
1084 | ctx.add(io_type + register_op_prefix() + register_op_name(RO_WRITE) + "(name, val)", | ||
1085 | oss.str()); | ||
1086 | // read-modify-write | ||
1087 | oss.str(""); | ||
1088 | if(at[i] == AT_RW) | ||
1089 | { | ||
1090 | oss << io_type << register_op_prefix() << register_op_name(RO_WRITE) + "(name, "; | ||
1091 | oss << "(" << io_type << register_op_prefix() << register_op_name(RO_READ) + "(name) & (vand))"; | ||
1092 | oss << " | (vor))"; | ||
1093 | } | ||
1094 | else if(at[i] == AT_WO) | ||
1095 | oss << io_type << register_op_prefix() << register_op_name(RO_WRITE) + "(name, vor)"; | ||
1096 | else | ||
1097 | oss << "_Static_assert(0, #name \" is read-only\")"; | ||
1098 | ctx.add(io_type + register_op_prefix() + register_op_name(RO_RMW) + "(name, vand, vor)", | ||
1099 | oss.str()); | ||
1100 | // variable | ||
1101 | oss.str(""); | ||
1102 | if(at[i] == AT_RO) | ||
1103 | oss << "(*(const volatile uint" << width[j] << "_t *)(" << reg_addr << "))"; | ||
1104 | else | ||
1105 | oss << "(*(volatile uint" << width[j] << "_t *)(" << reg_addr << "))"; | ||
1106 | ctx.add(io_type + register_op_prefix() + register_op_name(RO_VAR) + "(name, ...)", | ||
1107 | oss.str()); | ||
1108 | |||
1109 | ctx.add_raw("\n"); | ||
1110 | } | ||
1111 | } | ||
1112 | ctx.print(fout); | ||
1113 | fout << "\n"; | ||
1114 | |||
1115 | /* print GET_VARIANT macro */ | ||
1116 | std::string get_var = macro_name(MN_GET_VARIANT); | ||
1117 | fout << "/** " << get_var << "\n"; | ||
1118 | fout << " *\n"; | ||
1119 | fout << " * usage: " << get_var << "(register, variant_prefix, variant_postfix)\n"; | ||
1120 | fout << " *\n"; | ||
1121 | fout << " * effect: expands to register variant given as argument\n"; | ||
1122 | fout << " * note: internal usage\n"; | ||
1123 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1124 | fout << " *\n"; | ||
1125 | fout << " * example: " << get_var << "(ICOLL_CTRL, , _SET)\n"; | ||
1126 | fout << " * example: " << get_var << "(ICOLL_ENABLE(3), , _CLR)\n"; | ||
1127 | fout << " */\n"; | ||
1128 | fout << "#define " << get_var << "(name, varp, vars) " | ||
1129 | << get_var << "_(" << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1130 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", " | ||
1131 | << safe_macro_paste(false, type_xfix(MT_REG_INDEX, true)) | ||
1132 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_INDEX, false)) << ", varp, vars)\n"; | ||
1133 | fout << "#define " << get_var << "_(...) " << get_var << "__(__VA_ARGS__)\n"; | ||
1134 | fout << "#define " << get_var << "__(name, index, varp, vars) " | ||
1135 | << "varp##name##vars index\n"; | ||
1136 | fout << "\n"; | ||
1137 | |||
1138 | /* print BF_OR macro */ | ||
1139 | std::string bf_or = macro_name(MN_FIELD_OR); | ||
1140 | fout << "/** " << bf_or << "\n"; | ||
1141 | fout << " *\n"; | ||
1142 | fout << " * usage: " << bf_or << "(register, f1(v1), f2(v2), ...)\n"; | ||
1143 | fout << " *\n"; | ||
1144 | fout << " * effect: expands to the register value where each field fi has value vi.\n"; | ||
1145 | fout << " * Informally: reg_f1(v1) | reg_f2(v2) | ...\n"; | ||
1146 | fout << " * note: enumerated values for fields can be obtained by using the syntax:\n"; | ||
1147 | fout << " * f1" << type_xfix(MT_FIELD_BFV, false) << "(name)\n"; | ||
1148 | fout << " *\n"; | ||
1149 | fout << " * example: " << bf_or << "(ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1150 | fout << " */\n"; | ||
1151 | fout << "#define " << bf_or << "(reg, ...) " | ||
1152 | << var_expand << "(" << var_or << ", " << type_xfix(MT_FIELD_BF, true) | ||
1153 | << "##reg##" << field_prefix() << ", __VA_ARGS__)\n"; | ||
1154 | fout << "\n"; | ||
1155 | |||
1156 | /* print BF_OR macro */ | ||
1157 | std::string bfm_or = macro_name(MN_FIELD_OR_MASK); | ||
1158 | fout << "/** " << bfm_or << "\n"; | ||
1159 | fout << " *\n"; | ||
1160 | fout << " * usage: " << bfm_or << "(register, f1(v1), f2(v2), ...)\n"; | ||
1161 | fout << " *\n"; | ||
1162 | fout << " * effect: expands to the register value where each field fi has maximum value (vi is ignored).\n"; | ||
1163 | fout << " * note: internal usage\n"; | ||
1164 | fout << " *\n"; | ||
1165 | fout << " * example: " << bfm_or << "(ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1166 | fout << " */\n"; | ||
1167 | fout << "#define " << bfm_or << "(reg, ...) " | ||
1168 | << var_expand << "(" << var_or << ", " << type_xfix(MT_FIELD_BFM, true) | ||
1169 | << "##reg##" << field_prefix() << ", __VA_ARGS__)\n"; | ||
1170 | fout << "\n"; | ||
1171 | |||
1172 | /* print BM_OR macro */ | ||
1173 | std::string bm_or = macro_name(MN_MASK_OR); | ||
1174 | fout << "/** " << bm_or << "\n"; | ||
1175 | fout << " *\n"; | ||
1176 | fout << " * usage: " << bm_or << "(register, f1, f2, ...)\n"; | ||
1177 | fout << " *\n"; | ||
1178 | fout << " * effect: expands to the register value where each field fi is set to its maximum value.\n"; | ||
1179 | fout << " * Informally: reg_f1_mask | reg_f2_mask | ...\n"; | ||
1180 | fout << " *\n"; | ||
1181 | fout << " * example: " << bm_or << "(ICOLL_CTRL, SFTRST, CLKGATE)\n"; | ||
1182 | fout << " */\n"; | ||
1183 | fout << "#define " << bm_or << "(reg, ...) " | ||
1184 | << var_expand << "(" << var_or << ", " << type_xfix(MT_FIELD_BM, true) | ||
1185 | << "##reg##" << field_prefix() << ", __VA_ARGS__)\n\n"; | ||
1186 | fout << "\n"; | ||
1187 | |||
1188 | /* print REG_READ macro */ | ||
1189 | std::string reg_read = macro_name(MN_REG_READ); | ||
1190 | fout << "/** " << reg_read << "\n"; | ||
1191 | fout << " *\n"; | ||
1192 | fout << " * usage: " << reg_read << "(register)\n"; | ||
1193 | fout << " *\n"; | ||
1194 | fout << " * effect: read a register and return its value\n"; | ||
1195 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1196 | fout << " *\n"; | ||
1197 | fout << " * example: " << reg_read << "(ICOLL_STATUS)\n"; | ||
1198 | fout << " * " << reg_read << "(ICOLL_ENABLE(42))\n"; | ||
1199 | fout << " */\n"; | ||
1200 | fout << "#define " << reg_read << "(name) " | ||
1201 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1202 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1203 | << "(" << register_op_name(RO_READ) << ", name)\n"; | ||
1204 | fout << "\n"; | ||
1205 | |||
1206 | /* print FIELD_READX macro */ | ||
1207 | std::string bf_readx = macro_name(MN_FIELD_READX); | ||
1208 | fout << "/** " << bf_readx << "\n"; | ||
1209 | fout << " *\n"; | ||
1210 | fout << " * usage: " << bf_readx << "(value, register, field)\n"; | ||
1211 | fout << " *\n"; | ||
1212 | fout << " * effect: given a register value, return the value of a particular field\n"; | ||
1213 | fout << " * note: this macro does NOT read any register\n"; | ||
1214 | fout << " *\n"; | ||
1215 | fout << " * example: " << bf_readx << "(0xc0000000, ICOLL_CTRL, SFTRST)\n"; | ||
1216 | fout << " * " << bf_readx << "(0x46ff, ICOLL_ENABLE, CPU0_PRIO)\n"; | ||
1217 | fout << " */\n"; | ||
1218 | fout << "#define " << bf_readx << "(val, name, field) " | ||
1219 | << "(((val) & " << safe_macro_paste(false, type_xfix(MT_FIELD_BM, true)) | ||
1220 | << "name" << safe_macro_paste(true, type_xfix(MT_FIELD_BM, false)) | ||
1221 | << safe_macro_paste(true, field_prefix()) << "##field" | ||
1222 | << ") >> " << safe_macro_paste(false, type_xfix(MT_FIELD_BP, true)) | ||
1223 | << "name" << safe_macro_paste(true, type_xfix(MT_FIELD_BP, false)) | ||
1224 | << safe_macro_paste(true, field_prefix()) << "##field" | ||
1225 | << ")\n"; | ||
1226 | fout << "\n"; | ||
1227 | |||
1228 | /* print FIELD_READ macro */ | ||
1229 | std::string bf_read = macro_name(MN_FIELD_READ); | ||
1230 | fout << "/** " << bf_read << "\n"; | ||
1231 | fout << " *\n"; | ||
1232 | fout << " * usage: " << bf_read << "(register, field)\n"; | ||
1233 | fout << " *\n"; | ||
1234 | fout << " * effect: read a register and return the value of a particular field\n"; | ||
1235 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1236 | fout << " *\n"; | ||
1237 | fout << " * example: " << bf_read << "(ICOLL_CTRL, SFTRST)\n"; | ||
1238 | fout << " * " << bf_read << "(ICOLL_ENABLE(3), CPU0_PRIO)\n"; | ||
1239 | fout << " */\n"; | ||
1240 | fout << "#define " << bf_read << "(name, field) " << bf_read << "_(" | ||
1241 | << reg_read << "(name), " << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1242 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", field)\n"; | ||
1243 | fout << "#define " << bf_read << "_(...) " << bf_readx << "(__VA_ARGS__)\n"; | ||
1244 | fout << "\n"; | ||
1245 | |||
1246 | /* print REG_WRITE macro */ | ||
1247 | std::string reg_write = macro_name(MN_REG_WRITE); | ||
1248 | fout << "/** " << reg_write << "\n"; | ||
1249 | fout << " *\n"; | ||
1250 | fout << " * usage: " << reg_write << "(register, value)\n"; | ||
1251 | fout << " *\n"; | ||
1252 | fout << " * effect: write a register\n"; | ||
1253 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1254 | fout << " *\n"; | ||
1255 | fout << " * example: " << reg_write << "(ICOLL_CTRL, 0x42)\n"; | ||
1256 | fout << " * " << reg_write << "(ICOLL_ENABLE_SET(3), 0x37)\n"; | ||
1257 | fout << " */\n"; | ||
1258 | fout << "#define " << reg_write << "(name, val) " | ||
1259 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1260 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1261 | << "(" << register_op_name(RO_WRITE) << ", name, val)\n"; | ||
1262 | fout << "\n"; | ||
1263 | |||
1264 | /* print FIELD_WRITE macro */ | ||
1265 | std::string bf_write = macro_name(MN_FIELD_WRITE); | ||
1266 | fout << "/** " << bf_write << "\n"; | ||
1267 | fout << " *\n"; | ||
1268 | fout << " * usage: " << bf_write << "(register, f1(v1), f2(v2), ...)\n"; | ||
1269 | fout << " *\n"; | ||
1270 | fout << " * effect: change the register value so that field fi has value vi\n"; | ||
1271 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1272 | fout << " * note: this macro may perform a read-modify-write\n"; | ||
1273 | fout << " *\n"; | ||
1274 | fout << " * example: " << bf_write << "(ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1275 | fout << " * " << bf_write << "(ICOLL_ENABLE(3), CPU0_PRIO(1), CPU0_TYPE_V(FIQ))\n"; | ||
1276 | fout << " */\n"; | ||
1277 | fout << "#define " << bf_write << "(name, ...) " | ||
1278 | << bf_write << "_(name, " << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1279 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", __VA_ARGS__)\n"; | ||
1280 | fout << "#define " << bf_write << "_(name, name2, ...) " | ||
1281 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1282 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1283 | << "(" << register_op_name(RO_RMW) << ", name, " | ||
1284 | << "~" << macro_name(MN_FIELD_OR_MASK) << "(name2, __VA_ARGS__), " | ||
1285 | << macro_name(MN_FIELD_OR) << "(name2, __VA_ARGS__))\n"; | ||
1286 | fout << "\n"; | ||
1287 | |||
1288 | /* print FIELD_OVERWRITE macro */ | ||
1289 | std::string bf_overwrite = macro_name(MN_FIELD_OVERWRITE); | ||
1290 | fout << "/** " << bf_overwrite << "\n"; | ||
1291 | fout << " *\n"; | ||
1292 | fout << " * usage: " << bf_overwrite << "(register, f1(v1), f2(v2), ...)\n"; | ||
1293 | fout << " *\n"; | ||
1294 | fout << " * effect: change the register value so that field fi has value vi and other fields have value zero\n"; | ||
1295 | fout << " * thus this macro is equivalent to:\n"; | ||
1296 | fout << " * " << reg_write << "(register, " << bf_or << "(register, f1(v1), ...))\n"; | ||
1297 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1298 | fout << " * note: this macro will overwrite the register (it is NOT a read-modify-write)\n"; | ||
1299 | fout << " *\n"; | ||
1300 | fout << " * example: " << bf_overwrite << "(ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1301 | fout << " * " << bf_overwrite << "(ICOLL_ENABLE(3), CPU0_PRIO(1), CPU0_TYPE_V(FIQ))\n"; | ||
1302 | fout << " */\n"; | ||
1303 | fout << "#define " << bf_overwrite << "(name, ...) " | ||
1304 | << bf_overwrite << "_(name, " << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1305 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", __VA_ARGS__)\n"; | ||
1306 | fout << "#define " << bf_overwrite << "_(name, name2, ...) " | ||
1307 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1308 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1309 | << "(" << register_op_name(RO_WRITE) << ", name, " | ||
1310 | << macro_name(MN_FIELD_OR) << "(name2, __VA_ARGS__))\n"; | ||
1311 | fout << "\n"; | ||
1312 | |||
1313 | /* print FIELD_WRITEX macro */ | ||
1314 | std::string bf_writex = macro_name(MN_FIELD_WRITEX); | ||
1315 | fout << "/** " << bf_writex << "\n"; | ||
1316 | fout << " *\n"; | ||
1317 | fout << " * usage: " << bf_writex << "(var, register, f1(v1), f2(v2), ...)\n"; | ||
1318 | fout << " *\n"; | ||
1319 | fout << " * effect: change the variable value so that field fi has value vi\n"; | ||
1320 | fout << " * note: this macro will perform a read-modify-write\n"; | ||
1321 | fout << " *\n"; | ||
1322 | fout << " * example: " << bf_writex << "(var, ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1323 | fout << " * " << bf_writex << "(var, ICOLL_ENABLE, CPU0_PRIO(1), CPU0_TYPE_V(FIQ))\n"; | ||
1324 | fout << " */\n"; | ||
1325 | fout << "#define " << bf_writex << "(var, name, ...) " | ||
1326 | << "(var) = " << macro_name(MN_FIELD_OR) << "(name, __VA_ARGS__) | (~" | ||
1327 | << macro_name(MN_FIELD_OR_MASK) << "(name, __VA_ARGS__) & (var))\n"; | ||
1328 | fout << "\n"; | ||
1329 | |||
1330 | /* print FIELD_SET/FIELD_CLEAR macro */ | ||
1331 | for(int i = 0; i < 2; i++) | ||
1332 | { | ||
1333 | macro_name_t n = (i == 0) ? MN_FIELD_SET : MN_FIELD_CLEAR; | ||
1334 | std::string bf_set = macro_name(n); | ||
1335 | std::string set_var = sct_variant(n); | ||
1336 | |||
1337 | fout << "/** " << bf_set << "\n"; | ||
1338 | fout << " *\n"; | ||
1339 | fout << " * usage: " << bf_set << "(register, f1, f2, ...)\n"; | ||
1340 | fout << " *\n"; | ||
1341 | fout << " * effect: change the register value so that field fi has "; | ||
1342 | if(i == 0) | ||
1343 | fout << "maximum value\n"; | ||
1344 | else | ||
1345 | fout << "value zero\n"; | ||
1346 | if(has_sct()) | ||
1347 | fout << " * IMPORTANT: this macro performs a write to the " << set_var << " variant of the register\n"; | ||
1348 | else | ||
1349 | fout << " * note: this macro will perform a read-modify-write\n"; | ||
1350 | |||
1351 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1352 | fout << " *\n"; | ||
1353 | fout << " * example: " << bf_set << "(ICOLL_CTRL, SFTRST, CLKGATE)\n"; | ||
1354 | fout << " * " << bf_set << "(ICOLL_ENABLE(3), CPU0_PRIO, CPU0_TYPE)\n"; | ||
1355 | fout << " */\n"; | ||
1356 | |||
1357 | if(has_sct()) | ||
1358 | { | ||
1359 | fout << "#define " << bf_set << "(name, ...) " << bf_set << "_(" | ||
1360 | << macro_name(MN_GET_VARIANT) << "(name, " << variant_xfix(set_var, true) | ||
1361 | << ", " << variant_xfix(set_var, false) << "), " | ||
1362 | << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1363 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) | ||
1364 | << ", __VA_ARGS__)\n"; | ||
1365 | fout << "#define " << bf_set << "_(name, name2, ...) " << macro_name(MN_REG_WRITE) | ||
1366 | << "(name, " << macro_name(MN_MASK_OR) << "(name2, __VA_ARGS__))\n"; | ||
1367 | } | ||
1368 | else | ||
1369 | { | ||
1370 | fout << "#define " << bf_set << "(name, ...) " | ||
1371 | << bf_set << "_(name, " << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1372 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", __VA_ARGS__)\n"; | ||
1373 | fout << "#define " << bf_set << "_(name, name2, ...) " | ||
1374 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1375 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1376 | << "(" << register_op_name(RO_RMW) << ", name, ~"; | ||
1377 | if(i == 0) | ||
1378 | fout << "0," << macro_name(MN_MASK_OR) << "(name2, __VA_ARGS__))\n"; | ||
1379 | else | ||
1380 | fout << macro_name(MN_MASK_OR) << "(name2, __VA_ARGS__), 0)\n"; | ||
1381 | } | ||
1382 | fout << "\n"; | ||
1383 | } | ||
1384 | |||
1385 | if(has_sct()) | ||
1386 | { | ||
1387 | std::string set_var = sct_variant(MN_FIELD_SET); | ||
1388 | std::string clr_var = sct_variant(MN_FIELD_CLEAR); | ||
1389 | /* print REG_CS */ | ||
1390 | std::string reg_cs = macro_name(MN_REG_CLEAR_SET); | ||
1391 | fout << "/** " << reg_cs << "\n"; | ||
1392 | fout << " *\n"; | ||
1393 | fout << " * usage: " << reg_cs << "(register, clear_value, set_value)\n"; | ||
1394 | fout << " *\n"; | ||
1395 | fout << " * effect: clear some bits using " << set_var << " variant and then set some using " << set_var << " variant\n"; | ||
1396 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1397 | fout << " *\n"; | ||
1398 | fout << " * example: " << reg_cs << "(ICOLL_CTRL, 0xff, 0x42)\n"; | ||
1399 | fout << " * " << reg_cs << "(ICOLL_ENABLE(3), 0xff, 0x37)\n"; | ||
1400 | fout << " */\n"; | ||
1401 | fout << "#define " << reg_cs << "(name, cval, sval) " | ||
1402 | << reg_cs << "_(" << macro_name(MN_GET_VARIANT) << "(name, " | ||
1403 | << variant_xfix(clr_var, true) << ", " << variant_xfix(clr_var, false) << "), " | ||
1404 | << macro_name(MN_GET_VARIANT) << "(name, " << variant_xfix(set_var, true) | ||
1405 | << ", " << variant_xfix(set_var, false) << "), cval, sval)\n"; | ||
1406 | fout << "#define " << reg_cs << "_(cname, sname, cval, sval) " | ||
1407 | << "do { " << macro_name(MN_REG_WRITE) << "(cname, cval); " | ||
1408 | << macro_name(MN_REG_WRITE) << "(sname, sval); } while(0)\n"; | ||
1409 | fout << "\n"; | ||
1410 | |||
1411 | /* print BF_CS */ | ||
1412 | std::string bf_cs = macro_name(MN_FIELD_CLEAR_SET); | ||
1413 | fout << "/** " << bf_cs << "\n"; | ||
1414 | fout << " *\n"; | ||
1415 | fout << " * usage: " << bf_cs << "(register, f1(v1), f2(v2), ...)\n"; | ||
1416 | fout << " *\n"; | ||
1417 | fout << " * effect: change the register value so that field fi has value vi using " << clr_var << " and " << set_var << " variants\n"; | ||
1418 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1419 | fout << " * note: this macro will NOT perform a read-modify-write and is thus safer\n"; | ||
1420 | fout << " * IMPORTANT: this macro will set some fields to 0 temporarily, make sure this is acceptable\n"; | ||
1421 | fout << " *\n"; | ||
1422 | fout << " * example: " << bf_cs << "(ICOLL_CTRL, SFTRST(1), CLKGATE(0), TZ_LOCK_V(UNLOCKED))\n"; | ||
1423 | fout << " * " << bf_cs << "(ICOLL_ENABLE(3), CPU0_PRIO(1), CPU0_TYPE_V(FIQ))\n"; | ||
1424 | fout << " */\n"; | ||
1425 | fout << "#define " << bf_cs << "(name, ...) " | ||
1426 | << bf_cs << "_(name, " << safe_macro_paste(false, type_xfix(MT_REG_NAME, true)) | ||
1427 | << "name" << safe_macro_paste(true, type_xfix(MT_REG_NAME, false)) << ", __VA_ARGS__)\n"; | ||
1428 | fout << "#define " << bf_cs << "_(name, name2, ...) " | ||
1429 | << macro_name(MN_REG_CLEAR_SET) << "(name, " << macro_name(MN_FIELD_OR_MASK) | ||
1430 | << "(name2, __VA_ARGS__), " << macro_name(MN_FIELD_OR) << "(name2, __VA_ARGS__))\n"; | ||
1431 | fout << "\n"; | ||
1432 | } | ||
1433 | |||
1434 | /* print REG_VAR macro */ | ||
1435 | std::string reg_var = macro_name(MN_VARIABLE); | ||
1436 | fout << "/** " << reg_var << "\n"; | ||
1437 | fout << " *\n"; | ||
1438 | fout << " * usage: " << reg_var << "(register)\n"; | ||
1439 | fout << " *\n"; | ||
1440 | fout << " * effect: return a variable-like expression that can be read/written\n"; | ||
1441 | fout << " * note: register must be fully qualified if indexed\n"; | ||
1442 | fout << " * note: read-only registers will yield a constant expression\n"; | ||
1443 | fout << " *\n"; | ||
1444 | fout << " * example: unsigned x = " << reg_var << "(ICOLL_STATUS)\n"; | ||
1445 | fout << " * unsigned x = " << reg_var << "(ICOLL_ENABLE(42))\n"; | ||
1446 | fout << " * " << reg_var << "(ICOLL_ENABLE(42)) = 64\n"; | ||
1447 | fout << " */\n"; | ||
1448 | fout << "#define " << reg_var << "(name) " | ||
1449 | << safe_macro_paste(false, type_xfix(MT_REG_TYPE, true)) << "name" | ||
1450 | << safe_macro_paste(true, type_xfix(MT_REG_TYPE, false)) | ||
1451 | << "(" << register_op_name(RO_VAR) << ", name)\n"; | ||
1452 | fout << "\n"; | ||
1453 | |||
1454 | print_guard(fout, guard, false); | ||
1455 | fout.close(); | ||
1456 | return true; | ||
1457 | } | ||
1458 | |||
1459 | bool common_generator::generate(error_context_t& ectx) | ||
1460 | { | ||
1461 | /* first find which inst goes to which file */ | ||
1462 | std::map< std::string, std::vector< pseudo_node_inst_t > > regmap; | ||
1463 | for(size_t i = 0; i < m_soc.size(); i++) | ||
1464 | { | ||
1465 | soc_ref_t soc(&m_soc[i]); | ||
1466 | pseudo_node_inst_t inst; | ||
1467 | inst.inst = soc.root_inst(); | ||
1468 | gather_files(inst, has_selectors() ? selector_soc_dir(soc) + "/" : | ||
1469 | "", regmap); | ||
1470 | } | ||
1471 | /* create output directory */ | ||
1472 | create_dir(m_outdir); | ||
1473 | /* print files */ | ||
1474 | std::map< std::string, std::vector< pseudo_node_inst_t > >::iterator it = regmap.begin(); | ||
1475 | for(; it != regmap.end(); ++it) | ||
1476 | { | ||
1477 | create_alldir(m_outdir, it->first.c_str()); | ||
1478 | std::ofstream fout((m_outdir + "/" + it->first).c_str()); | ||
1479 | if(!fout) | ||
1480 | { | ||
1481 | printf("Cannot create '%s'\n", (m_outdir + "/" + it->first).c_str()); | ||
1482 | return false; | ||
1483 | } | ||
1484 | std::vector< soc_ref_t > soc_list = list_socs(it->second); | ||
1485 | print_copyright(fout, soc_list); | ||
1486 | std::string guard = header_include_guard(it->first); | ||
1487 | print_guard(fout, guard, true); | ||
1488 | |||
1489 | /* if we generate selectors, we include the macro header in them, otherwise | ||
1490 | * we include the macro header right here */ | ||
1491 | if(!has_selectors()) | ||
1492 | { | ||
1493 | fout << "\n"; | ||
1494 | fout << "#include \"" << macro_header() << "\"\n"; | ||
1495 | } | ||
1496 | |||
1497 | for(size_t i = 0; i < it->second.size(); i++) | ||
1498 | { | ||
1499 | if(!generate_register(fout, it->second[i])) | ||
1500 | { | ||
1501 | printf("Cannot generate register"); | ||
1502 | print_inst(it->second[i]); | ||
1503 | return false; | ||
1504 | } | ||
1505 | } | ||
1506 | |||
1507 | print_guard(fout, guard, false); | ||
1508 | fout.close(); | ||
1509 | } | ||
1510 | /* for selectors only */ | ||
1511 | if(has_selectors()) | ||
1512 | { | ||
1513 | /* list all possible headers and per soc headers */ | ||
1514 | std::map< std::string, std::set< soc_ref_t > > headers; | ||
1515 | for(it = regmap.begin(); it != regmap.end(); ++it) | ||
1516 | { | ||
1517 | /* pick the first instance in the file to extract the file name */ | ||
1518 | node_inst_t inst = it->second[0].inst; | ||
1519 | headers[register_header(inst)].insert(inst.node().soc()); | ||
1520 | } | ||
1521 | /* create selector headers */ | ||
1522 | std::map< std::string, std::set< soc_ref_t > >::iterator jt; | ||
1523 | for(jt = headers.begin(); jt != headers.end(); ++jt) | ||
1524 | { | ||
1525 | std::ofstream fout((m_outdir + "/" + jt->first).c_str()); | ||
1526 | if(!fout) | ||
1527 | { | ||
1528 | printf("Cannot create selector '%s'\n", (m_outdir + "/" + jt->first).c_str()); | ||
1529 | return false; | ||
1530 | } | ||
1531 | print_copyright(fout, std::vector< soc_ref_t >()); | ||
1532 | std::string guard = header_include_guard(jt->first); | ||
1533 | print_guard(fout, guard, true); | ||
1534 | |||
1535 | /* if we generate selectors, we include the macro header in them */ | ||
1536 | fout << "\n"; | ||
1537 | fout << "#include \"" << macro_header() << "\"\n"; | ||
1538 | |||
1539 | std::set< soc_ref_t >::iterator kt; | ||
1540 | define_align_context_t ctx; | ||
1541 | for(kt = jt->second.begin(); kt != jt->second.end(); ++kt) | ||
1542 | { | ||
1543 | std::ostringstream oss; | ||
1544 | oss << "\"" << selector_soc_dir(*kt) << "/" << jt->first << "\""; | ||
1545 | ctx.add(selector_soc_macro(*kt), oss.str()); | ||
1546 | } | ||
1547 | fout << "\n"; | ||
1548 | ctx.print(fout); | ||
1549 | fout << "\n"; | ||
1550 | fout << "#include \"" << selector_include_header() << "\"\n"; | ||
1551 | fout << "\n"; | ||
1552 | for(kt = jt->second.begin(); kt != jt->second.end(); ++kt) | ||
1553 | fout << "#undef " << selector_soc_macro(*kt) << "\n"; | ||
1554 | |||
1555 | print_guard(fout, guard, false); | ||
1556 | fout.close(); | ||
1557 | } | ||
1558 | } | ||
1559 | /* generate macro header */ | ||
1560 | if(!generate_macro_header(ectx)) | ||
1561 | return false; | ||
1562 | return true; | ||
1563 | } | ||
1564 | |||
1565 | /** | ||
1566 | * Generator: jz | ||
1567 | */ | ||
1568 | |||
1569 | class jz_generator : public common_generator | ||
1570 | { | ||
1571 | bool has_selectors() const | ||
1572 | { | ||
1573 | return m_soc.size() >= 2; | ||
1574 | } | ||
1575 | |||
1576 | std::string selector_soc_dir(const soc_ref_t& ref) const | ||
1577 | { | ||
1578 | return ref.get()->name; | ||
1579 | } | ||
1580 | |||
1581 | std::string selector_include_header() const | ||
1582 | { | ||
1583 | return "select.h"; | ||
1584 | } | ||
1585 | |||
1586 | std::string selector_soc_macro(const soc_ref_t& ref) const | ||
1587 | { | ||
1588 | return toupper(ref.get()->name) + "_INCLUDE"; | ||
1589 | } | ||
1590 | |||
1591 | std::string register_header(const node_inst_t& inst) const | ||
1592 | { | ||
1593 | /* one register header per top-level block */ | ||
1594 | if(inst.is_root()) | ||
1595 | return "<error>"; | ||
1596 | if(inst.parent().is_root()) | ||
1597 | return tolower(inst.node().name()) + ".h"; | ||
1598 | else | ||
1599 | return register_header(inst.parent()); | ||
1600 | } | ||
1601 | |||
1602 | std::string macro_name(macro_name_t macro) const | ||
1603 | { | ||
1604 | switch(macro) | ||
1605 | { | ||
1606 | case MN_REG_READ: return "jz_read"; | ||
1607 | case MN_FIELD_READ: return "jz_readf"; | ||
1608 | case MN_FIELD_READX: return "jz_vreadf"; | ||
1609 | case MN_REG_WRITE: return "jz_write"; | ||
1610 | case MN_FIELD_WRITE: return "jz_writef"; | ||
1611 | case MN_FIELD_OVERWRITE: return "jz_overwritef"; | ||
1612 | case MN_FIELD_WRITEX: return "jz_vwritef"; | ||
1613 | case MN_FIELD_SET: return "jz_setf"; | ||
1614 | case MN_FIELD_CLEAR: return "jz_clrf"; | ||
1615 | case MN_FIELD_TOG: return "jz_togf"; | ||
1616 | case MN_FIELD_CLEAR_SET: return "jz_csf"; | ||
1617 | case MN_FIELD_OR: return "jz_orf"; | ||
1618 | case MN_FIELD_OR_MASK: return "__jz_orfm"; // internal macro | ||
1619 | case MN_MASK_OR: return "jz_orm"; | ||
1620 | case MN_REG_CLEAR_SET: return "jz_cs"; | ||
1621 | case MN_GET_VARIANT: return "__jz_variant"; // internal macro | ||
1622 | case MN_VARIABLE: return "jz_reg"; | ||
1623 | default: return "<macro_name>"; | ||
1624 | } | ||
1625 | } | ||
1626 | |||
1627 | std::string macro_header() const | ||
1628 | { | ||
1629 | return "macro.h"; | ||
1630 | } | ||
1631 | |||
1632 | bool register_flag(const node_inst_t& inst, register_flag_t flag) const | ||
1633 | { | ||
1634 | /* make everything parametrized */ | ||
1635 | switch(flag) | ||
1636 | { | ||
1637 | case RF_GENERATE_ALL_INST: return false; | ||
1638 | case RF_GENERATE_PARAM_INST: return true; | ||
1639 | default: return false; | ||
1640 | } | ||
1641 | } | ||
1642 | |||
1643 | std::string type_xfix(macro_type_t type, bool prefix) const | ||
1644 | { | ||
1645 | switch(type) | ||
1646 | { | ||
1647 | case MT_REG_ADDR: return prefix ? "JA_" : ""; | ||
1648 | case MT_REG_TYPE: return prefix ? "JT_" : ""; | ||
1649 | case MT_REG_NAME: return prefix ? "JN_" : ""; | ||
1650 | case MT_REG_INDEX: return prefix ? "JI_" : ""; | ||
1651 | case MT_REG_VAR: return prefix ? "REG_" : ""; | ||
1652 | case MT_FIELD_BP: return prefix ? "BP_" : ""; | ||
1653 | case MT_FIELD_BM: return prefix ? "BM_" : ""; | ||
1654 | case MT_FIELD_BV: return prefix ? "BV_" : ""; | ||
1655 | case MT_FIELD_BF: return prefix ? "BF_" : ""; | ||
1656 | case MT_FIELD_BFM: return prefix ? "BFM_" : ""; | ||
1657 | case MT_FIELD_BFV: return prefix ? "BF_" : "_V"; | ||
1658 | case MT_FIELD_BFMV: return prefix ? "BFM_" : "_V"; | ||
1659 | case MT_IO_TYPE: return prefix ? "JIO_" : ""; | ||
1660 | default: return "<xfix>"; | ||
1661 | } | ||
1662 | } | ||
1663 | |||
1664 | std::string variant_xfix(const std::string& variant, bool prefix) const | ||
1665 | { | ||
1666 | /* variant X -> reg_X */ | ||
1667 | if(prefix) | ||
1668 | return ""; | ||
1669 | else | ||
1670 | return "_" + toupper(variant); | ||
1671 | } | ||
1672 | |||
1673 | std::string inst_prefix(const node_inst_t& inst) const | ||
1674 | { | ||
1675 | /* separate blocks with _: block_reg */ | ||
1676 | return "_"; | ||
1677 | } | ||
1678 | |||
1679 | std::string field_prefix() const | ||
1680 | { | ||
1681 | /* separate fields with _: block_reg_field */ | ||
1682 | return "_"; | ||
1683 | } | ||
1684 | |||
1685 | std::string enum_prefix() const | ||
1686 | { | ||
1687 | /* separate enums with __: block_reg_field__enum */ | ||
1688 | return "__"; | ||
1689 | } | ||
1690 | |||
1691 | std::string enum_name(const enum_ref_t& enum_) const | ||
1692 | { | ||
1693 | return enum_.get()->name; | ||
1694 | } | ||
1695 | |||
1696 | access_type_t register_access(const std::string& variant, access_t access) const | ||
1697 | { | ||
1698 | /* SET and CLR are special and always promoted to WO */ | ||
1699 | if(variant == "set" || variant == "clr" || access == WRITE_ONLY) | ||
1700 | return AT_WO; | ||
1701 | else if(access == READ_ONLY) | ||
1702 | return AT_RO; | ||
1703 | else | ||
1704 | return AT_RW; | ||
1705 | } | ||
1706 | |||
1707 | bool has_sct() const | ||
1708 | { | ||
1709 | return true; | ||
1710 | } | ||
1711 | |||
1712 | std::string sct_variant(macro_name_t name) const | ||
1713 | { | ||
1714 | switch(name) | ||
1715 | { | ||
1716 | case MN_FIELD_SET: return "set"; // always use set variant | ||
1717 | case MN_FIELD_CLEAR: return "clr"; // always use clr variant | ||
1718 | default: return ""; | ||
1719 | } | ||
1720 | } | ||
1721 | }; | ||
1722 | |||
1723 | /** | ||
1724 | * Generator: imx | ||
1725 | */ | ||
1726 | |||
1727 | class imx_generator : public common_generator | ||
1728 | { | ||
1729 | bool has_selectors() const | ||
1730 | { | ||
1731 | return m_soc.size() >= 2; | ||
1732 | } | ||
1733 | |||
1734 | std::string selector_soc_dir(const soc_ref_t& ref) const | ||
1735 | { | ||
1736 | return ref.get()->name; | ||
1737 | } | ||
1738 | |||
1739 | std::string selector_include_header() const | ||
1740 | { | ||
1741 | return "select.h"; | ||
1742 | } | ||
1743 | |||
1744 | std::string selector_soc_macro(const soc_ref_t& ref) const | ||
1745 | { | ||
1746 | return toupper(ref.get()->name) + "_INCLUDE"; | ||
1747 | } | ||
1748 | |||
1749 | std::string register_header(const node_inst_t& inst) const | ||
1750 | { | ||
1751 | /* one register header per top-level block */ | ||
1752 | if(inst.is_root()) | ||
1753 | return "<error>"; | ||
1754 | if(inst.parent().is_root()) | ||
1755 | return tolower(inst.node().name()) + ".h"; | ||
1756 | else | ||
1757 | return register_header(inst.parent()); | ||
1758 | } | ||
1759 | |||
1760 | std::string macro_name(macro_name_t macro) const | ||
1761 | { | ||
1762 | switch(macro) | ||
1763 | { | ||
1764 | case MN_REG_READ: return "REG_RD"; | ||
1765 | case MN_FIELD_READ: return "BF_RD"; | ||
1766 | case MN_FIELD_READX: return "BF_RDX"; | ||
1767 | case MN_REG_WRITE: return "REG_WR"; | ||
1768 | case MN_FIELD_WRITE: return "BF_WR"; | ||
1769 | case MN_FIELD_OVERWRITE: return "BF_WR_ALL"; | ||
1770 | case MN_FIELD_WRITEX: return "BF_WRX"; | ||
1771 | case MN_FIELD_SET: return "BF_SET"; | ||
1772 | case MN_FIELD_CLEAR: return "BF_CLR"; | ||
1773 | case MN_FIELD_TOG: return "BF_TOG"; | ||
1774 | case MN_FIELD_CLEAR_SET: return "BF_CS"; | ||
1775 | case MN_FIELD_OR: return "BF_OR"; | ||
1776 | case MN_FIELD_OR_MASK: return "__BFM_OR"; | ||
1777 | case MN_MASK_OR: return "BM_OR"; | ||
1778 | case MN_REG_CLEAR_SET: return "REG_CS"; | ||
1779 | case MN_GET_VARIANT: return "__REG_VARIANT"; | ||
1780 | case MN_VARIABLE: return "HW"; | ||
1781 | default: return "<macro_name>"; | ||
1782 | } | ||
1783 | } | ||
1784 | |||
1785 | std::string macro_header() const | ||
1786 | { | ||
1787 | return "macro.h"; | ||
1788 | } | ||
1789 | |||
1790 | bool register_flag(const node_inst_t& inst, register_flag_t flag) const | ||
1791 | { | ||
1792 | /* make everything parametrized */ | ||
1793 | switch(flag) | ||
1794 | { | ||
1795 | case RF_GENERATE_ALL_INST: return false; | ||
1796 | case RF_GENERATE_PARAM_INST: return true; | ||
1797 | default: return false; | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | std::string type_xfix(macro_type_t type, bool prefix) const | ||
1802 | { | ||
1803 | switch(type) | ||
1804 | { | ||
1805 | case MT_REG_ADDR: return prefix ? "HWA_" : ""; | ||
1806 | case MT_REG_TYPE: return prefix ? "HWT_" : ""; | ||
1807 | case MT_REG_NAME: return prefix ? "HWN_" : ""; | ||
1808 | case MT_REG_INDEX: return prefix ? "HWI_" : ""; | ||
1809 | case MT_REG_VAR: return prefix ? "HW_" : ""; | ||
1810 | case MT_FIELD_BP: return prefix ? "BP_" : ""; | ||
1811 | case MT_FIELD_BM: return prefix ? "BM_" : ""; | ||
1812 | case MT_FIELD_BV: return prefix ? "BV_" : ""; | ||
1813 | case MT_FIELD_BF: return prefix ? "BF_" : ""; | ||
1814 | case MT_FIELD_BFM: return prefix ? "BFM_" : ""; | ||
1815 | case MT_FIELD_BFV: return prefix ? "BF_" : "_V"; | ||
1816 | case MT_FIELD_BFMV: return prefix ? "BFM_" : "_V"; | ||
1817 | case MT_IO_TYPE: return prefix ? "HWIO_" : ""; | ||
1818 | default: return "<xfix>"; | ||
1819 | } | ||
1820 | } | ||
1821 | |||
1822 | std::string variant_xfix(const std::string& variant, bool prefix) const | ||
1823 | { | ||
1824 | /* variant X -> reg_X */ | ||
1825 | if(prefix) | ||
1826 | return ""; | ||
1827 | else | ||
1828 | return "_" + toupper(variant); | ||
1829 | } | ||
1830 | |||
1831 | std::string inst_prefix(const node_inst_t& inst) const | ||
1832 | { | ||
1833 | /* separate blocks with _: block_reg */ | ||
1834 | return "_"; | ||
1835 | } | ||
1836 | |||
1837 | std::string field_prefix() const | ||
1838 | { | ||
1839 | /* separate fields with _: block_reg_field */ | ||
1840 | return "_"; | ||
1841 | } | ||
1842 | |||
1843 | std::string enum_prefix() const | ||
1844 | { | ||
1845 | /* separate enums with __: block_reg_field__enum */ | ||
1846 | return "__"; | ||
1847 | } | ||
1848 | |||
1849 | std::string enum_name(const enum_ref_t& enum_) const | ||
1850 | { | ||
1851 | return enum_.get()->name; | ||
1852 | } | ||
1853 | |||
1854 | access_type_t register_access(const std::string& variant, access_t access) const | ||
1855 | { | ||
1856 | /* SET, CLR and TOG are special and always promoted to WO */ | ||
1857 | if(variant == "set" || variant == "clr" || variant == "tog" || access == WRITE_ONLY) | ||
1858 | return AT_WO; | ||
1859 | else if(access == READ_ONLY) | ||
1860 | return AT_RO; | ||
1861 | else | ||
1862 | return AT_RW; | ||
1863 | } | ||
1864 | |||
1865 | bool has_sct() const | ||
1866 | { | ||
1867 | return true; | ||
1868 | } | ||
1869 | |||
1870 | std::string sct_variant(macro_name_t name) const | ||
1871 | { | ||
1872 | switch(name) | ||
1873 | { | ||
1874 | case MN_FIELD_SET: return "set"; // always use set variant | ||
1875 | case MN_FIELD_CLEAR: return "clr"; // always use clr variant | ||
1876 | case MN_FIELD_TOG: return "tog"; // always use tog variant | ||
1877 | default: return ""; | ||
1878 | } | ||
1879 | } | ||
1880 | }; | ||
1881 | |||
1882 | /** | ||
1883 | * Driver | ||
1884 | */ | ||
1885 | |||
1886 | abstract_generator *get_generator(const std::string& name) | ||
1887 | { | ||
1888 | if(name == "jz") | ||
1889 | return new jz_generator(); | ||
1890 | else if(name == "imx") | ||
1891 | return new imx_generator(); | ||
1892 | else | ||
1893 | return 0; | ||
1894 | } | ||
1895 | |||
1896 | void usage() | ||
1897 | { | ||
1898 | printf("usage: headergen [options] <desc files...>\n"); | ||
1899 | printf("options:\n"); | ||
1900 | printf(" -?/--help Dispaly this help\n"); | ||
1901 | printf(" -g/--generator <gen> Select generator (jz, imx)\n"); | ||
1902 | printf(" -o/--outdir <dir> Output directory\n"); | ||
1903 | exit(1); | ||
1904 | } | ||
1905 | |||
1906 | int main(int argc, char **argv) | ||
1907 | { | ||
1908 | char *generator_name = NULL; | ||
1909 | char *outdir = NULL; | ||
1910 | if(argc <= 1) | ||
1911 | usage(); | ||
1912 | |||
1913 | while(1) | ||
1914 | { | ||
1915 | static struct option long_options[] = | ||
1916 | { | ||
1917 | {"help", no_argument, 0, '?'}, | ||
1918 | {"generator", required_argument, 0, 'g'}, | ||
1919 | {"outdir", required_argument, 0, 'o'}, | ||
1920 | {0, 0, 0, 0} | ||
1921 | }; | ||
1922 | |||
1923 | int c = getopt_long(argc, argv, "?g:o:", long_options, NULL); | ||
1924 | if(c == -1) | ||
1925 | break; | ||
1926 | switch(c) | ||
1927 | { | ||
1928 | case -1: | ||
1929 | break; | ||
1930 | case '?': | ||
1931 | usage(); | ||
1932 | break; | ||
1933 | case 'g': | ||
1934 | generator_name = optarg; | ||
1935 | break; | ||
1936 | case 'o': | ||
1937 | outdir = optarg; | ||
1938 | break; | ||
1939 | default: | ||
1940 | abort(); | ||
1941 | } | ||
1942 | } | ||
1943 | if(argc == optind) | ||
1944 | { | ||
1945 | printf("You need at least one description file\n"); | ||
1946 | return 3; | ||
1947 | } | ||
1948 | if(outdir == 0) | ||
1949 | { | ||
1950 | printf("You need to select an output directory\n"); | ||
1951 | return 4; | ||
1952 | } | ||
1953 | if(generator_name == 0) | ||
1954 | { | ||
1955 | printf("You need to select a generator\n"); | ||
1956 | return 1; | ||
1957 | } | ||
1958 | abstract_generator *gen = get_generator(generator_name); | ||
1959 | if(gen == 0) | ||
1960 | { | ||
1961 | printf("Unknown generator name '%s'\n", generator_name); | ||
1962 | return 2; | ||
1963 | } | ||
1964 | |||
1965 | gen->set_output_dir(outdir); | ||
1966 | for(int i = optind; i < argc; i++) | ||
1967 | { | ||
1968 | error_context_t ctx; | ||
1969 | soc_t s; | ||
1970 | bool ret = parse_xml(argv[i], s, ctx); | ||
1971 | if(ctx.count() != 0) | ||
1972 | printf("In file %s:\n", argv[i]); | ||
1973 | print_context(ctx); | ||
1974 | if(!ret) | ||
1975 | { | ||
1976 | printf("Cannot parse file '%s'\n", argv[i]); | ||
1977 | return 1; | ||
1978 | } | ||
1979 | gen->add_soc(s); | ||
1980 | } | ||
1981 | error_context_t ctx; | ||
1982 | bool ret = gen->generate(ctx); | ||
1983 | print_context(ctx); | ||
1984 | if(!ret) | ||
1985 | { | ||
1986 | printf("Cannot generate headers\n"); | ||
1987 | return 5; | ||
1988 | } | ||
1989 | |||
1990 | return 0; | ||
1991 | } | ||