diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-12-14 11:53:55 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2015-09-11 16:40:19 +0200 |
commit | 1cada1f8339d6b5f8506277f80e62aaef77ab774 (patch) | |
tree | 8477120e97832d659d2ffc471a8bfde73ad4c36e /utils/regtools/headergen_v1.cpp | |
parent | c8d3638b9ebc24e4766714da1c9f961e350799c6 (diff) | |
download | rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.gz rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.zip |
soc_desc: new version of the desc file format
Fix qeditor to use the old soc_desc_v1.
Port hwstub_shell to the new description format.
Change-Id: I9fefbff534bfaa5c3603bb3dd8307a2b76e88cfc
Diffstat (limited to 'utils/regtools/headergen_v1.cpp')
-rw-r--r-- | utils/regtools/headergen_v1.cpp | 751 |
1 files changed, 751 insertions, 0 deletions
diff --git a/utils/regtools/headergen_v1.cpp b/utils/regtools/headergen_v1.cpp new file mode 100644 index 0000000000..7b38366d5d --- /dev/null +++ b/utils/regtools/headergen_v1.cpp | |||
@@ -0,0 +1,751 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2013 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_v1.hpp" | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <algorithm> | ||
25 | #include <map> | ||
26 | #include <sstream> | ||
27 | #include <sys/stat.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <getopt.h> | ||
30 | |||
31 | using namespace soc_desc_v1; | ||
32 | |||
33 | #define HEADERGEN_VERSION "2.1.8" | ||
34 | |||
35 | #define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0) | ||
36 | |||
37 | bool g_gen_selector = false; | ||
38 | |||
39 | std::string g_macro_filename; | ||
40 | |||
41 | std::string g_soc_name; | ||
42 | std::string g_soc_dev; | ||
43 | std::string g_soc_reg; | ||
44 | std::string g_soc_field; | ||
45 | std::string g_soc_dev_regs_base; | ||
46 | |||
47 | namespace { | ||
48 | std::string tolower(const std::string s) | ||
49 | { | ||
50 | std::string res = s; | ||
51 | std::transform(res.begin(), res.end(), res.begin(), ::tolower); | ||
52 | return res; | ||
53 | } | ||
54 | |||
55 | std::string toupper(const std::string& s) | ||
56 | { | ||
57 | std::string res = s; | ||
58 | std::transform(res.begin(), res.end(), res.begin(), ::toupper); | ||
59 | return res; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | template< typename T > | ||
64 | std::string to_str(const T& v) | ||
65 | { | ||
66 | std::ostringstream oss; | ||
67 | oss << v; | ||
68 | return oss.str(); | ||
69 | } | ||
70 | |||
71 | template< typename T > | ||
72 | std::string to_hex(const T& v) | ||
73 | { | ||
74 | std::ostringstream oss; | ||
75 | oss << std::hex << v; | ||
76 | return oss.str(); | ||
77 | } | ||
78 | |||
79 | typedef std::pair< std::string, std::string > xml_ver_t; | ||
80 | |||
81 | void fprint_copyright(FILE *f, const std::vector< xml_ver_t >& versions, char const *author) | ||
82 | { | ||
83 | std::ostringstream ver; | ||
84 | time_t t = time(NULL); | ||
85 | struct tm tm = *localtime(&t); | ||
86 | |||
87 | for(size_t i = 0; i < versions.size(); i++) | ||
88 | ver << " " << versions[i].first << ":" << versions[i].second; | ||
89 | |||
90 | fprintf(f,"\ | ||
91 | /***************************************************************************\n\ | ||
92 | * __________ __ ___.\n\ | ||
93 | * Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\ | ||
94 | * Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\ | ||
95 | * Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\ | ||
96 | * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\ | ||
97 | * \\/ \\/ \\/ \\/ \\/\n\ | ||
98 | * This file was automatically generated by headergen, DO NOT EDIT it.\n\ | ||
99 | * headergen version: " HEADERGEN_VERSION "\n"); | ||
100 | if(versions.size() > 0) | ||
101 | fprintf(f, " * XML versions:%s\n", ver.str().c_str()); | ||
102 | fprintf(f,"\ | ||
103 | *\n\ | ||
104 | * Copyright (C) "); | ||
105 | fprintf(f, "%d by %s\n", 1900+tm.tm_year, author); | ||
106 | fprintf(f,"\ | ||
107 | *\n\ | ||
108 | * This program is free software; you can redistribute it and/or\n\ | ||
109 | * modify it under the terms of the GNU General Public License\n\ | ||
110 | * as published by the Free Software Foundation; either version 2\n\ | ||
111 | * of the License, or (at your option) any later version.\n\ | ||
112 | *\n\ | ||
113 | * This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\ | ||
114 | * KIND, either express or implied.\n\ | ||
115 | *\n\ | ||
116 | ****************************************************************************/\n"); | ||
117 | } | ||
118 | |||
119 | void fprint_copyright(FILE *f, const xml_ver_t& version, char const *author) | ||
120 | { | ||
121 | fprint_copyright(f, std::vector< xml_ver_t >(1, version), author); | ||
122 | } | ||
123 | |||
124 | void fprint_copyright(FILE *f, char const *author) | ||
125 | { | ||
126 | fprint_copyright(f, std::vector< xml_ver_t >(), author); | ||
127 | } | ||
128 | |||
129 | void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name) | ||
130 | { | ||
131 | if(begin) | ||
132 | { | ||
133 | fprintf(f, "#ifndef %s\n", name.c_str()); | ||
134 | fprintf(f, "#define %s\n", name.c_str()); | ||
135 | } | ||
136 | else | ||
137 | fprintf(f, "#endif /* %s */\n", name.c_str()); | ||
138 | } | ||
139 | |||
140 | void fprint_include_guard(FILE *f, bool begin) | ||
141 | { | ||
142 | std::string name = "__HEADERGEN__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev) | ||
143 | + "__H__"; | ||
144 | fprint_include_guard_ex(f, begin, name); | ||
145 | } | ||
146 | |||
147 | struct limited_column_context_t | ||
148 | { | ||
149 | limited_column_context_t(size_t nr_col = 80) | ||
150 | :m_nr_col(nr_col), m_prevent_wordcut(true) {} | ||
151 | void set_prefix(const std::string& prefix) { m_prefix = prefix; } | ||
152 | void add(const std::string& text) | ||
153 | { | ||
154 | for(size_t i = 0; i < text.size();) | ||
155 | { | ||
156 | size_t offset = 0; | ||
157 | if(m_cur_line.size() == 0) | ||
158 | m_cur_line = m_prefix; | ||
159 | size_t len = std::min(text.size() - i, m_nr_col - m_cur_line.size()); | ||
160 | // prevent word cut | ||
161 | if(m_prevent_wordcut && !isspace(text[i + len - 1]) && | ||
162 | i + len < text.size() && !isspace(text[i + len])) | ||
163 | { | ||
164 | size_t pos = text.find_last_of(" \t\n\v\r\f", i + len - 1); | ||
165 | if(pos == std::string::npos || pos < i) | ||
166 | len = 0; | ||
167 | else | ||
168 | len = pos - i + 1; | ||
169 | } | ||
170 | size_t pos = text.find('\n', i); | ||
171 | if(pos != std::string::npos && pos <= i + len) | ||
172 | { | ||
173 | offset = 1; | ||
174 | len = pos - i; | ||
175 | } | ||
176 | m_cur_line += text.substr(i, len); | ||
177 | // len == 0 means we need a new line | ||
178 | if(m_cur_line.size() == m_nr_col || len == 0) | ||
179 | { | ||
180 | m_lines.push_back(m_cur_line); | ||
181 | m_cur_line = ""; | ||
182 | } | ||
183 | i += len + offset; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | std::string to_string() | ||
188 | { | ||
189 | std::string str; | ||
190 | for(size_t i = 0; i < m_lines.size(); i++) | ||
191 | str += m_lines[i] + "\n"; | ||
192 | if(m_cur_line.size() != 0) | ||
193 | str += m_cur_line + "\n"; | ||
194 | return str; | ||
195 | } | ||
196 | |||
197 | void print(FILE *f) | ||
198 | { | ||
199 | fprintf(f, "%s", to_string().c_str()); | ||
200 | } | ||
201 | |||
202 | std::vector< std::string > m_lines; | ||
203 | std::string m_cur_line; | ||
204 | std::string m_prefix; | ||
205 | size_t m_nr_col; | ||
206 | bool m_prevent_wordcut; | ||
207 | }; | ||
208 | |||
209 | struct define_align_context_t | ||
210 | { | ||
211 | define_align_context_t():m_max_name(0) {} | ||
212 | void add(const std::string& name, const std::string& val) | ||
213 | { | ||
214 | m_lines.push_back(std::make_pair(name, val)); | ||
215 | m_max_name = std::max(m_max_name, name.size()); | ||
216 | } | ||
217 | |||
218 | void add_raw(const std::string& line) | ||
219 | { | ||
220 | m_lines.push_back(std::make_pair("", line)); | ||
221 | } | ||
222 | |||
223 | void print(FILE *f) | ||
224 | { | ||
225 | std::string define = "#define "; | ||
226 | size_t align = define.size() + m_max_name + 1; | ||
227 | align = ((align + 3) / 4) * 4; | ||
228 | |||
229 | for(size_t i = 0; i < m_lines.size(); i++) | ||
230 | { | ||
231 | std::string name = m_lines[i].first; | ||
232 | // raw entry ? | ||
233 | if(name.size() == 0) | ||
234 | { | ||
235 | fprintf(f, "%s", m_lines[i].second.c_str()); | ||
236 | continue; | ||
237 | } | ||
238 | name.insert(name.end(), align - define.size() - name.size(), ' '); | ||
239 | fprintf(f, "%s%s%s\n", define.c_str(), name.c_str(), m_lines[i].second.c_str()); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | size_t m_max_name; | ||
244 | std::vector< std::pair< std::string, std::string > > m_lines; | ||
245 | }; | ||
246 | |||
247 | limited_column_context_t print_description(const std::string& desc, const std::string& prefix) | ||
248 | { | ||
249 | limited_column_context_t ctx; | ||
250 | if(desc.size() == 0) | ||
251 | return ctx; | ||
252 | ctx.set_prefix(prefix); | ||
253 | ctx.add(desc); | ||
254 | return ctx; | ||
255 | } | ||
256 | |||
257 | void fprint_description(FILE *f, const std::string& desc, const std::string& prefix) | ||
258 | { | ||
259 | limited_column_context_t ctx = print_description(desc, prefix); | ||
260 | ctx.print(f); | ||
261 | } | ||
262 | |||
263 | void fprint_description(define_align_context_t& ctx, const std::string& desc, const std::string& prefix) | ||
264 | { | ||
265 | limited_column_context_t ctx2 = print_description(desc, prefix); | ||
266 | ctx.add_raw(ctx2.to_string()); | ||
267 | } | ||
268 | |||
269 | void gen_soc_field(define_align_context_t& ctx, bool multidev, bool multireg, const soc_reg_field_t& field) | ||
270 | { | ||
271 | if(field.desc.size() != 0) | ||
272 | { | ||
273 | ctx.add_raw("/* Field: " + field.name + "\n"); | ||
274 | fprint_description(ctx, "Description: " + field.desc + " */\n", " * "); | ||
275 | } | ||
276 | |||
277 | std::string prefix = g_soc_dev + "_" + g_soc_reg + "_" + g_soc_field; | ||
278 | ctx.add("BP_" + prefix, to_str(field.first_bit)); | ||
279 | ctx.add("BM_" + prefix, "0x" + to_hex(field.bitmask())); | ||
280 | |||
281 | for(size_t i = 0; i < field.value.size(); i++) | ||
282 | ctx.add("BV_" + prefix + "__" + field.value[i].name, "0x" + to_hex(field.value[i].value)); | ||
283 | |||
284 | ctx.add("BF_" + prefix + "(v)", "(((v) << " + to_str(field.first_bit) + ") & 0x" + to_hex(field.bitmask()) + ")"); | ||
285 | |||
286 | if(field.value.size() > 0) | ||
287 | ctx.add("BF_" + prefix + "_V(v)", "((BV_" + prefix + "__##v" + " << " + to_str(field.first_bit) + ") & 0x" + to_hex(field.bitmask()) + ")"); | ||
288 | } | ||
289 | |||
290 | void gen_soc_reg(FILE *f, bool multidev, const soc_reg_t& reg, char const *author, char const *hwprefix) | ||
291 | { | ||
292 | bool multireg = reg.addr.size() > 1; | ||
293 | |||
294 | static const char *suffix[] = {"", "_SET", "_CLR", "_TOG"}; | ||
295 | bool sct = !!(reg.flags & REG_HAS_SCT); | ||
296 | |||
297 | // comment generator | ||
298 | fprintf(f, "/**\n"); | ||
299 | fprintf(f, " * Register: %s%s_%s\n", hwprefix, g_soc_dev.c_str(), g_soc_reg.c_str()); | ||
300 | fprintf(f, " * Address:"); | ||
301 | if(multireg && reg.formula.type == REG_FORMULA_STRING) | ||
302 | { | ||
303 | fprintf(f, " %s\n", reg.formula.string.c_str()); | ||
304 | } | ||
305 | else | ||
306 | { | ||
307 | for(size_t i = 0; i < reg.addr.size(); i++) | ||
308 | fprintf(f, " %#x", reg.addr[i].addr); | ||
309 | fprintf(f, "\n"); | ||
310 | } | ||
311 | fprintf(f, " * SCT: %s\n", sct ? "yes" : "no"); | ||
312 | if(reg.desc.size() != 0) | ||
313 | fprint_description(f, "Description: " + reg.desc, " * "); | ||
314 | fprintf(f, " */\n"); | ||
315 | |||
316 | define_align_context_t ctx; | ||
317 | |||
318 | if (multireg && reg.formula.type != REG_FORMULA_STRING) | ||
319 | { | ||
320 | for(int i=0; i < (int)reg.addr.size(); i++) | ||
321 | { | ||
322 | std::ostringstream name, value; | ||
323 | name << hwprefix << g_soc_dev << "_" << reg.addr[i].name; | ||
324 | if (multidev) | ||
325 | { | ||
326 | name << "(d)"; | ||
327 | } | ||
328 | value << "(*(volatile unsigned long *)(" << g_soc_dev_regs_base; | ||
329 | if (multidev) | ||
330 | { | ||
331 | value << "(d)"; | ||
332 | } | ||
333 | value << " + 0x" << std::hex << reg.addr[i].addr << "))"; | ||
334 | |||
335 | ctx.add(name.str(), value.str()); | ||
336 | } | ||
337 | } | ||
338 | else | ||
339 | { | ||
340 | for(int i = 0; i < (sct ? 4 : 1); i++) | ||
341 | { | ||
342 | std::ostringstream name; | ||
343 | name << hwprefix << g_soc_dev << "_" << g_soc_reg << suffix[i]; | ||
344 | if(multidev || multireg) | ||
345 | { | ||
346 | name << "("; | ||
347 | if(multidev) | ||
348 | name << "d"; | ||
349 | if(multidev && multireg) | ||
350 | name << ","; | ||
351 | if(multireg) | ||
352 | name << "n"; | ||
353 | name << ")"; | ||
354 | } | ||
355 | std::ostringstream value; | ||
356 | value << "(*(volatile unsigned long *)(" << g_soc_dev_regs_base; | ||
357 | if(multidev) | ||
358 | value << "(d)"; | ||
359 | value << " + "; | ||
360 | if(multireg) | ||
361 | { | ||
362 | std::string formula = reg.formula.string.c_str(); | ||
363 | size_t pos = formula.find("n"); | ||
364 | while(pos != std::string::npos) | ||
365 | { | ||
366 | formula.replace(pos, 1, "(n)"); | ||
367 | pos = formula.find("n", pos + 2); | ||
368 | } | ||
369 | value << formula; | ||
370 | } | ||
371 | else | ||
372 | value << "0x" << std::hex << reg.addr[0].addr; | ||
373 | |||
374 | if(sct) | ||
375 | value << " + 0x" << std::hex << (i * 4); | ||
376 | value << "))"; | ||
377 | |||
378 | ctx.add(name.str(), value.str()); | ||
379 | } | ||
380 | } | ||
381 | |||
382 | for(size_t i = 0; i < reg.field.size(); i++) | ||
383 | { | ||
384 | g_soc_field = reg.field[i].name; | ||
385 | gen_soc_field(ctx, multidev, multireg, reg.field[i]); | ||
386 | } | ||
387 | |||
388 | ctx.print(f); | ||
389 | |||
390 | fprintf(f, "\n"); | ||
391 | } | ||
392 | |||
393 | void gen_soc_dev_header(const std::string& filename, const xml_ver_t& ver, const soc_dev_t& dev, | ||
394 | char const *author, char const *hwprefix) | ||
395 | { | ||
396 | /* | ||
397 | printf("Generate headers for soc %s, dev %s: use file %s\n", g_soc_name.c_str(), | ||
398 | g_soc_dev.c_str(), filename.c_str()); | ||
399 | */ | ||
400 | FILE *f = fopen(filename.c_str(), "w"); | ||
401 | if(f == NULL) | ||
402 | { | ||
403 | printf("Cannot open %s for writing: %m\n", filename.c_str()); | ||
404 | return; | ||
405 | } | ||
406 | fprint_copyright(f, ver, author); | ||
407 | fprint_include_guard(f, true); | ||
408 | if(g_macro_filename.size() > 0) | ||
409 | fprintf(f, "#include \"%s\"\n", g_macro_filename.c_str()); | ||
410 | |||
411 | /* print base */ | ||
412 | fprintf(f, "\n"); | ||
413 | g_soc_dev_regs_base = "REGS_" + g_soc_dev + "_BASE"; | ||
414 | fprintf(f, "#define %s", g_soc_dev_regs_base.c_str()); | ||
415 | |||
416 | if(dev.addr.size() > 1) | ||
417 | fprintf(f, "(i)"); | ||
418 | fprintf(f, " ("); | ||
419 | |||
420 | for(size_t i = 0; i < dev.addr.size() - 1; i++) | ||
421 | fprintf(f, "(i) == %d ? %#x : ", (int)i + 1, dev.addr[i].addr); | ||
422 | |||
423 | fprintf(f, "%#x)\n", dev.addr[dev.addr.size() - 1].addr); | ||
424 | |||
425 | fprintf(f, "\n"); | ||
426 | |||
427 | /* print version */ | ||
428 | fprintf(f, "#define REGS_%s_VERSION \"%s\"\n\n", g_soc_dev.c_str(), dev.version.c_str()); | ||
429 | |||
430 | for(size_t i = 0; i < dev.reg.size(); i++) | ||
431 | { | ||
432 | g_soc_reg = dev.reg[i].name; | ||
433 | gen_soc_reg(f, dev.addr.size() > 1, dev.reg[i], author, hwprefix); | ||
434 | } | ||
435 | |||
436 | fprint_include_guard(f, false); | ||
437 | fclose(f); | ||
438 | } | ||
439 | |||
440 | void gen_soc_headers(const std::string& prefix, const soc_t& soc, char const *author, char const *hwprefix) | ||
441 | { | ||
442 | printf("Generate headers for soc %s: use directory %s\n", soc.name.c_str(), | ||
443 | prefix.c_str()); | ||
444 | mkdir(prefix.c_str(), 0770); | ||
445 | |||
446 | for(size_t i = 0; i < soc.dev.size(); i++) | ||
447 | { | ||
448 | g_soc_dev = soc.dev[i].name; | ||
449 | xml_ver_t ver(soc.name, soc.dev[i].version); | ||
450 | gen_soc_dev_header(prefix + "/regs-" + tolower(g_soc_dev.c_str()) + ".h", ver, soc.dev[i], author, hwprefix); | ||
451 | } | ||
452 | } | ||
453 | |||
454 | void gen_headers(const std::string& prefix, const std::vector< soc_t >& socs, char const *author, char const *hwprefix) | ||
455 | { | ||
456 | for(size_t i = 0; i < socs.size(); i++) | ||
457 | { | ||
458 | g_soc_name = socs[i].name; | ||
459 | std::string dir = prefix; | ||
460 | if(g_gen_selector) | ||
461 | dir += "/" + socs[i].name; | ||
462 | gen_soc_headers(dir, socs[i], author, hwprefix); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | typedef std::map< std::string, std::vector< std::pair< size_t, size_t > > > general_dev_list_t; | ||
467 | general_dev_list_t build_general_dev_list(const std::vector< soc_t >& socs) | ||
468 | { | ||
469 | general_dev_list_t map; | ||
470 | for(size_t i = 0; i < socs.size(); i++) | ||
471 | { | ||
472 | for(size_t j = 0; j < socs[i].dev.size(); j++) | ||
473 | map[tolower(socs[i].dev[j].name)].push_back(std::make_pair(i,j)); | ||
474 | } | ||
475 | return map; | ||
476 | } | ||
477 | |||
478 | void gen_select_header(const std::string& filename, const std::string& dev, | ||
479 | const std::vector< std::string >& socs, const std::vector< xml_ver_t >& ver, char const *author) | ||
480 | { | ||
481 | std::string guard = "__SELECT__" + toupper(dev) + "__H__"; | ||
482 | FILE *f = fopen(filename.c_str(), "w"); | ||
483 | if(f == NULL) | ||
484 | error("Cannot open file %s\n", filename.c_str()); | ||
485 | fprint_copyright(f, ver, author); | ||
486 | fprint_include_guard_ex(f, true, guard); | ||
487 | if(g_macro_filename.size() > 0) | ||
488 | fprintf(f, "#include \"%s\"\n", g_macro_filename.c_str()); | ||
489 | fprintf(f, "\n"); | ||
490 | |||
491 | for(size_t i = 0; i < socs.size(); i++) | ||
492 | { | ||
493 | fprintf(f, "#define %s_INCLUDE \"%s/regs-%s.h\"\n", | ||
494 | toupper(socs[i]).c_str(), tolower(socs[i]).c_str(), | ||
495 | tolower(dev).c_str()); | ||
496 | } | ||
497 | fprintf(f, "\n#include \"regs-select.h\"\n\n"); | ||
498 | for(size_t i = 0; i < socs.size(); i++) | ||
499 | { | ||
500 | fprintf(f, "#undef %s_INCLUDE\n", toupper(socs[i]).c_str()); | ||
501 | } | ||
502 | fprintf(f, "\n"); | ||
503 | fprint_include_guard_ex(f, false, guard); | ||
504 | fclose(f); | ||
505 | } | ||
506 | |||
507 | void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs, char const *author) | ||
508 | { | ||
509 | printf("Generate select headers: use directory %s\n", prefix.c_str()); | ||
510 | general_dev_list_t map = build_general_dev_list(socs); | ||
511 | for(general_dev_list_t::iterator it = map.begin(); it != map.end(); ++it) | ||
512 | { | ||
513 | std::vector< xml_ver_t > ver; | ||
514 | std::vector< std::string > names; | ||
515 | for(size_t i = 0; i < it->second.size(); i++) | ||
516 | { | ||
517 | size_t soc_nr = it->second[i].first; | ||
518 | size_t dev_in_soc_nr = it->second[i].second; | ||
519 | ver.push_back(std::make_pair(socs[soc_nr].name, socs[soc_nr].dev[dev_in_soc_nr].version)); | ||
520 | names.push_back(socs[soc_nr].name); | ||
521 | } | ||
522 | gen_select_header(prefix + "/regs-" + it->first + ".h", it->first, names, ver, author); | ||
523 | } | ||
524 | } | ||
525 | |||
526 | void gen_macro_list(FILE *f, const std::string& prefix, int count, int nr_digits, | ||
527 | const std::string& sep, int max_per_line = 1000, const std::string& align = "") | ||
528 | { | ||
529 | for(int i = 1; i <= count;) | ||
530 | { | ||
531 | for(int j = i; j <= std::min(count, i + max_per_line - 1); j++) | ||
532 | { | ||
533 | fprintf(f, "%s%0*d", prefix.c_str(), nr_digits, j); | ||
534 | if(j < count) | ||
535 | fprintf(f, "%s", sep.c_str()); | ||
536 | } | ||
537 | i += max_per_line; | ||
538 | if(i <= count) | ||
539 | fprintf(f, "\\\n%s", align.c_str()); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | void gen_macro(const std::string& filename, bool variadic, char const *author, char const *hwprefix) | ||
544 | { | ||
545 | printf("Generate %smacro header: use %s\n", variadic ? "": "non-variadic ", | ||
546 | filename.c_str()); | ||
547 | std::string guard = "__REGS__MACRO__H__"; | ||
548 | FILE *f = fopen(filename.c_str(), "w"); | ||
549 | if(f == NULL) | ||
550 | error("Cannot open file %s\n", filename.c_str()); | ||
551 | fprint_copyright(f, author); | ||
552 | fprint_include_guard_ex(f, true, guard); | ||
553 | fprintf(f, "\n"); | ||
554 | |||
555 | #define REG_WRITE "REG_WRITE" | ||
556 | fprintf(f, "#ifndef %s\n", REG_WRITE); | ||
557 | fprintf(f, "#define %s(var,value) ((var) = (value))\n", REG_WRITE); | ||
558 | fprintf(f, "#endif /* %s */\n", REG_WRITE); | ||
559 | fprintf(f, "\n"); | ||
560 | |||
561 | #define REG_READ "REG_READ" | ||
562 | fprintf(f, "#ifndef %s\n", REG_READ); | ||
563 | fprintf(f, "#define %s(var) (var)\n", REG_READ); | ||
564 | fprintf(f, "#endif /* %s */\n", REG_READ); | ||
565 | fprintf(f, "\n"); | ||
566 | |||
567 | const int MAX_NARGS = 32; | ||
568 | |||
569 | fprintf(f, "\ | ||
570 | #define BF_SET(reg, field) "REG_WRITE"(%1$s##reg##_SET, BM_##reg##_##field)\n\ | ||
571 | #define BF_CLR(reg, field) "REG_WRITE"(%1$s##reg##_CLR, BM_##reg##_##field)\n\ | ||
572 | #define BF_TOG(reg, field) "REG_WRITE"(%1$s##reg##_TOG, BM_##reg##_##field)\n\ | ||
573 | \n\ | ||
574 | #define BF_SETV(reg, field, v) "REG_WRITE"(%1$s##reg##_SET, BF_##reg##_##field(v))\n\ | ||
575 | #define BF_CLRV(reg, field, v) "REG_WRITE"(%1$s##reg##_CLR, BF_##reg##_##field(v))\n\ | ||
576 | #define BF_TOGV(reg, field, v) "REG_WRITE"(%1$s##reg##_TOG, BF_##reg##_##field(v))\n\ | ||
577 | \n\ | ||
578 | #define BF_RDX(val, reg, field) (("REG_READ"(val) & BM_##reg##_##field) >> BP_##reg##_##field)\n\ | ||
579 | #define BF_RD(reg, field) BF_RDX("REG_READ"(%1$s##reg), reg, field)\n\ | ||
580 | #define BF_WRX(val, reg, field, v) "REG_WRITE"(val, ("REG_READ"(val) & ~BM_##reg##_##field) | (((v) << BP_##reg##_##field) & BM_##reg##_##field))\n\ | ||
581 | #define BF_WR(reg, field, v) BF_WRX(%1$s##reg, reg, field, v)\n\ | ||
582 | #define BF_WR_V(reg, field, sy) BF_WR(reg, field, BV_##reg##_##field##__##sy)\n\ | ||
583 | #define BF_WR_VX(val, reg, field, sy) BF_WRX(val, reg, field, BV_##reg##_##field##__##sy)\n\ | ||
584 | \n\ | ||
585 | #define BF_SETn(reg, n, field) "REG_WRITE"(%1$s##reg##_SET(n), BM_##reg##_##field)\n\ | ||
586 | #define BF_CLRn(reg, n, field) "REG_WRITE"(%1$s##reg##_CLR(n), BM_##reg##_##field)\n\ | ||
587 | #define BF_TOGn(reg, n, field) "REG_WRITE"(%1$s##reg##_TOG(n), BM_##reg##_##field)\n\ | ||
588 | \n\ | ||
589 | #define BF_SETVn(reg, n, field, v) "REG_WRITE"(%1$s##reg##_SET(n), BF_##reg##_##field(v))\n\ | ||
590 | #define BF_CLRVn(reg, n, field, v) "REG_WRITE"(%1$s##reg##_CLR(n), BF_##reg##_##field(v))\n\ | ||
591 | #define BF_TOGVn(reg, n, field, v) "REG_WRITE"(%1$s##reg##_TOG(n), BF_##reg##_##field(v))\n\ | ||
592 | \n\ | ||
593 | #define BF_RDn(reg, n, field) BF_RDX(%1$s##reg(n), reg, field)\n\ | ||
594 | #define BF_WRn(reg, n, field, v) BF_WRX(%1$s##reg(n), reg, field, v)\n\ | ||
595 | #define BF_WRn_V(reg, n, field, sy) BF_WRn(reg, n, field, BV_##reg##_##field##__##sy)\n\ | ||
596 | \n", hwprefix); | ||
597 | |||
598 | for(int nargs = 1; nargs <= MAX_NARGS; nargs++) | ||
599 | { | ||
600 | fprintf(f, "#define BM_OR%d(reg, ", nargs); | ||
601 | gen_macro_list(f, "f", nargs, 2, ", ", 10, " "); | ||
602 | fprintf(f, ") \\\n ("); | ||
603 | gen_macro_list(f, "BM_##reg##_##f", nargs, 2, " | ", 4, " "); | ||
604 | fprintf(f, ")\n"); | ||
605 | } | ||
606 | fprintf(f, "\n"); | ||
607 | |||
608 | for(int nargs = 1; nargs <= MAX_NARGS; nargs++) | ||
609 | { | ||
610 | fprintf(f, "#define BF_OR%d(reg, ", nargs); | ||
611 | gen_macro_list(f, "f", nargs, 2, ", ", 10, " "); | ||
612 | fprintf(f, ") \\\n ("); | ||
613 | gen_macro_list(f, "BF_##reg##_##f", nargs, 2, " | ", 4, " "); | ||
614 | fprintf(f, ")\n"); | ||
615 | } | ||
616 | fprintf(f, "\n"); | ||
617 | |||
618 | if(variadic) | ||
619 | { | ||
620 | fprintf(f, "#define REG_NARG(...) REG_NARGS_(__VA_ARGS__"); | ||
621 | for(int i = MAX_NARGS; i >= 1; i--) | ||
622 | fprintf(f, ", %d", i); | ||
623 | fprintf(f, ")\n"); | ||
624 | fprintf(f, "#define REG_NARGS_("); | ||
625 | gen_macro_list(f, "_", MAX_NARGS, 1, ", "); | ||
626 | fprintf(f, ", N, ...) N\n\n"); | ||
627 | |||
628 | fprintf(f, "#define REG_VARIADIC(macro, reg, ...) REG_VARIADIC_(macro, REG_NARG(__VA_ARGS__), reg, __VA_ARGS__)\n"); | ||
629 | fprintf(f, "#define REG_VARIADIC_(macro, cnt, reg, ...) REG_VARIADIC__(macro, cnt, reg, __VA_ARGS__)\n"); | ||
630 | fprintf(f, "#define REG_VARIADIC__(macro, cnt, reg, ...) REG_VARIADIC___(macro##cnt, reg, __VA_ARGS__)\n"); | ||
631 | fprintf(f, "#define REG_VARIADIC___(macro, reg, ...) macro(reg, __VA_ARGS__)\n\n"); | ||
632 | |||
633 | fprintf(f, "#define BM_OR(reg, ...) REG_VARIADIC(BM_OR, reg, __VA_ARGS__)\n"); | ||
634 | fprintf(f, "#define BF_OR(reg, ...) REG_VARIADIC(BF_OR, reg, __VA_ARGS__)\n"); | ||
635 | } | ||
636 | |||
637 | fprint_include_guard_ex(f, false, guard); | ||
638 | fclose(f); | ||
639 | } | ||
640 | |||
641 | void usage() | ||
642 | { | ||
643 | printf("usage: headergen [options] <desc files...> <output directory>\n"); | ||
644 | printf("options:\n"); | ||
645 | printf(" -?/--help Dispaly this help\n"); | ||
646 | printf(" -s/--selector Always produce selector files\n"); | ||
647 | printf(" -m/--no-macro Do not generate a macro file with helpers\n"); | ||
648 | printf(" -i/--no-include Do not include the macro file in the headers\n"); | ||
649 | printf(" -v/--no-variadic Do not generate variadic macros\n"); | ||
650 | printf(" -p/--reg-prefix \"prefix\" Prefix register names\n"); | ||
651 | printf(" -a/--author \"Author\" Set author name in preamble\n"); | ||
652 | printf("\n"); | ||
653 | printf("Default option is to generate a macro file with variadic macros.\n"); | ||
654 | printf("Default option is to include the macro file in the headers.\n"); | ||
655 | printf("Default option is to generate selector files only for two or more socs.\n"); | ||
656 | printf("Default option is to create one subdirectory per soc, except if no\n"); | ||
657 | printf("selector files are needed. The subdirectories will be created if necessary.\n"); | ||
658 | printf("Default option is to not prefix register names\n"); | ||
659 | printf("Default option is \"Unknown Author\" for author in preamble\n"); | ||
660 | exit(1); | ||
661 | } | ||
662 | |||
663 | int main(int argc, char **argv) | ||
664 | { | ||
665 | bool force_selector = false; | ||
666 | bool no_variadic = false; | ||
667 | bool no_macro = false; | ||
668 | bool no_include = false; | ||
669 | char const *author = "Unknown Author"; | ||
670 | char const *hwprefix = ""; | ||
671 | |||
672 | if(argc <= 1) | ||
673 | usage(); | ||
674 | |||
675 | while(1) | ||
676 | { | ||
677 | static struct option long_options[] = | ||
678 | { | ||
679 | {"help", no_argument, 0, '?'}, | ||
680 | {"selector", no_argument, 0, 's'}, | ||
681 | {"no-macro", no_argument, 0, 'm'}, | ||
682 | {"no-include", no_argument, 0, 'i'}, | ||
683 | {"no-variadic", no_argument, 0, 'v'}, | ||
684 | {"reg-prefix", required_argument, 0, 'p'}, | ||
685 | {"author", required_argument, 0, 'a'}, | ||
686 | {0, 0, 0, 0} | ||
687 | }; | ||
688 | |||
689 | int c = getopt_long(argc, argv, "?smivp:a:", long_options, NULL); | ||
690 | if(c == -1) | ||
691 | break; | ||
692 | switch(c) | ||
693 | { | ||
694 | case -1: | ||
695 | break; | ||
696 | case '?': | ||
697 | usage(); | ||
698 | break; | ||
699 | case 's': | ||
700 | force_selector = true; | ||
701 | break; | ||
702 | case 'm': | ||
703 | no_macro = true; | ||
704 | break; | ||
705 | case 'i': | ||
706 | no_include = true; | ||
707 | break; | ||
708 | case 'v': | ||
709 | no_variadic = true; | ||
710 | break; | ||
711 | case 'a' : | ||
712 | author = optarg; | ||
713 | break; | ||
714 | case 'p' : | ||
715 | hwprefix = optarg; | ||
716 | break; | ||
717 | default: | ||
718 | abort(); | ||
719 | } | ||
720 | } | ||
721 | |||
722 | std::vector< soc_t > socs; | ||
723 | for(int i = optind; i < argc - 1; i++) | ||
724 | { | ||
725 | soc_t s; | ||
726 | if(!parse_xml(argv[i], s)) | ||
727 | { | ||
728 | printf("Cannot parse %s\n", argv[i]); | ||
729 | return 1; | ||
730 | } | ||
731 | socs.push_back(s); | ||
732 | } | ||
733 | |||
734 | g_gen_selector = force_selector || socs.size() > 1; | ||
735 | |||
736 | if(!no_macro) | ||
737 | { | ||
738 | g_macro_filename = std::string(argv[argc - 1]) + "/regs-macro.h"; | ||
739 | gen_macro(g_macro_filename, !no_variadic, author, hwprefix); | ||
740 | g_macro_filename = "regs-macro.h"; | ||
741 | if(no_include) | ||
742 | g_macro_filename.clear(); | ||
743 | } | ||
744 | if(g_gen_selector) | ||
745 | { | ||
746 | gen_selectors(argv[argc - 1], socs, author); | ||
747 | g_macro_filename.clear(); | ||
748 | } | ||
749 | gen_headers(argv[argc - 1], socs, author, hwprefix); | ||
750 | return 0; | ||
751 | } | ||