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 #include "blifparse.h"
24 static bool read_next_line(char *&buffer
, size_t &buffer_size
, int &line_count
, std::istream
&f
)
32 buffer_len
+= strlen(buffer
+ buffer_len
);
33 while (buffer_len
> 0 && (buffer
[buffer_len
-1] == ' ' || buffer
[buffer_len
-1] == '\t' ||
34 buffer
[buffer_len
-1] == '\r' || buffer
[buffer_len
-1] == '\n'))
35 buffer
[--buffer_len
] = 0;
37 if (buffer_size
-buffer_len
< 4096) {
39 buffer
= (char*)realloc(buffer
, buffer_size
);
42 if (buffer_len
== 0 || buffer
[buffer_len
-1] == '\\') {
43 if (buffer_len
> 0 && buffer
[buffer_len
-1] == '\\')
44 buffer
[--buffer_len
] = 0;
46 if (!std::getline(f
, strbuf
))
48 while (buffer_size
-buffer_len
< strbuf
.size()+1) {
50 buffer
= (char*)realloc(buffer
, buffer_size
);
52 strcpy(buffer
+buffer_len
, strbuf
.c_str());
58 static std::pair
<RTLIL::IdString
, int> wideports_split(std::string name
)
62 if (name
.empty() || name
.back() != ']')
65 for (int i
= 0; i
+1 < GetSize(name
); i
++) {
68 else if (name
[i
] < '0' || name
[i
] > '9')
70 else if (i
== pos
+1 && name
[i
] == '0' && name
[i
+1] != ']')
75 return std::pair
<RTLIL::IdString
, int>("\\" + name
.substr(0, pos
), atoi(name
.c_str() + pos
+1)+1);
78 return std::pair
<RTLIL::IdString
, int>("\\" + name
, 0);
81 void parse_blif(RTLIL::Design
*design
, std::istream
&f
, std::string dff_name
, bool run_clean
, bool sop_mode
, bool wideports
)
83 RTLIL::Module
*module
= nullptr;
84 RTLIL::Const
*lutptr
= NULL
;
85 RTLIL::Cell
*sopcell
= NULL
;
86 RTLIL::Cell
*lastcell
= nullptr;
87 RTLIL::State lut_default_state
= RTLIL::State::Sx
;
88 std::string err_reason
;
89 int blif_maxnum
= 0, sopmode
= -1;
91 auto blif_wire
= [&](const std::string
&wire_name
) -> Wire
*
93 if (wire_name
[0] == '$')
95 for (int i
= 0; i
+1 < GetSize(wire_name
); i
++)
97 if (wire_name
[i
] != '$')
101 while (i
+len
+1 < GetSize(wire_name
) && '0' <= wire_name
[i
+len
+1] && wire_name
[i
+len
+1] <= '9')
105 string num_str
= wire_name
.substr(i
+1, len
);
106 int num
= atoi(num_str
.c_str()) & 0x0fffffff;
107 blif_maxnum
= std::max(blif_maxnum
, num
);
112 IdString wire_id
= RTLIL::escape_id(wire_name
);
113 Wire
*wire
= module
->wire(wire_id
);
116 wire
= module
->addWire(wire_id
);
121 dict
<RTLIL::IdString
, RTLIL::Const
> *obj_attributes
= nullptr;
122 dict
<RTLIL::IdString
, RTLIL::Const
> *obj_parameters
= nullptr;
124 dict
<RTLIL::IdString
, std::pair
<int, bool>> wideports_cache
;
126 size_t buffer_size
= 4096;
127 char *buffer
= (char*)malloc(buffer_size
);
132 if (!read_next_line(buffer
, buffer_size
, line_count
, f
)) {
133 if (module
!= nullptr)
139 continue_without_read
:
140 if (buffer
[0] == '#')
143 if (buffer
[0] == '.')
146 for (auto &bit
: lutptr
->bits
)
147 if (bit
== RTLIL::State::Sx
)
148 bit
= lut_default_state
;
150 lut_default_state
= RTLIL::State::Sx
;
158 char *cmd
= strtok(buffer
, " \t\r\n");
160 if (!strcmp(cmd
, ".model")) {
161 if (module
!= nullptr)
163 module
= new RTLIL::Module
;
165 module
->name
= RTLIL::escape_id(strtok(NULL
, " \t\r\n"));
166 obj_attributes
= &module
->attributes
;
167 obj_parameters
= nullptr;
168 if (design
->module(module
->name
))
169 log_error("Duplicate definition of module %s in line %d!\n", log_id(module
->name
), line_count
);
174 if (module
== nullptr)
177 if (!strcmp(cmd
, ".end"))
179 for (auto &wp
: wideports_cache
)
181 auto name
= wp
.first
;
182 int width
= wp
.second
.first
;
183 bool isinput
= wp
.second
.second
;
185 RTLIL::Wire
*wire
= module
->addWire(name
, width
);
186 wire
->port_input
= isinput
;
187 wire
->port_output
= !isinput
;
189 for (int i
= 0; i
< width
; i
++) {
190 RTLIL::IdString other_name
= name
.str() + stringf("[%d]", i
);
191 RTLIL::Wire
*other_wire
= module
->wire(other_name
);
193 other_wire
->port_input
= false;
194 other_wire
->port_output
= false;
196 module
->connect(other_wire
, SigSpec(wire
, i
));
198 module
->connect(SigSpec(wire
, i
), other_wire
);
203 module
->fixup_ports();
204 wideports_cache
.clear();
208 Const
buffer_lut(vector
<RTLIL::State
>({State::S0
, State::S1
}));
209 vector
<Cell
*> remove_cells
;
211 for (auto cell
: module
->cells())
212 if (cell
->type
== "$lut" && cell
->getParam("\\LUT") == buffer_lut
) {
213 module
->connect(cell
->getPort("\\Y"), cell
->getPort("\\A"));
214 remove_cells
.push_back(cell
);
217 for (auto cell
: remove_cells
)
218 module
->remove(cell
);
220 Wire
*true_wire
= module
->wire("$true");
221 Wire
*false_wire
= module
->wire("$false");
222 Wire
*undef_wire
= module
->wire("$undef");
224 if (true_wire
!= nullptr)
225 module
->rename(true_wire
, stringf("$true$%d", ++blif_maxnum
));
227 if (false_wire
!= nullptr)
228 module
->rename(false_wire
, stringf("$false$%d", ++blif_maxnum
));
230 if (undef_wire
!= nullptr)
231 module
->rename(undef_wire
, stringf("$undef$%d", ++blif_maxnum
));
233 autoidx
= std::max(autoidx
, blif_maxnum
+1);
239 obj_attributes
= nullptr;
240 obj_parameters
= nullptr;
244 if (!strcmp(cmd
, ".inputs") || !strcmp(cmd
, ".outputs"))
247 while ((p
= strtok(NULL
, " \t\r\n")) != NULL
)
249 RTLIL::IdString
wire_name(stringf("\\%s", p
));
250 RTLIL::Wire
*wire
= module
->wire(wire_name
);
252 wire
= module
->addWire(wire_name
);
253 if (!strcmp(cmd
, ".inputs"))
254 wire
->port_input
= true;
256 wire
->port_output
= true;
259 std::pair
<RTLIL::IdString
, int> wp
= wideports_split(p
);
261 wideports_cache
[wp
.first
].first
= std::max(wideports_cache
[wp
.first
].first
, wp
.second
);
262 wideports_cache
[wp
.first
].second
= !strcmp(cmd
, ".inputs");
266 obj_attributes
= nullptr;
267 obj_parameters
= nullptr;
271 if (!strcmp(cmd
, ".cname"))
273 char *p
= strtok(NULL
, " \t\r\n");
277 if(lastcell
== nullptr || module
== nullptr)
279 err_reason
= stringf("No primitive object to attach .cname %s.", p
);
280 goto error_with_reason
;
283 module
->rename(lastcell
, p
);
287 if (!strcmp(cmd
, ".attr") || !strcmp(cmd
, ".param")) {
288 char *n
= strtok(NULL
, " \t\r\n");
289 char *v
= strtok(NULL
, "\r\n");
290 IdString id_n
= RTLIL::escape_id(n
);
293 std::string
str(v
+1);
294 if (str
.back() == '"')
295 str
.resize(str
.size()-1);
296 const_v
= Const(str
);
299 const_v
.bits
.resize(n
);
300 for (int i
= 0; i
< n
; i
++)
301 const_v
.bits
[i
] = v
[n
-i
-1] != '0' ? State::S1
: State::S0
;
303 if (!strcmp(cmd
, ".attr")) {
304 if (obj_attributes
== nullptr) {
305 err_reason
= stringf("No object to attach .attr too.");
306 goto error_with_reason
;
308 (*obj_attributes
)[id_n
] = const_v
;
310 if (obj_parameters
== nullptr) {
311 err_reason
= stringf("No object to attach .param too.");
312 goto error_with_reason
;
314 (*obj_parameters
)[id_n
] = const_v
;
319 if (!strcmp(cmd
, ".latch"))
321 char *d
= strtok(NULL
, " \t\r\n");
322 char *q
= strtok(NULL
, " \t\r\n");
323 char *edge
= strtok(NULL
, " \t\r\n");
324 char *clock
= strtok(NULL
, " \t\r\n");
325 char *init
= strtok(NULL
, " \t\r\n");
326 RTLIL::Cell
*cell
= nullptr;
328 if (clock
== nullptr && edge
!= nullptr) {
333 if (init
!= nullptr && (init
[0] == '0' || init
[0] == '1'))
334 blif_wire(q
)->attributes
["\\init"] = Const(init
[0] == '1' ? 1 : 0, 1);
336 if (clock
== nullptr)
339 if (!strcmp(edge
, "re"))
340 cell
= module
->addDff(NEW_ID
, blif_wire(clock
), blif_wire(d
), blif_wire(q
));
341 else if (!strcmp(edge
, "fe"))
342 cell
= module
->addDff(NEW_ID
, blif_wire(clock
), blif_wire(d
), blif_wire(q
), false);
343 else if (!strcmp(edge
, "ah"))
344 cell
= module
->addDlatch(NEW_ID
, blif_wire(clock
), blif_wire(d
), blif_wire(q
));
345 else if (!strcmp(edge
, "al"))
346 cell
= module
->addDlatch(NEW_ID
, blif_wire(clock
), blif_wire(d
), blif_wire(q
), false);
349 if (dff_name
.empty()) {
350 cell
= module
->addFf(NEW_ID
, blif_wire(d
), blif_wire(q
));
352 cell
= module
->addCell(NEW_ID
, dff_name
);
353 cell
->setPort("\\D", blif_wire(d
));
354 cell
->setPort("\\Q", blif_wire(q
));
359 obj_attributes
= &cell
->attributes
;
360 obj_parameters
= &cell
->parameters
;
364 if (!strcmp(cmd
, ".gate") || !strcmp(cmd
, ".subckt"))
366 char *p
= strtok(NULL
, " \t\r\n");
370 IdString celltype
= RTLIL::escape_id(p
);
371 RTLIL::Cell
*cell
= module
->addCell(NEW_ID
, celltype
);
373 dict
<RTLIL::IdString
, dict
<int, SigBit
>> cell_wideports_cache
;
375 while ((p
= strtok(NULL
, " \t\r\n")) != NULL
)
377 char *q
= strchr(p
, '=');
378 if (q
== NULL
|| !q
[0])
383 std::pair
<RTLIL::IdString
, int> wp
= wideports_split(p
);
385 cell_wideports_cache
[wp
.first
][wp
.second
-1] = blif_wire(q
);
387 cell
->setPort(RTLIL::escape_id(p
), *q
? blif_wire(q
) : SigSpec());
389 cell
->setPort(RTLIL::escape_id(p
), *q
? blif_wire(q
) : SigSpec());
393 for (auto &it
: cell_wideports_cache
)
396 for (auto &b
: it
.second
)
397 width
= std::max(width
, b
.first
+ 1);
401 for (int i
= 0; i
< width
; i
++) {
402 if (it
.second
.count(i
))
403 sig
.append(it
.second
.at(i
));
405 sig
.append(module
->addWire(NEW_ID
));
408 cell
->setPort(it
.first
, sig
);
412 obj_attributes
= &cell
->attributes
;
413 obj_parameters
= &cell
->parameters
;
417 obj_attributes
= nullptr;
418 obj_parameters
= nullptr;
420 if (!strcmp(cmd
, ".barbuf") || !strcmp(cmd
, ".conn"))
422 char *p
= strtok(NULL
, " \t\r\n");
426 char *q
= strtok(NULL
, " \t\r\n");
430 module
->connect(blif_wire(q
), blif_wire(p
));
434 if (!strcmp(cmd
, ".names"))
437 RTLIL::SigSpec input_sig
, output_sig
;
438 while ((p
= strtok(NULL
, " \t\r\n")) != NULL
)
439 input_sig
.append(blif_wire(p
));
440 output_sig
= input_sig
.extract(input_sig
.size()-1, 1);
441 input_sig
= input_sig
.extract(0, input_sig
.size()-1);
443 if (input_sig
.size() == 0)
445 RTLIL::State state
= RTLIL::State::Sa
;
447 if (!read_next_line(buffer
, buffer_size
, line_count
, f
))
449 for (int i
= 0; buffer
[i
]; i
++) {
450 if (buffer
[i
] == ' ' || buffer
[i
] == '\t')
452 if (i
== 0 && buffer
[i
] == '.')
453 goto finished_parsing_constval
;
454 if (buffer
[i
] == '0') {
455 if (state
== RTLIL::State::S1
)
457 state
= RTLIL::State::S0
;
460 if (buffer
[i
] == '1') {
461 if (state
== RTLIL::State::S0
)
463 state
= RTLIL::State::S1
;
470 finished_parsing_constval
:
471 if (state
== RTLIL::State::Sa
)
472 state
= RTLIL::State::S0
;
473 if (output_sig
.as_wire()->name
== "$undef")
474 state
= RTLIL::State::Sx
;
475 module
->connect(RTLIL::SigSig(output_sig
, state
));
476 goto continue_without_read
;
481 sopcell
= module
->addCell(NEW_ID
, "$sop");
482 sopcell
->parameters
["\\WIDTH"] = RTLIL::Const(input_sig
.size());
483 sopcell
->parameters
["\\DEPTH"] = 0;
484 sopcell
->parameters
["\\TABLE"] = RTLIL::Const();
485 sopcell
->setPort("\\A", input_sig
);
486 sopcell
->setPort("\\Y", output_sig
);
492 RTLIL::Cell
*cell
= module
->addCell(NEW_ID
, "$lut");
493 cell
->parameters
["\\WIDTH"] = RTLIL::Const(input_sig
.size());
494 cell
->parameters
["\\LUT"] = RTLIL::Const(RTLIL::State::Sx
, 1 << input_sig
.size());
495 cell
->setPort("\\A", input_sig
);
496 cell
->setPort("\\Y", output_sig
);
497 lutptr
= &cell
->parameters
.at("\\LUT");
498 lut_default_state
= RTLIL::State::Sx
;
507 if (lutptr
== NULL
&& sopcell
== NULL
)
510 char *input
= strtok(buffer
, " \t\r\n");
511 char *output
= strtok(NULL
, " \t\r\n");
513 if (input
== NULL
|| output
== NULL
|| (strcmp(output
, "0") && strcmp(output
, "1")))
516 int input_len
= strlen(input
);
520 log_assert(sopcell
->parameters
["\\WIDTH"].as_int() == input_len
);
521 sopcell
->parameters
["\\DEPTH"] = sopcell
->parameters
["\\DEPTH"].as_int() + 1;
523 for (int i
= 0; i
< input_len
; i
++)
526 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S1
);
527 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S0
);
530 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S0
);
531 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S1
);
534 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S0
);
535 sopcell
->parameters
["\\TABLE"].bits
.push_back(State::S0
);
540 sopmode
= (*output
== '1');
542 SigSpec outnet
= sopcell
->getPort("\\Y");
543 SigSpec tempnet
= module
->addWire(NEW_ID
);
544 module
->addNotGate(NEW_ID
, tempnet
, outnet
);
545 sopcell
->setPort("\\Y", tempnet
);
548 log_assert(sopmode
== (*output
== '1'));
556 for (int i
= 0; i
< (1 << input_len
); i
++) {
557 for (int j
= 0; j
< input_len
; j
++) {
560 char c2
= (i
& (1 << j
)) != 0 ? '1' : '0';
565 lutptr
->bits
.at(i
) = !strcmp(output
, "0") ? RTLIL::State::S0
: RTLIL::State::S1
;
569 lut_default_state
= !strcmp(output
, "0") ? RTLIL::State::S1
: RTLIL::State::S0
;
576 log_error("Syntax error in line %d!\n", line_count
);
578 log_error("Syntax error in line %d: %s\n", line_count
, err_reason
.c_str());
581 struct BlifFrontend
: public Frontend
{
582 BlifFrontend() : Frontend("blif", "read BLIF file") { }
583 void help() YS_OVERRIDE
585 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
587 log(" read_blif [options] [filename]\n");
589 log("Load modules from a BLIF file into the current design.\n");
592 log(" Create $sop cells instead of $lut cells\n");
594 log(" -wideports\n");
595 log(" Merge ports that match the pattern 'name[int]' into a single\n");
596 log(" multi-bit port 'name'.\n");
599 void execute(std::istream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
601 bool sop_mode
= false;
602 bool wideports
= false;
604 log_header(design
, "Executing BLIF frontend.\n");
607 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
608 std::string arg
= args
[argidx
];
613 if (arg
== "-wideports") {
619 extra_args(f
, filename
, args
, argidx
);
621 parse_blif(design
, *f
, "", true, sop_mode
, wideports
);