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