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 // [[CITE]] EDIF Version 2 0 0 Grammar
21 // http://web.archive.org/web/20050730021644/http://www.edif.org/documentation/BNF_GRAMMAR/index.html
23 #include "kernel/rtlil.h"
24 #include "kernel/register.h"
25 #include "kernel/sigtools.h"
26 #include "kernel/celltypes.h"
27 #include "kernel/log.h"
31 PRIVATE_NAMESPACE_BEGIN
33 #define EDIF_DEF(_id) edif_names(RTLIL::unescape_id(_id), true).c_str()
34 #define EDIF_DEFR(_id, _ren, _bl, _br) edif_names(RTLIL::unescape_id(_id), true, _ren, _bl, _br).c_str()
35 #define EDIF_REF(_id) edif_names(RTLIL::unescape_id(_id), false).c_str()
40 char delim_left
, delim_right
;
41 std::set
<std::string
> generated_names
, used_names
;
42 std::map
<std::string
, std::string
> name_map
;
44 EdifNames() : counter(1), delim_left('['), delim_right(']') { }
46 std::string
operator()(std::string id
, bool define
, bool port_rename
= false, int range_left
= 0, int range_right
= 0)
49 std::string new_id
= operator()(id
, false);
51 return stringf("(rename %s \"%s%c%d:%d%c\")", new_id
.c_str(), id
.c_str(), delim_left
, range_left
, range_right
, delim_right
);
52 return new_id
!= id
? stringf("(rename %s \"%s\")", new_id
.c_str(), id
.c_str()) : id
;
55 if (name_map
.count(id
) > 0)
56 return name_map
.at(id
);
57 if (generated_names
.count(id
) > 0)
59 if (id
== "GND" || id
== "VCC")
62 for (size_t i
= 0; i
< id
.size(); i
++) {
63 if ('A' <= id
[i
] && id
[i
] <= 'Z')
65 if ('a' <= id
[i
] && id
[i
] <= 'z')
67 if ('0' <= id
[i
] && id
[i
] <= '9' && i
> 0)
69 if (id
[i
] == '_' && i
> 0 && i
!= id
.size()-1)
74 used_names
.insert(id
);
80 gen_name
= stringf("id%05d", counter
++);
81 if (generated_names
.count(gen_name
) == 0 &&
82 used_names
.count(gen_name
) == 0)
85 generated_names
.insert(gen_name
);
86 name_map
[id
] = gen_name
;
91 struct EdifBackend
: public Backend
{
92 EdifBackend() : Backend("edif", "write design to EDIF netlist file") { }
93 void help() YS_OVERRIDE
95 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
97 log(" write_edif [options] [filename]\n");
99 log("Write the current design to an EDIF netlist file.\n");
101 log(" -top top_module\n");
102 log(" set the specified module as design top module\n");
105 log(" do not create \"GND\" and \"VCC\" cells. (this will produce an error\n");
106 log(" if the design contains constant nets. use \"hilomap\" to map to custom\n");
107 log(" constant drivers first)\n");
110 log(" create \"GND\" and \"VCC\" cells with \"Y\" outputs. (the default is \"G\"\n");
111 log(" for \"GND\" and \"P\" for \"VCC\".)\n");
114 log(" create EDIF properties for cell attributes\n");
117 log(" create extra KEEP nets by allowing a cell to drive multiple nets.\n");
119 log(" -pvector {par|bra|ang}\n");
120 log(" sets the delimiting character for module port rename clauses to\n");
121 log(" parentheses, square brackets, or angle brackets.\n");
123 log("Unfortunately there are different \"flavors\" of the EDIF file format. This\n");
124 log("command generates EDIF files for the Xilinx place&route tools. It might be\n");
125 log("necessary to make small modifications to this command when a different tool\n");
126 log("is targeted.\n");
129 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
131 log_header(design
, "Executing EDIF backend.\n");
132 std::string top_module_name
;
133 bool port_rename
= false;
134 bool attr_properties
= false;
135 std::map
<RTLIL::IdString
, std::map
<RTLIL::IdString
, int>> lib_cell_ports
;
136 bool nogndvcc
= false, gndvccy
= false, keepmode
= false;
137 CellTypes
ct(design
);
138 EdifNames edif_names
;
141 for (argidx
= 1; argidx
< args
.size(); argidx
++)
143 if (args
[argidx
] == "-top" && argidx
+1 < args
.size()) {
144 top_module_name
= args
[++argidx
];
147 if (args
[argidx
] == "-nogndvcc") {
151 if (args
[argidx
] == "-gndvccy") {
155 if (args
[argidx
] == "-attrprop") {
156 attr_properties
= true;
159 if (args
[argidx
] == "-keep") {
163 if (args
[argidx
] == "-pvector" && argidx
+1 < args
.size()) {
166 parray
= args
[++argidx
];
167 if (parray
== "par") {
168 edif_names
.delim_left
= '(';edif_names
.delim_right
= ')';
169 } else if (parray
== "ang") {
170 edif_names
.delim_left
= '<';edif_names
.delim_right
= '>';
172 edif_names
.delim_left
= '[';edif_names
.delim_right
= ']';
178 extra_args(f
, filename
, args
, argidx
);
180 if (top_module_name
.empty())
181 for (auto module
: design
->modules())
182 if (module
->get_bool_attribute(ID::top
))
183 top_module_name
= module
->name
.str();
185 for (auto module
: design
->modules())
187 if (module
->get_blackbox_attribute())
190 if (top_module_name
.empty())
191 top_module_name
= module
->name
.str();
193 if (module
->processes
.size() != 0)
194 log_error("Found unmapped processes in module %s: unmapped processes are not supported in EDIF backend!\n", log_id(module
->name
));
195 if (module
->memories
.size() != 0)
196 log_error("Found unmapped memories in module %s: unmapped memories are not supported in EDIF backend!\n", log_id(module
->name
));
198 for (auto cell
: module
->cells())
200 if (design
->module(cell
->type
) == nullptr || design
->module(cell
->type
)->get_blackbox_attribute()) {
201 lib_cell_ports
[cell
->type
];
202 for (auto p
: cell
->connections())
203 lib_cell_ports
[cell
->type
][p
.first
] = GetSize(p
.second
);
208 if (top_module_name
.empty())
209 log_error("No module found in design!\n");
211 *f
<< stringf("(edif %s\n", EDIF_DEF(top_module_name
));
212 *f
<< stringf(" (edifVersion 2 0 0)\n");
213 *f
<< stringf(" (edifLevel 0)\n");
214 *f
<< stringf(" (keywordMap (keywordLevel 0))\n");
215 *f
<< stringf(" (comment \"Generated by %s\")\n", yosys_version_str
);
217 *f
<< stringf(" (external LIB\n");
218 *f
<< stringf(" (edifLevel 0)\n");
219 *f
<< stringf(" (technology (numberDefinition))\n");
223 *f
<< stringf(" (cell GND\n");
224 *f
<< stringf(" (cellType GENERIC)\n");
225 *f
<< stringf(" (view VIEW_NETLIST\n");
226 *f
<< stringf(" (viewType NETLIST)\n");
227 *f
<< stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy
? 'Y' : 'G');
228 *f
<< stringf(" )\n");
229 *f
<< stringf(" )\n");
231 *f
<< stringf(" (cell VCC\n");
232 *f
<< stringf(" (cellType GENERIC)\n");
233 *f
<< stringf(" (view VIEW_NETLIST\n");
234 *f
<< stringf(" (viewType NETLIST)\n");
235 *f
<< stringf(" (interface (port %c (direction OUTPUT)))\n", gndvccy
? 'Y' : 'P');
236 *f
<< stringf(" )\n");
237 *f
<< stringf(" )\n");
240 for (auto &cell_it
: lib_cell_ports
) {
241 *f
<< stringf(" (cell %s\n", EDIF_DEF(cell_it
.first
));
242 *f
<< stringf(" (cellType GENERIC)\n");
243 *f
<< stringf(" (view VIEW_NETLIST\n");
244 *f
<< stringf(" (viewType NETLIST)\n");
245 *f
<< stringf(" (interface\n");
246 for (auto &port_it
: cell_it
.second
) {
247 const char *dir
= "INOUT";
248 if (ct
.cell_known(cell_it
.first
)) {
249 if (!ct
.cell_output(cell_it
.first
, port_it
.first
))
251 else if (!ct
.cell_input(cell_it
.first
, port_it
.first
))
254 int width
= port_it
.second
;
257 auto m
= design
->module(cell_it
.first
);
259 auto w
= m
->wire(port_it
.first
);
262 start
= w
->start_offset
;
267 *f
<< stringf(" (port %s (direction %s))\n", EDIF_DEF(port_it
.first
), dir
);
270 b
[upto
? 0 : 1] = start
;
271 b
[upto
? 1 : 0] = start
+width
-1;
272 *f
<< stringf(" (port (array %s %d) (direction %s))\n", EDIF_DEFR(port_it
.first
, port_rename
, b
[0], b
[1]), width
, dir
);
275 *f
<< stringf(" )\n");
276 *f
<< stringf(" )\n");
277 *f
<< stringf(" )\n");
279 *f
<< stringf(" )\n");
281 std::vector
<RTLIL::Module
*> sorted_modules
;
283 // extract module dependencies
284 std::map
<RTLIL::Module
*, std::set
<RTLIL::Module
*>> module_deps
;
285 for (auto module
: design
->modules()) {
286 module_deps
[module
] = std::set
<RTLIL::Module
*>();
287 for (auto cell
: module
->cells())
288 if (design
->module(cell
->type
) != nullptr)
289 module_deps
[module
].insert(design
->module(cell
->type
));
292 // simple good-enough topological sort
293 // (O(n*m) on n elements and depth m)
294 while (module_deps
.size() > 0) {
295 size_t sorted_modules_idx
= sorted_modules
.size();
296 for (auto &it
: module_deps
) {
297 for (auto &dep
: it
.second
)
298 if (module_deps
.count(dep
) > 0)
300 // log("Next in topological sort: %s\n", log_id(it.first->name));
301 sorted_modules
.push_back(it
.first
);
304 if (sorted_modules_idx
== sorted_modules
.size())
305 log_error("Cyclic dependency between modules found! Cycle includes module %s.\n", log_id(module_deps
.begin()->first
->name
));
306 while (sorted_modules_idx
< sorted_modules
.size())
307 module_deps
.erase(sorted_modules
.at(sorted_modules_idx
++));
311 *f
<< stringf(" (library DESIGN\n");
312 *f
<< stringf(" (edifLevel 0)\n");
313 *f
<< stringf(" (technology (numberDefinition))\n");
315 auto add_prop
= [&](IdString name
, Const val
) {
316 if ((val
.flags
& RTLIL::CONST_FLAG_STRING
) != 0)
317 *f
<< stringf("\n (property %s (string \"%s\"))", EDIF_DEF(name
), val
.decode_string().c_str());
318 else if (val
.bits
.size() <= 32 && RTLIL::SigSpec(val
).is_fully_def())
319 *f
<< stringf("\n (property %s (integer %u))", EDIF_DEF(name
), val
.as_int());
321 std::string hex_string
= "";
322 for (size_t i
= 0; i
< val
.bits
.size(); i
+= 4) {
324 if (i
+0 < val
.bits
.size() && val
.bits
.at(i
+0) == RTLIL::State::S1
) digit_value
|= 1;
325 if (i
+1 < val
.bits
.size() && val
.bits
.at(i
+1) == RTLIL::State::S1
) digit_value
|= 2;
326 if (i
+2 < val
.bits
.size() && val
.bits
.at(i
+2) == RTLIL::State::S1
) digit_value
|= 4;
327 if (i
+3 < val
.bits
.size() && val
.bits
.at(i
+3) == RTLIL::State::S1
) digit_value
|= 8;
328 char digit_str
[2] = { "0123456789abcdef"[digit_value
], 0 };
329 hex_string
= std::string(digit_str
) + hex_string
;
331 *f
<< stringf("\n (property %s (string \"%d'h%s\"))", EDIF_DEF(name
), GetSize(val
.bits
), hex_string
.c_str());
334 for (auto module
: sorted_modules
)
336 if (module
->get_blackbox_attribute())
339 SigMap
sigmap(module
);
340 std::map
<RTLIL::SigSpec
, std::set
<std::pair
<std::string
, bool>>> net_join_db
;
342 *f
<< stringf(" (cell %s\n", EDIF_DEF(module
->name
));
343 *f
<< stringf(" (cellType GENERIC)\n");
344 *f
<< stringf(" (view VIEW_NETLIST\n");
345 *f
<< stringf(" (viewType NETLIST)\n");
346 *f
<< stringf(" (interface\n");
348 for (auto wire
: module
->wires()) {
349 if (wire
->port_id
== 0)
351 const char *dir
= "INOUT";
352 if (!wire
->port_output
)
354 else if (!wire
->port_input
)
356 if (wire
->width
== 1) {
357 *f
<< stringf(" (port %s (direction %s)", EDIF_DEF(wire
->name
), dir
);
359 for (auto &p
: wire
->attributes
)
360 add_prop(p
.first
, p
.second
);
362 RTLIL::SigSpec sig
= sigmap(RTLIL::SigSpec(wire
));
363 net_join_db
[sig
].insert(make_pair(stringf("(portRef %s)", EDIF_REF(wire
->name
)), wire
->port_input
));
366 b
[wire
->upto
? 0 : 1] = wire
->start_offset
;
367 b
[wire
->upto
? 1 : 0] = wire
->start_offset
+ GetSize(wire
) - 1;
368 *f
<< stringf(" (port (array %s %d) (direction %s)", EDIF_DEFR(wire
->name
, port_rename
, b
[0], b
[1]), wire
->width
, dir
);
370 for (auto &p
: wire
->attributes
)
371 add_prop(p
.first
, p
.second
);
374 for (int i
= 0; i
< wire
->width
; i
++) {
375 RTLIL::SigSpec sig
= sigmap(RTLIL::SigSpec(wire
, i
));
376 net_join_db
[sig
].insert(make_pair(stringf("(portRef (member %s %d))", EDIF_REF(wire
->name
), GetSize(wire
)-i
-1), wire
->port_input
));
381 *f
<< stringf(" )\n");
382 *f
<< stringf(" (contents\n");
385 *f
<< stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n");
386 *f
<< stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n");
389 for (auto cell
: module
->cells()) {
390 *f
<< stringf(" (instance %s\n", EDIF_DEF(cell
->name
));
391 *f
<< stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell
->type
),
392 lib_cell_ports
.count(cell
->type
) > 0 ? " (libraryRef LIB)" : "");
393 for (auto &p
: cell
->parameters
)
394 add_prop(p
.first
, p
.second
);
396 for (auto &p
: cell
->attributes
)
397 add_prop(p
.first
, p
.second
);
399 *f
<< stringf(")\n");
400 for (auto &p
: cell
->connections()) {
401 RTLIL::SigSpec sig
= sigmap(p
.second
);
402 for (int i
= 0; i
< GetSize(sig
); i
++)
403 if (sig
[i
].wire
== NULL
&& sig
[i
] != RTLIL::State::S0
&& sig
[i
] != RTLIL::State::S1
)
404 log_warning("Bit %d of cell port %s.%s.%s driven by %s will be left unconnected in EDIF output.\n",
405 i
, log_id(module
), log_id(cell
), log_id(p
.first
), log_signal(sig
[i
]));
407 int member_idx
= GetSize(sig
)-i
-1;
408 auto m
= design
->module(cell
->type
);
409 int width
= sig
.size();
411 auto w
= m
->wire(p
.first
);
413 member_idx
= GetSize(w
)-i
-1;
418 net_join_db
[sig
[i
]].insert(make_pair(stringf("(portRef %s (instanceRef %s))", EDIF_REF(p
.first
), EDIF_REF(cell
->name
)), cell
->output(p
.first
)));
420 net_join_db
[sig
[i
]].insert(make_pair(stringf("(portRef (member %s %d) (instanceRef %s))",
421 EDIF_REF(p
.first
), member_idx
, EDIF_REF(cell
->name
)), cell
->output(p
.first
)));
427 for (auto &it
: net_join_db
) {
428 RTLIL::SigBit sig
= it
.first
;
429 if (sig
.wire
== NULL
&& sig
!= RTLIL::State::S0
&& sig
!= RTLIL::State::S1
) {
430 if (sig
== RTLIL::State::Sx
) {
431 for (auto &ref
: it
.second
)
432 log_warning("Exporting x-bit on %s as zero bit.\n", ref
.first
.c_str());
433 sig
= RTLIL::State::S0
;
434 } else if (sig
== RTLIL::State::Sz
) {
437 for (auto &ref
: it
.second
)
438 log_error("Don't know how to handle %s on %s.\n", log_signal(sig
), ref
.first
.c_str());
443 if (sig
== RTLIL::State::S0
)
445 else if (sig
== RTLIL::State::S1
)
448 netname
= log_signal(sig
);
449 for (size_t i
= 0; i
< netname
.size(); i
++)
450 if (netname
[i
] == ' ' || netname
[i
] == '\\')
451 netname
.erase(netname
.begin() + i
--);
453 *f
<< stringf(" (net %s (joined\n", EDIF_DEF(netname
));
454 for (auto &ref
: it
.second
)
455 *f
<< stringf(" %s\n", ref
.first
.c_str());
456 if (sig
.wire
== NULL
) {
458 log_error("Design contains constant nodes (map with \"hilomap\" first).\n");
459 if (sig
== RTLIL::State::S0
)
460 *f
<< stringf(" (portRef %c (instanceRef GND))\n", gndvccy
? 'Y' : 'G');
461 if (sig
== RTLIL::State::S1
)
462 *f
<< stringf(" (portRef %c (instanceRef VCC))\n", gndvccy
? 'Y' : 'P');
465 if (attr_properties
&& sig
.wire
!= NULL
)
466 for (auto &p
: sig
.wire
->attributes
)
467 add_prop(p
.first
, p
.second
);
468 *f
<< stringf("\n )\n");
471 for (auto wire
: module
->wires())
473 if (!wire
->get_bool_attribute(ID::keep
))
476 for(int i
= 0; i
< wire
->width
; i
++)
478 SigBit raw_sig
= RTLIL::SigSpec(wire
, i
);
479 SigBit mapped_sig
= sigmap(raw_sig
);
481 if (raw_sig
== mapped_sig
|| net_join_db
.count(mapped_sig
) == 0)
484 std::string netname
= log_signal(raw_sig
);
485 for (size_t i
= 0; i
< netname
.size(); i
++)
486 if (netname
[i
] == ' ' || netname
[i
] == '\\')
487 netname
.erase(netname
.begin() + i
--);
491 *f
<< stringf(" (net %s (joined\n", EDIF_DEF(netname
));
493 auto &refs
= net_join_db
.at(mapped_sig
);
494 for (auto &ref
: refs
)
496 *f
<< stringf(" %s\n", ref
.first
.c_str());
499 if (attr_properties
&& raw_sig
.wire
!= NULL
)
500 for (auto &p
: raw_sig
.wire
->attributes
)
501 add_prop(p
.first
, p
.second
);
503 *f
<< stringf("\n )\n");
507 log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname
));
512 *f
<< stringf(" )\n");
513 *f
<< stringf(" )\n");
514 *f
<< stringf(" )\n");
516 *f
<< stringf(" )\n");
518 *f
<< stringf(" (design %s\n", EDIF_DEF(top_module_name
));
519 *f
<< stringf(" (cellRef %s (libraryRef DESIGN))\n", EDIF_REF(top_module_name
));
520 *f
<< stringf(" )\n");
522 *f
<< stringf(")\n");
526 PRIVATE_NAMESPACE_END