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/swiss_knife.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/swiss_knife.cpp')
-rw-r--r-- | utils/regtools/swiss_knife.cpp | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/utils/regtools/swiss_knife.cpp b/utils/regtools/swiss_knife.cpp new file mode 100644 index 0000000000..eaa2519a27 --- /dev/null +++ b/utils/regtools/swiss_knife.cpp | |||
@@ -0,0 +1,612 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2014 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 "soc_desc_v1.hpp" | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <map> | ||
26 | #include <set> | ||
27 | #include <cstring> | ||
28 | |||
29 | using namespace soc_desc; | ||
30 | |||
31 | void print_context(const error_context_t& ctx) | ||
32 | { | ||
33 | for(size_t j = 0; j < ctx.count(); j++) | ||
34 | { | ||
35 | error_t e = ctx.get(j); | ||
36 | switch(e.level()) | ||
37 | { | ||
38 | case error_t::INFO: printf("[INFO]"); break; | ||
39 | case error_t::WARNING: printf("[WARN]"); break; | ||
40 | case error_t::FATAL: printf("[FATAL]"); break; | ||
41 | default: printf("[UNK]"); break; | ||
42 | } | ||
43 | if(e.location().size() != 0) | ||
44 | printf(" %s:", e.location().c_str()); | ||
45 | printf(" %s\n", e.message().c_str()); | ||
46 | } | ||
47 | } | ||
48 | |||
49 | bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_value_t& in, enum_t& out, error_context_t& ctx) | ||
50 | { | ||
51 | out.name = in.name; | ||
52 | out.desc = in.desc; | ||
53 | out.value = in.value; | ||
54 | return true; | ||
55 | } | ||
56 | |||
57 | bool convert_v1_to_v2(const soc_desc_v1::soc_reg_field_t& in, field_t& out, error_context_t& ctx) | ||
58 | { | ||
59 | out.name = in.name; | ||
60 | out.desc = in.desc; | ||
61 | out.pos = in.first_bit; | ||
62 | out.width = in.last_bit - in.first_bit + 1; | ||
63 | out.enum_.resize(in.value.size()); | ||
64 | for(size_t i = 0; i < in.value.size(); i++) | ||
65 | if(!convert_v1_to_v2(in.value[i], out.enum_[i], ctx)) | ||
66 | return false; | ||
67 | return true; | ||
68 | } | ||
69 | |||
70 | bool convert_v1_to_v2(const soc_desc_v1::soc_reg_addr_t& in, instance_t& out, error_context_t& ctx) | ||
71 | { | ||
72 | out.name = in.name; | ||
73 | out.type = instance_t::SINGLE; | ||
74 | out.addr = in.addr; | ||
75 | return true; | ||
76 | } | ||
77 | |||
78 | bool convert_v1_to_v2(const soc_desc_v1::soc_reg_formula_t& in, range_t& out, error_context_t& ctx) | ||
79 | { | ||
80 | out.type = range_t::FORMULA; | ||
81 | out.formula = in.string; | ||
82 | out.variable = "n"; | ||
83 | return true; | ||
84 | } | ||
85 | |||
86 | bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_context_t& ctx, | ||
87 | std::string _loc) | ||
88 | { | ||
89 | std::string loc = _loc + "." + in.name; | ||
90 | out.name = in.name; | ||
91 | out.desc = in.desc; | ||
92 | if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE) | ||
93 | { | ||
94 | out.instance.resize(in.addr.size()); | ||
95 | for(size_t i = 0; i < in.addr.size(); i++) | ||
96 | if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx)) | ||
97 | return false; | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | out.instance.resize(1); | ||
102 | out.instance[0].name = in.name; | ||
103 | out.instance[0].type = instance_t::RANGE; | ||
104 | out.instance[0].range.first = 0; | ||
105 | out.instance[0].range.count = in.addr.size(); | ||
106 | /* check if formula is base/stride */ | ||
107 | bool is_stride = true; | ||
108 | soc_word_t base = 0, stride = 0; | ||
109 | if(in.addr.size() <= 1) | ||
110 | { | ||
111 | ctx.add(error_t(error_t::WARNING, loc, | ||
112 | "register uses a formula but has only one instance")); | ||
113 | is_stride = false; | ||
114 | } | ||
115 | else | ||
116 | { | ||
117 | base = in.addr[0].addr; | ||
118 | stride = in.addr[1].addr - base; | ||
119 | for(size_t i = 0; i < in.addr.size(); i++) | ||
120 | if(base + i * stride != in.addr[i].addr) | ||
121 | is_stride = false; | ||
122 | } | ||
123 | |||
124 | if(is_stride) | ||
125 | { | ||
126 | ctx.add(error_t(error_t::INFO, loc, "promoted formula to base/stride")); | ||
127 | out.instance[0].range.type = range_t::STRIDE; | ||
128 | out.instance[0].range.base = base; | ||
129 | out.instance[0].range.stride = stride; | ||
130 | } | ||
131 | else if(!convert_v1_to_v2(in.formula, out.instance[0].range, ctx)) | ||
132 | return false; | ||
133 | } | ||
134 | out.register_.resize(1); | ||
135 | out.register_[0].width = 32; | ||
136 | out.register_[0].field.resize(in.field.size()); | ||
137 | for(size_t i = 0; i < in.field.size(); i++) | ||
138 | if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx)) | ||
139 | return false; | ||
140 | /* sct */ | ||
141 | if(in.flags & soc_desc_v1::REG_HAS_SCT) | ||
142 | { | ||
143 | out.node.resize(1); | ||
144 | out.node[0].name = "SCT"; | ||
145 | out.node[0].instance.resize(3); | ||
146 | const char *names[3] = {"SET", "CLR", "TOG"}; | ||
147 | for(size_t i = 0; i < 3; i++) | ||
148 | { | ||
149 | out.node[0].instance[i].name = names[i]; | ||
150 | out.node[0].instance[i].type = instance_t::SINGLE; | ||
151 | out.node[0].instance[i].addr = 4 + i *4; | ||
152 | } | ||
153 | } | ||
154 | return true; | ||
155 | } | ||
156 | |||
157 | bool convert_v1_to_v2(const soc_desc_v1::soc_dev_addr_t& in, instance_t& out, error_context_t& ctx) | ||
158 | { | ||
159 | out.name = in.name; | ||
160 | out.type = instance_t::SINGLE; | ||
161 | out.addr = in.addr; | ||
162 | return true; | ||
163 | } | ||
164 | |||
165 | bool convert_v1_to_v2(const soc_desc_v1::soc_dev_t& in, node_t& out, error_context_t& ctx, | ||
166 | std::string _loc) | ||
167 | { | ||
168 | std::string loc = _loc + "." + in.name; | ||
169 | if(!in.version.empty()) | ||
170 | ctx.add(error_t(error_t::INFO, loc, "dropped version")); | ||
171 | out.name = in.name; | ||
172 | out.title = in.long_name; | ||
173 | out.desc = in.desc; | ||
174 | out.instance.resize(in.addr.size()); | ||
175 | for(size_t i = 0; i < in.addr.size(); i++) | ||
176 | if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx)) | ||
177 | return false; | ||
178 | out.node.resize(in.reg.size()); | ||
179 | for(size_t i = 0; i < in.reg.size(); i++) | ||
180 | if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc)) | ||
181 | return false; | ||
182 | return true; | ||
183 | } | ||
184 | |||
185 | bool convert_v1_to_v2(const soc_desc_v1::soc_t& in, soc_t& out, error_context_t& ctx) | ||
186 | { | ||
187 | out.name = in.name; | ||
188 | out.title = in.desc; | ||
189 | out.node.resize(in.dev.size()); | ||
190 | for(size_t i = 0; i < in.dev.size(); i++) | ||
191 | if(!convert_v1_to_v2(in.dev[i], out.node[i], ctx, in.name)) | ||
192 | return false; | ||
193 | return true; | ||
194 | } | ||
195 | |||
196 | int do_convert(int argc, char **argv) | ||
197 | { | ||
198 | if(argc != 2) | ||
199 | return printf("convert mode expects two arguments\n"); | ||
200 | soc_desc_v1::soc_t soc; | ||
201 | if(!soc_desc_v1::parse_xml(argv[0], soc)) | ||
202 | return printf("cannot read file '%s'\n", argv[0]); | ||
203 | error_context_t ctx; | ||
204 | soc_t new_soc; | ||
205 | if(!convert_v1_to_v2(soc, new_soc, ctx)) | ||
206 | { | ||
207 | print_context(ctx); | ||
208 | return printf("cannot convert from v1 to v2\n"); | ||
209 | } | ||
210 | if(!produce_xml(argv[1], new_soc, ctx)) | ||
211 | { | ||
212 | print_context(ctx); | ||
213 | return printf("cannot write file '%s'\n", argv[1]); | ||
214 | } | ||
215 | print_context(ctx); | ||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | int do_read(int argc, char **argv) | ||
220 | { | ||
221 | for(int i = 0; i < argc; i++) | ||
222 | { | ||
223 | error_context_t ctx; | ||
224 | soc_t soc; | ||
225 | bool ret = parse_xml(argv[i], soc, ctx); | ||
226 | if(ctx.count() != 0) | ||
227 | printf("In file %s:\n", argv[i]); | ||
228 | print_context(ctx); | ||
229 | if(!ret) | ||
230 | { | ||
231 | printf("cannot parse file '%s'\n", argv[i]); | ||
232 | continue; | ||
233 | } | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | int do_eval(int argc, char **argv) | ||
239 | { | ||
240 | std::map< std::string, soc_word_t > map; | ||
241 | for(int i = 0; i < argc; i++) | ||
242 | { | ||
243 | std::string formula(argv[i]); | ||
244 | soc_word_t result; | ||
245 | if(strcmp(argv[i], "--var") == 0) | ||
246 | { | ||
247 | if(i + 1 >= argc) | ||
248 | break; | ||
249 | i++; | ||
250 | std::string str(argv[i]); | ||
251 | size_t pos = str.find('='); | ||
252 | if(pos == std::string::npos) | ||
253 | { | ||
254 | printf("invalid variable string '%s'\n", str.c_str()); | ||
255 | continue; | ||
256 | } | ||
257 | std::string name = str.substr(0, pos); | ||
258 | std::string val = str.substr(pos + 1); | ||
259 | char *end; | ||
260 | soc_word_t v = strtoul(val.c_str(), &end, 0); | ||
261 | if(*end) | ||
262 | { | ||
263 | printf("invalid variable string '%s'\n", str.c_str()); | ||
264 | continue; | ||
265 | } | ||
266 | printf("%s = %#lx\n", name.c_str(), (unsigned long)v); | ||
267 | map[name] = v; | ||
268 | continue; | ||
269 | } | ||
270 | error_context_t ctx; | ||
271 | if(!evaluate_formula(formula, map, result, "", ctx)) | ||
272 | { | ||
273 | print_context(ctx); | ||
274 | printf("cannot parse '%s'\n", formula.c_str()); | ||
275 | } | ||
276 | else | ||
277 | printf("result: %lu (%#lx)\n", (unsigned long)result, (unsigned long)result); | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | int do_write(int argc, char **argv) | ||
283 | { | ||
284 | if(argc != 2) | ||
285 | return printf("write mode expects two arguments\n"); | ||
286 | soc_t soc; | ||
287 | error_context_t ctx; | ||
288 | if(!parse_xml(argv[0], soc, ctx)) | ||
289 | { | ||
290 | print_context(ctx); | ||
291 | return printf("cannot read file '%s'\n", argv[0]); | ||
292 | } | ||
293 | if(!produce_xml(argv[1], soc, ctx)) | ||
294 | { | ||
295 | print_context(ctx); | ||
296 | return printf("cannot write file '%s'\n", argv[1]); | ||
297 | } | ||
298 | print_context(ctx); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | void check_name(const std::string& path, const std::string& name, error_context_t& ctx) | ||
303 | { | ||
304 | if(name.empty()) | ||
305 | ctx.add(error_t(error_t::FATAL, path, "name is empty")); | ||
306 | for(size_t i = 0; i < name.size(); i++) | ||
307 | if(!isalnum(name[i]) && name[i] != '_') | ||
308 | ctx.add(error_t(error_t::FATAL, path, "name '" + name + | ||
309 | "' must only contain alphanumeric characters or '_'")); | ||
310 | } | ||
311 | |||
312 | void check_instance(const std::string& _path, const instance_t& inst, error_context_t& ctx) | ||
313 | { | ||
314 | std::string path = _path + "." + inst.name; | ||
315 | check_name(path, inst.name, ctx); | ||
316 | if(inst.type == instance_t::RANGE) | ||
317 | { | ||
318 | if(inst.range.type == range_t::FORMULA) | ||
319 | { | ||
320 | check_name(path + ".<formula variable>", inst.range.variable, ctx); | ||
321 | /* try to parse formula */ | ||
322 | std::map< std::string, soc_word_t> var; | ||
323 | var[inst.range.variable] = inst.range.first; | ||
324 | soc_word_t res; | ||
325 | if(!evaluate_formula(inst.range.formula, var, res, path + ".<formula>", ctx)) | ||
326 | ctx.add(error_t(error_t::FATAL, path + ".<formula>", | ||
327 | "cannot evaluate formula")); | ||
328 | } | ||
329 | } | ||
330 | } | ||
331 | |||
332 | void check_field(const std::string& _path, const field_t& field, error_context_t& ctx) | ||
333 | { | ||
334 | std::string path = _path + "." + field.name; | ||
335 | check_name(path, field.name, ctx); | ||
336 | if(field.width == 0) | ||
337 | ctx.add(error_t(error_t::WARNING, path, "field has width 0")); | ||
338 | soc_word_t max = field.bitmask() >> field.pos; | ||
339 | std::set< std::string > names; | ||
340 | std::map< soc_word_t, std::string > map; | ||
341 | for(size_t i = 0; i < field.enum_.size(); i++) | ||
342 | { | ||
343 | soc_word_t v = field.enum_[i].value; | ||
344 | std::string n = field.enum_[i].name; | ||
345 | std::string path_ = path + "." + n; | ||
346 | check_name(path_, n, ctx); | ||
347 | if(v > max) | ||
348 | ctx.add(error_t(error_t::FATAL, path_, "value does not fit into the field")); | ||
349 | if(names.find(n) != names.end()) | ||
350 | ctx.add(error_t(error_t::FATAL, path, "duplicate name '" + n + "' in enums")); | ||
351 | names.insert(n); | ||
352 | if(map.find(v) != map.end()) | ||
353 | ctx.add(error_t(error_t::WARNING, path, "'" + n + "' and '" + map[v] + "' have the same value")); | ||
354 | map[v] = n; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | void check_register(const std::string& _path, const soc_desc::register_t& reg, error_context_t& ctx) | ||
359 | { | ||
360 | std::string path = _path + ".<register>"; | ||
361 | if(reg.width != 8 && reg.width != 16 && reg.width != 32) | ||
362 | ctx.add(error_t(error_t::WARNING, path, "width is not 8, 16 or 32")); | ||
363 | for(size_t i = 0; i < reg.field.size(); i++) | ||
364 | check_field(path, reg.field[i], ctx); | ||
365 | std::set< std::string > names; | ||
366 | soc_word_t bitmap = 0; | ||
367 | for(size_t i = 0; i < reg.field.size(); i++) | ||
368 | { | ||
369 | std::string n = reg.field[i].name; | ||
370 | if(names.find(n) != names.end()) | ||
371 | ctx.add(error_t(error_t::FATAL, path, "duplicate name '" + n + "' in fields")); | ||
372 | if(reg.field[i].pos + reg.field[i].width > reg.width) | ||
373 | ctx.add(error_t(error_t::FATAL, path, "field '" + n + "' does not fit into the register")); | ||
374 | names.insert(n); | ||
375 | if(bitmap & reg.field[i].bitmask()) | ||
376 | { | ||
377 | /* find the duplicate to ease debugging */ | ||
378 | for(size_t j = 0; j < i; j++) | ||
379 | if(reg.field[j].bitmask() & reg.field[i].bitmask()) | ||
380 | ctx.add(error_t(error_t::FATAL, path, "overlap between fields '" + | ||
381 | reg.field[j].name + "' and '" + n + "'")); | ||
382 | } | ||
383 | bitmap |= reg.field[i].bitmask(); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | void check_nodes(const std::string& path, const std::vector< node_t >& nodes, | ||
388 | error_context_t& ctx); | ||
389 | |||
390 | void check_node(const std::string& _path, const node_t& node, error_context_t& ctx) | ||
391 | { | ||
392 | std::string path = _path + "." + node.name; | ||
393 | check_name(_path, node.name, ctx); | ||
394 | if(node.instance.empty()) | ||
395 | ctx.add(error_t(error_t::FATAL, path, "subnode with no instances")); | ||
396 | for(size_t j = 0; j < node.instance.size(); j++) | ||
397 | check_instance(path, node.instance[j], ctx); | ||
398 | for(size_t i = 0; i < node.register_.size(); i++) | ||
399 | check_register(path, node.register_[i], ctx); | ||
400 | check_nodes(path, node.node, ctx); | ||
401 | } | ||
402 | |||
403 | void check_nodes(const std::string& path, const std::vector< node_t >& nodes, | ||
404 | error_context_t& ctx) | ||
405 | { | ||
406 | for(size_t i = 0; i < nodes.size(); i++) | ||
407 | check_node(path, nodes[i], ctx); | ||
408 | /* gather all instance names */ | ||
409 | std::set< std::string > names; | ||
410 | for(size_t i = 0; i < nodes.size(); i++) | ||
411 | for(size_t j = 0; j < nodes[i].instance.size(); j++) | ||
412 | { | ||
413 | std::string n = nodes[i].instance[j].name; | ||
414 | if(names.find(n) != names.end()) | ||
415 | ctx.add(error_t(error_t::FATAL, path, "duplicate instance name '" + | ||
416 | n + "' in subnodes")); | ||
417 | names.insert(n); | ||
418 | } | ||
419 | /* gather all node names */ | ||
420 | names.clear(); | ||
421 | for(size_t i = 0; i < nodes.size(); i++) | ||
422 | { | ||
423 | std::string n = nodes[i].name; | ||
424 | if(names.find(n) != names.end()) | ||
425 | ctx.add(error_t(error_t::FATAL, path, "duplicate node name '" + n + | ||
426 | "' in subnodes")); | ||
427 | names.insert(n); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | void do_check(soc_t& soc, error_context_t& ctx) | ||
432 | { | ||
433 | check_name(soc.name, soc.name, ctx); | ||
434 | check_nodes(soc.name, soc.node, ctx); | ||
435 | } | ||
436 | |||
437 | int do_check(int argc, char **argv) | ||
438 | { | ||
439 | for(int i = 0; i < argc; i++) | ||
440 | { | ||
441 | error_context_t ctx; | ||
442 | soc_t soc; | ||
443 | bool ret = parse_xml(argv[i], soc, ctx); | ||
444 | if(ret) | ||
445 | do_check(soc, ctx); | ||
446 | if(ctx.count() != 0) | ||
447 | printf("In file %s:\n", argv[i]); | ||
448 | print_context(ctx); | ||
449 | if(!ret) | ||
450 | { | ||
451 | printf("cannot parse file '%s'\n", argv[i]); | ||
452 | continue; | ||
453 | } | ||
454 | } | ||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | const unsigned DUMP_NODES = 1 << 0; | ||
459 | const unsigned DUMP_INSTANCES = 1 << 1; | ||
460 | const unsigned DUMP_VERBOSE = 1 << 2; | ||
461 | const unsigned DUMP_REGISTERS = 1 << 3; | ||
462 | |||
463 | void print_path(node_ref_t node, bool nl = true) | ||
464 | { | ||
465 | printf("%s", node.soc().get()->name.c_str()); | ||
466 | std::vector< std::string > path = node.path(); | ||
467 | for(size_t i = 0; i < path.size(); i++) | ||
468 | printf(".%s", path[i].c_str()); | ||
469 | if(nl) | ||
470 | printf("\n"); | ||
471 | } | ||
472 | |||
473 | void print_inst(node_inst_t inst, bool end = true) | ||
474 | { | ||
475 | if(!inst.is_root()) | ||
476 | { | ||
477 | print_inst(inst.parent(), false); | ||
478 | printf(".%s", inst.name().c_str()); | ||
479 | if(inst.is_indexed()) | ||
480 | printf("[%u]", (unsigned)inst.index()); | ||
481 | } | ||
482 | else | ||
483 | { | ||
484 | printf("%s", inst.soc().get()->name.c_str()); | ||
485 | } | ||
486 | if(end) | ||
487 | printf(" @ %#x\n", inst.addr()); | ||
488 | } | ||
489 | |||
490 | void print_reg(register_ref_t reg, unsigned flags) | ||
491 | { | ||
492 | if(!(flags & DUMP_REGISTERS)) | ||
493 | return; | ||
494 | node_ref_t node = reg.node(); | ||
495 | soc_desc::register_t *r = reg.get(); | ||
496 | print_path(node, false); | ||
497 | printf(":width=%u\n", (unsigned)r->width); | ||
498 | std::vector< field_ref_t > fields = reg.fields(); | ||
499 | for(size_t i = 0; i < fields.size(); i++) | ||
500 | { | ||
501 | field_t *f = fields[i].get(); | ||
502 | print_path(node, false); | ||
503 | if(f->width == 1) | ||
504 | printf(":[%u]=", (unsigned)f->pos); | ||
505 | else | ||
506 | printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos); | ||
507 | printf("%s\n", f->name.c_str()); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | void do_dump(node_ref_t node, unsigned flags) | ||
512 | { | ||
513 | print_path(node); | ||
514 | if(node.reg().node() == node) | ||
515 | print_reg(node.reg(), flags); | ||
516 | std::vector< node_ref_t > children = node.children(); | ||
517 | for(size_t i = 0; i < children.size(); i++) | ||
518 | do_dump(children[i], flags); | ||
519 | } | ||
520 | |||
521 | void do_dump(node_inst_t inst, unsigned flags) | ||
522 | { | ||
523 | print_inst(inst); | ||
524 | std::vector< node_inst_t > children = inst.children(); | ||
525 | for(size_t i = 0; i < children.size(); i++) | ||
526 | do_dump(children[i], flags); | ||
527 | } | ||
528 | |||
529 | void do_dump(soc_t& soc, unsigned flags) | ||
530 | { | ||
531 | soc_ref_t ref(&soc); | ||
532 | if(flags & DUMP_NODES) | ||
533 | do_dump(ref.root(), flags); | ||
534 | if(flags & DUMP_INSTANCES) | ||
535 | do_dump(ref.root_inst(), flags); | ||
536 | } | ||
537 | |||
538 | int do_dump(int argc, char **argv) | ||
539 | { | ||
540 | unsigned flags = 0; | ||
541 | int i = 0; | ||
542 | for(; i < argc; i++) | ||
543 | { | ||
544 | if(strcmp(argv[i], "--nodes") == 0) | ||
545 | flags |= DUMP_NODES; | ||
546 | else if(strcmp(argv[i], "--instances") == 0) | ||
547 | flags |= DUMP_INSTANCES; | ||
548 | else if(strcmp(argv[i], "--verbose") == 0) | ||
549 | flags |= DUMP_VERBOSE; | ||
550 | else if(strcmp(argv[i], "--registers") == 0) | ||
551 | flags |= DUMP_REGISTERS; | ||
552 | else | ||
553 | break; | ||
554 | } | ||
555 | if(i == argc) | ||
556 | { | ||
557 | printf("you must specify at least one file\n"); | ||
558 | return 1; | ||
559 | } | ||
560 | for(; i < argc; i++) | ||
561 | { | ||
562 | error_context_t ctx; | ||
563 | soc_t soc; | ||
564 | bool ret = parse_xml(argv[i], soc, ctx); | ||
565 | if(ret) | ||
566 | do_dump(soc, flags); | ||
567 | if(ctx.count() != 0) | ||
568 | printf("In file %s:\n", argv[i]); | ||
569 | print_context(ctx); | ||
570 | if(!ret) | ||
571 | { | ||
572 | printf("cannot parse file '%s'\n", argv[i]); | ||
573 | continue; | ||
574 | } | ||
575 | } | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | void usage() | ||
580 | { | ||
581 | printf("usage: swiss_knife <mode> [options]\n"); | ||
582 | printf("modes:\n"); | ||
583 | printf(" read <files...>\n"); | ||
584 | printf(" write <read file> <write file>\n"); | ||
585 | printf(" eval [<formula>|--var <name>=<val>]...\n"); | ||
586 | printf(" convert <input file> <output file>\n"); | ||
587 | printf(" check <files...>\n"); | ||
588 | printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n"); | ||
589 | exit(1); | ||
590 | } | ||
591 | |||
592 | int main(int argc, char **argv) | ||
593 | { | ||
594 | if(argc < 2) | ||
595 | usage(); | ||
596 | std::string mode = argv[1]; | ||
597 | if(mode == "read") | ||
598 | return do_read(argc - 2, argv + 2); | ||
599 | else if(mode == "write") | ||
600 | return do_write(argc - 2, argv + 2); | ||
601 | else if(mode == "eval") | ||
602 | return do_eval(argc - 2, argv + 2); | ||
603 | else if(mode == "convert") | ||
604 | return do_convert(argc - 2, argv + 2); | ||
605 | else if(mode == "check") | ||
606 | return do_check(argc - 2, argv + 2); | ||
607 | else if(mode == "dump") | ||
608 | return do_dump(argc - 2, argv + 2); | ||
609 | else | ||
610 | usage(); | ||
611 | return 0; | ||
612 | } \ No newline at end of file | ||