Added "dump" command (part ilang backend)
[yosys.git] / backends / ilang / ilang_backend.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 * ---
19 *
20 * A very simple and straightforward backend for the RTLIL text
21 * representation (as understood by the 'ilang' frontend).
22 *
23 */
24
25 #include "ilang_backend.h"
26 #include "kernel/register.h"
27 #include "kernel/log.h"
28 #include <string>
29 #include <assert.h>
30 #include <string.h>
31 #include <errno.h>
32
33 using namespace ILANG_BACKEND;
34
35 void ILANG_BACKEND::dump_const(FILE *f, const RTLIL::Const &data, int width, int offset, bool autoint)
36 {
37 if (width < 0)
38 width = data.bits.size() - offset;
39 if (data.str.empty() || width != (int)data.bits.size()) {
40 if (width == 32 && autoint) {
41 int32_t val = 0;
42 for (int i = 0; i < width; i++) {
43 assert(offset+i < (int)data.bits.size());
44 switch (data.bits[offset+i]) {
45 case RTLIL::S0: break;
46 case RTLIL::S1: val |= 1 << i; break;
47 default: val = -1; break;
48 }
49 }
50 if (val >= 0) {
51 fprintf(f, "%d", val);
52 return;
53 }
54 }
55 fprintf(f, "%d'", width);
56 for (int i = offset+width-1; i >= offset; i--) {
57 assert(i < (int)data.bits.size());
58 switch (data.bits[i]) {
59 case RTLIL::S0: fprintf(f, "0"); break;
60 case RTLIL::S1: fprintf(f, "1"); break;
61 case RTLIL::Sx: fprintf(f, "x"); break;
62 case RTLIL::Sz: fprintf(f, "z"); break;
63 case RTLIL::Sa: fprintf(f, "-"); break;
64 case RTLIL::Sm: fprintf(f, "m"); break;
65 }
66 }
67 } else {
68 fprintf(f, "\"");
69 for (size_t i = 0; i < data.str.size(); i++) {
70 if (data.str[i] == '\n')
71 fprintf(f, "\\n");
72 else if (data.str[i] == '\t')
73 fprintf(f, "\\t");
74 else if (data.str[i] < 32)
75 fprintf(f, "\\%03o", data.str[i]);
76 else if (data.str[i] == '"')
77 fprintf(f, "\\\"");
78 else
79 fputc(data.str[i], f);
80 }
81 fprintf(f, "\"");
82 }
83 }
84
85 void ILANG_BACKEND::dump_sigchunk(FILE *f, const RTLIL::SigChunk &chunk, bool autoint)
86 {
87 if (chunk.wire == NULL) {
88 dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
89 } else {
90 if (chunk.width == chunk.wire->width && chunk.offset == 0)
91 fprintf(f, "%s", chunk.wire->name.c_str());
92 else if (chunk.width == 1)
93 fprintf(f, "%s [%d]", chunk.wire->name.c_str(), chunk.offset);
94 else
95 fprintf(f, "%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
96 }
97 }
98
99 void ILANG_BACKEND::dump_sigspec(FILE *f, const RTLIL::SigSpec &sig, bool autoint)
100 {
101 if (sig.chunks.size() == 1) {
102 dump_sigchunk(f, sig.chunks[0], autoint);
103 } else {
104 fprintf(f, "{ ");
105 for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
106 dump_sigchunk(f, *it, false);
107 fprintf(f, " ");
108 }
109 fprintf(f, "}");
110 }
111 }
112
113 void ILANG_BACKEND::dump_wire(FILE *f, std::string indent, const RTLIL::Wire *wire)
114 {
115 for (auto it = wire->attributes.begin(); it != wire->attributes.end(); it++) {
116 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
117 dump_const(f, it->second);
118 fprintf(f, "\n");
119 }
120 fprintf(f, "%s" "wire ", indent.c_str());
121 if (wire->auto_width)
122 fprintf(f, "auto ");
123 if (wire->width != 1)
124 fprintf(f, "width %d ", wire->width);
125 if (wire->start_offset != 0)
126 fprintf(f, "offset %d ", wire->start_offset);
127 if (wire->port_input && !wire->port_output)
128 fprintf(f, "input %d ", wire->port_id);
129 if (!wire->port_input && wire->port_output)
130 fprintf(f, "output %d ", wire->port_id);
131 if (wire->port_input && wire->port_output)
132 fprintf(f, "inout %d ", wire->port_id);
133 fprintf(f, "%s\n", wire->name.c_str());
134 }
135
136 void ILANG_BACKEND::dump_memory(FILE *f, std::string indent, const RTLIL::Memory *memory)
137 {
138 for (auto it = memory->attributes.begin(); it != memory->attributes.end(); it++) {
139 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
140 dump_const(f, it->second);
141 fprintf(f, "\n");
142 }
143 fprintf(f, "%s" "memory ", indent.c_str());
144 if (memory->width != 1)
145 fprintf(f, "width %d ", memory->width);
146 if (memory->size != 0)
147 fprintf(f, "size %d ", memory->size);
148 fprintf(f, "%s\n", memory->name.c_str());
149 }
150
151 void ILANG_BACKEND::dump_cell(FILE *f, std::string indent, const RTLIL::Cell *cell)
152 {
153 for (auto it = cell->attributes.begin(); it != cell->attributes.end(); it++) {
154 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
155 dump_const(f, it->second);
156 fprintf(f, "\n");
157 }
158 fprintf(f, "%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
159 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
160 fprintf(f, "%s parameter %s ", indent.c_str(), it->first.c_str());
161 dump_const(f, it->second);
162 fprintf(f, "\n");
163 }
164 for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
165 fprintf(f, "%s connect %s ", indent.c_str(), it->first.c_str());
166 dump_sigspec(f, it->second);
167 fprintf(f, "\n");
168 }
169 fprintf(f, "%s" "end\n", indent.c_str());
170 }
171
172 void ILANG_BACKEND::dump_proc_case_body(FILE *f, std::string indent, const RTLIL::CaseRule *cs)
173 {
174 for (auto it = cs->actions.begin(); it != cs->actions.end(); it++)
175 {
176 fprintf(f, "%s" "assign ", indent.c_str());
177 dump_sigspec(f, it->first);
178 fprintf(f, " ");
179 dump_sigspec(f, it->second);
180 fprintf(f, "\n");
181 }
182
183 for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
184 dump_proc_switch(f, indent, *it);
185 }
186
187 void ILANG_BACKEND::dump_proc_switch(FILE *f, std::string indent, const RTLIL::SwitchRule *sw)
188 {
189 for (auto it = sw->attributes.begin(); it != sw->attributes.end(); it++) {
190 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
191 dump_const(f, it->second);
192 fprintf(f, "\n");
193 }
194
195 fprintf(f, "%s" "switch ", indent.c_str());
196 dump_sigspec(f, sw->signal);
197 fprintf(f, "\n");
198
199 for (auto it = sw->cases.begin(); it != sw->cases.end(); it++)
200 {
201 fprintf(f, "%s case ", indent.c_str());
202 for (size_t i = 0; i < (*it)->compare.size(); i++) {
203 if (i > 0)
204 fprintf(f, ", ");
205 dump_sigspec(f, (*it)->compare[i]);
206 }
207 fprintf(f, "\n");
208
209 dump_proc_case_body(f, indent + " ", *it);
210 }
211
212 fprintf(f, "%s" "end\n", indent.c_str());
213 }
214
215 void ILANG_BACKEND::dump_proc_sync(FILE *f, std::string indent, const RTLIL::SyncRule *sy)
216 {
217 fprintf(f, "%s" "sync ", indent.c_str());
218 switch (sy->type) {
219 if (0) case RTLIL::ST0: fprintf(f, "low ");
220 if (0) case RTLIL::ST1: fprintf(f, "high ");
221 if (0) case RTLIL::STp: fprintf(f, "posedge ");
222 if (0) case RTLIL::STn: fprintf(f, "negedge ");
223 if (0) case RTLIL::STe: fprintf(f, "edge ");
224 dump_sigspec(f, sy->signal);
225 fprintf(f, "\n");
226 break;
227 case RTLIL::STa: fprintf(f, "always\n"); break;
228 }
229
230 for (auto it = sy->actions.begin(); it != sy->actions.end(); it++) {
231 fprintf(f, "%s update ", indent.c_str());
232 dump_sigspec(f, it->first);
233 fprintf(f, " ");
234 dump_sigspec(f, it->second);
235 fprintf(f, "\n");
236 }
237 }
238
239 void ILANG_BACKEND::dump_proc(FILE *f, std::string indent, const RTLIL::Process *proc)
240 {
241 for (auto it = proc->attributes.begin(); it != proc->attributes.end(); it++) {
242 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
243 dump_const(f, it->second);
244 fprintf(f, "\n");
245 }
246 fprintf(f, "%s" "process %s\n", indent.c_str(), proc->name.c_str());
247 dump_proc_case_body(f, indent + " ", &proc->root_case);
248 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
249 dump_proc_sync(f, indent + " ", *it);
250 fprintf(f, "%s" "end\n", indent.c_str());
251 }
252
253 void ILANG_BACKEND::dump_conn(FILE *f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
254 {
255 fprintf(f, "%s" "connect ", indent.c_str());
256 dump_sigspec(f, left);
257 fprintf(f, " ");
258 dump_sigspec(f, right);
259 fprintf(f, "\n");
260 }
261
262 void ILANG_BACKEND::dump_module(FILE *f, std::string indent, const RTLIL::Module *module, const RTLIL::Design *design, bool only_selected)
263 {
264 for (auto it = module->attributes.begin(); it != module->attributes.end(); it++) {
265 fprintf(f, "%s" "attribute %s ", indent.c_str(), it->first.c_str());
266 dump_const(f, it->second);
267 fprintf(f, "\n");
268 }
269
270 fprintf(f, "%s" "module %s\n", indent.c_str(), module->name.c_str());
271
272 for (auto it = module->wires.begin(); it != module->wires.end(); it++)
273 if (!only_selected || design->selected(module, it->second)) {
274 if (only_selected)
275 fprintf(f, "\n");
276 dump_wire(f, indent + " ", it->second);
277 }
278
279 for (auto it = module->memories.begin(); it != module->memories.end(); it++)
280 if (!only_selected || design->selected(module, it->second)) {
281 if (only_selected)
282 fprintf(f, "\n");
283 dump_memory(f, indent + " ", it->second);
284 }
285
286 for (auto it = module->cells.begin(); it != module->cells.end(); it++)
287 if (!only_selected || design->selected(module, it->second)) {
288 if (only_selected)
289 fprintf(f, "\n");
290 dump_cell(f, indent + " ", it->second);
291 }
292
293 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
294 if (!only_selected || design->selected(module, it->second)) {
295 if (only_selected)
296 fprintf(f, "\n");
297 dump_proc(f, indent + " ", it->second);
298 }
299
300 bool first_conn_line = true;
301 for (auto it = module->connections.begin(); it != module->connections.end(); it++) {
302 bool show_conn = !only_selected;
303 if (only_selected) {
304 RTLIL::SigSpec sigs = it->first;
305 sigs.append(it->second);
306 for (auto &c : sigs.chunks) {
307 if (c.wire == NULL || !design->selected(module, c.wire))
308 continue;
309 show_conn = true;
310 }
311 }
312 if (show_conn) {
313 if (only_selected && first_conn_line)
314 fprintf(f, "\n");
315 dump_conn(f, indent + " ", it->first, it->second);
316 first_conn_line = false;
317 }
318 }
319
320 fprintf(f, "%s" "end\n", indent.c_str());
321 }
322
323 void ILANG_BACKEND::dump_design(FILE *f, const RTLIL::Design *design, bool only_selected)
324 {
325 for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
326 if (it != design->modules.begin() || only_selected)
327 fprintf(f, "\n");
328 if (!only_selected || design->selected(it->second))
329 dump_module(f, "", it->second, design, only_selected);
330 }
331 }
332
333 struct IlangBackend : public Backend {
334 IlangBackend() : Backend("ilang", "write design to ilang file") { }
335 virtual void help()
336 {
337 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
338 log("\n");
339 log(" write_ilang [filename]\n");
340 log("\n");
341 log("Write the current design to an 'ilang' file. (ilang is a text representation\n");
342 log("of a design in yosys's internal format.)\n");
343 log("\n");
344 }
345 virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) {
346 log_header("Executing ILANG backend.\n");
347 extra_args(f, filename, args, 1);
348 log("Output filename: %s\n", filename.c_str());
349 ILANG_BACKEND::dump_design(f, design, false);
350 }
351 } IlangBackend;
352
353 struct DumpPass : public Pass {
354 DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
355 virtual void help()
356 {
357 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
358 log("\n");
359 log(" dump [options] [selection]\n");
360 log("\n");
361 log("Write the selected parts of the design to the console or specified file in\n");
362 log("ilang format.\n");
363 log("\n");
364 log(" -outfile <filename>\n");
365 log(" Write to the specified file.\n");
366 log("\n");
367 }
368 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
369 {
370 std::string filename;
371
372 size_t argidx;
373 for (argidx = 1; argidx < args.size(); argidx++)
374 {
375 std::string arg = args[argidx];
376 if (arg == "-outfile" && argidx+1 < args.size()) {
377 filename = args[++argidx];
378 continue;
379 }
380 break;
381 }
382 extra_args(args, argidx, design);
383
384 FILE *f = NULL;
385 char *buf_ptr;
386 size_t buf_size;
387
388 if (!filename.empty()) {
389 f = fopen(filename.c_str(), "w");
390 if (f == NULL)
391 log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
392 } else {
393 f = open_memstream(&buf_ptr, &buf_size);
394 }
395
396 ILANG_BACKEND::dump_design(f, design, true);
397
398 fclose(f);
399
400 if (filename.empty()) {
401 log("%s", buf_ptr);
402 free(buf_ptr);
403 }
404 }
405 } DumpPass;
406