2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 * A very simple and straightforward backend for the RTLIL text
21 * representation (as understood by the 'ilang' frontend).
25 #include "ilang_backend.h"
26 #include "kernel/register.h"
27 #include "kernel/log.h"
33 using namespace ILANG_BACKEND
;
35 void ILANG_BACKEND::dump_const(FILE *f
, const RTLIL::Const
&data
, int width
, int offset
, bool autoint
)
38 width
= data
.bits
.size() - offset
;
39 if (data
.str
.empty() || width
!= (int)data
.bits
.size()) {
40 if (width
== 32 && autoint
) {
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;
51 fprintf(f
, "%d", val
);
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;
69 for (size_t i
= 0; i
< data
.str
.size(); i
++) {
70 if (data
.str
[i
] == '\n')
72 else if (data
.str
[i
] == '\t')
74 else if (data
.str
[i
] < 32)
75 fprintf(f
, "\\%03o", data
.str
[i
]);
76 else if (data
.str
[i
] == '"')
79 fputc(data
.str
[i
], f
);
85 void ILANG_BACKEND::dump_sigchunk(FILE *f
, const RTLIL::SigChunk
&chunk
, bool autoint
)
87 if (chunk
.wire
== NULL
) {
88 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, autoint
);
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
);
95 fprintf(f
, "%s [%d:%d]", chunk
.wire
->name
.c_str(), chunk
.offset
+chunk
.width
-1, chunk
.offset
);
99 void ILANG_BACKEND::dump_sigspec(FILE *f
, const RTLIL::SigSpec
&sig
, bool autoint
)
101 if (sig
.chunks
.size() == 1) {
102 dump_sigchunk(f
, sig
.chunks
[0], autoint
);
105 for (auto it
= sig
.chunks
.rbegin(); it
!= sig
.chunks
.rend(); it
++) {
106 dump_sigchunk(f
, *it
, false);
113 void ILANG_BACKEND::dump_wire(FILE *f
, std::string indent
, const RTLIL::Wire
*wire
)
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
);
120 fprintf(f
, "%s" "wire ", indent
.c_str());
121 if (wire
->auto_width
)
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());
136 void ILANG_BACKEND::dump_memory(FILE *f
, std::string indent
, const RTLIL::Memory
*memory
)
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
);
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());
151 void ILANG_BACKEND::dump_cell(FILE *f
, std::string indent
, const RTLIL::Cell
*cell
)
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
);
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
);
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
);
169 fprintf(f
, "%s" "end\n", indent
.c_str());
172 void ILANG_BACKEND::dump_proc_case_body(FILE *f
, std::string indent
, const RTLIL::CaseRule
*cs
)
174 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); it
++)
176 fprintf(f
, "%s" "assign ", indent
.c_str());
177 dump_sigspec(f
, it
->first
);
179 dump_sigspec(f
, it
->second
);
183 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); it
++)
184 dump_proc_switch(f
, indent
, *it
);
187 void ILANG_BACKEND::dump_proc_switch(FILE *f
, std::string indent
, const RTLIL::SwitchRule
*sw
)
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
);
195 fprintf(f
, "%s" "switch ", indent
.c_str());
196 dump_sigspec(f
, sw
->signal
);
199 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); it
++)
201 fprintf(f
, "%s case ", indent
.c_str());
202 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
205 dump_sigspec(f
, (*it
)->compare
[i
]);
209 dump_proc_case_body(f
, indent
+ " ", *it
);
212 fprintf(f
, "%s" "end\n", indent
.c_str());
215 void ILANG_BACKEND::dump_proc_sync(FILE *f
, std::string indent
, const RTLIL::SyncRule
*sy
)
217 fprintf(f
, "%s" "sync ", indent
.c_str());
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
);
227 case RTLIL::STa
: fprintf(f
, "always\n"); break;
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
);
234 dump_sigspec(f
, it
->second
);
239 void ILANG_BACKEND::dump_proc(FILE *f
, std::string indent
, const RTLIL::Process
*proc
)
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
);
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());
253 void ILANG_BACKEND::dump_conn(FILE *f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
255 fprintf(f
, "%s" "connect ", indent
.c_str());
256 dump_sigspec(f
, left
);
258 dump_sigspec(f
, right
);
262 void ILANG_BACKEND::dump_module(FILE *f
, std::string indent
, const RTLIL::Module
*module
, const RTLIL::Design
*design
, bool only_selected
)
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
);
270 fprintf(f
, "%s" "module %s\n", indent
.c_str(), module
->name
.c_str());
272 for (auto it
= module
->wires
.begin(); it
!= module
->wires
.end(); it
++)
273 if (!only_selected
|| design
->selected(module
, it
->second
)) {
276 dump_wire(f
, indent
+ " ", it
->second
);
279 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); it
++)
280 if (!only_selected
|| design
->selected(module
, it
->second
)) {
283 dump_memory(f
, indent
+ " ", it
->second
);
286 for (auto it
= module
->cells
.begin(); it
!= module
->cells
.end(); it
++)
287 if (!only_selected
|| design
->selected(module
, it
->second
)) {
290 dump_cell(f
, indent
+ " ", it
->second
);
293 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); it
++)
294 if (!only_selected
|| design
->selected(module
, it
->second
)) {
297 dump_proc(f
, indent
+ " ", it
->second
);
300 bool first_conn_line
= true;
301 for (auto it
= module
->connections
.begin(); it
!= module
->connections
.end(); it
++) {
302 bool show_conn
= !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
))
313 if (only_selected
&& first_conn_line
)
315 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
316 first_conn_line
= false;
320 fprintf(f
, "%s" "end\n", indent
.c_str());
323 void ILANG_BACKEND::dump_design(FILE *f
, const RTLIL::Design
*design
, bool only_selected
)
325 for (auto it
= design
->modules
.begin(); it
!= design
->modules
.end(); it
++) {
326 if (it
!= design
->modules
.begin() || only_selected
)
328 if (!only_selected
|| design
->selected(it
->second
))
329 dump_module(f
, "", it
->second
, design
, only_selected
);
333 struct IlangBackend
: public Backend
{
334 IlangBackend() : Backend("ilang", "write design to ilang file") { }
337 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
339 log(" write_ilang [filename]\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");
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);
353 struct DumpPass
: public Pass
{
354 DumpPass() : Pass("dump", "print parts of the design in ilang format") { }
357 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
359 log(" dump [options] [selection]\n");
361 log("Write the selected parts of the design to the console or specified file in\n");
362 log("ilang format.\n");
364 log(" -outfile <filename>\n");
365 log(" Write to the specified file.\n");
368 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
370 std::string filename
;
373 for (argidx
= 1; argidx
< args
.size(); argidx
++)
375 std::string arg
= args
[argidx
];
376 if (arg
== "-outfile" && argidx
+1 < args
.size()) {
377 filename
= args
[++argidx
];
382 extra_args(args
, argidx
, design
);
388 if (!filename
.empty()) {
389 f
= fopen(filename
.c_str(), "w");
391 log_error("Can't open file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
393 f
= open_memstream(&buf_ptr
, &buf_size
);
396 ILANG_BACKEND::dump_design(f
, design
, true);
400 if (filename
.empty()) {