Merge pull request #1949 from YosysHQ/eddie/select_blackbox
[yosys.git] / frontends / ilang / ilang_parser.y
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 frontend for the RTLIL text
21 * representation (as generated by the 'ilang' backend).
22 *
23 */
24
25 %{
26 #include <list>
27 #include "frontends/ilang/ilang_frontend.h"
28 YOSYS_NAMESPACE_BEGIN
29 namespace ILANG_FRONTEND {
30 std::istream *lexin;
31 RTLIL::Design *current_design;
32 RTLIL::Module *current_module;
33 RTLIL::Wire *current_wire;
34 RTLIL::Memory *current_memory;
35 RTLIL::Cell *current_cell;
36 RTLIL::Process *current_process;
37 std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
38 std::vector<RTLIL::CaseRule*> case_stack;
39 dict<RTLIL::IdString, RTLIL::Const> attrbuf;
40 bool flag_nooverwrite, flag_overwrite, flag_lib;
41 bool delete_current_module;
42 }
43 using namespace ILANG_FRONTEND;
44 YOSYS_NAMESPACE_END
45 USING_YOSYS_NAMESPACE
46 %}
47
48 %define api.prefix {rtlil_frontend_ilang_yy}
49
50 /* The union is defined in the header, so we need to provide all the
51 * includes it requires
52 */
53 %code requires {
54 #include <string>
55 #include <vector>
56 #include "frontends/ilang/ilang_frontend.h"
57 }
58
59 %union {
60 char *string;
61 int integer;
62 YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
63 YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
64 std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec;
65 }
66
67 %token <string> TOK_ID TOK_VALUE TOK_STRING
68 %token <integer> TOK_INT
69 %token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
70 %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
71 %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT
72 %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
73 %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO
74
75 %type <rsigspec> sigspec_list_reversed
76 %type <sigspec> sigspec sigspec_list
77 %type <integer> sync_type
78 %type <data> constant
79
80 %expect 0
81 %debug
82
83 %%
84
85 input:
86 optional_eol {
87 attrbuf.clear();
88 } design {
89 if (attrbuf.size() != 0)
90 rtlil_frontend_ilang_yyerror("dangling attribute");
91 };
92
93 EOL:
94 optional_eol TOK_EOL;
95
96 optional_eol:
97 optional_eol TOK_EOL | /* empty */;
98
99 design:
100 design module |
101 design attr_stmt |
102 design autoidx_stmt |
103 /* empty */;
104
105 module:
106 TOK_MODULE TOK_ID EOL {
107 delete_current_module = false;
108 if (current_design->has($2)) {
109 RTLIL::Module *existing_mod = current_design->module($2);
110 if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) {
111 log("Ignoring blackbox re-definition of module %s.\n", $2);
112 delete_current_module = true;
113 } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) {
114 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
115 } else if (flag_nooverwrite) {
116 log("Ignoring re-definition of module %s.\n", $2);
117 delete_current_module = true;
118 } else {
119 log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2);
120 current_design->remove(existing_mod);
121 }
122 }
123 current_module = new RTLIL::Module;
124 current_module->name = $2;
125 current_module->attributes = attrbuf;
126 if (!delete_current_module)
127 current_design->add(current_module);
128 attrbuf.clear();
129 free($2);
130 } module_body TOK_END {
131 if (attrbuf.size() != 0)
132 rtlil_frontend_ilang_yyerror("dangling attribute");
133 current_module->fixup_ports();
134 if (delete_current_module)
135 delete current_module;
136 else if (flag_lib)
137 current_module->makeblackbox();
138 current_module = nullptr;
139 } EOL;
140
141 module_body:
142 module_body module_stmt |
143 /* empty */;
144
145 module_stmt:
146 param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt;
147
148 param_stmt:
149 TOK_PARAMETER TOK_ID EOL {
150 current_module->avail_parameters($2);
151 free($2);
152 };
153
154 param_defval_stmt:
155 TOK_PARAMETER TOK_ID constant EOL {
156 current_module->avail_parameters($2);
157 current_module->parameter_default_values[$2] = *$3;
158 free($2);
159 };
160
161 attr_stmt:
162 TOK_ATTRIBUTE TOK_ID constant EOL {
163 attrbuf[$2] = *$3;
164 delete $3;
165 free($2);
166 };
167
168 autoidx_stmt:
169 TOK_AUTOIDX TOK_INT EOL {
170 autoidx = max(autoidx, $2);
171 };
172
173 wire_stmt:
174 TOK_WIRE {
175 current_wire = current_module->addWire("$__ilang_frontend_tmp__");
176 current_wire->attributes = attrbuf;
177 attrbuf.clear();
178 } wire_options TOK_ID EOL {
179 if (current_module->wire($4) != nullptr)
180 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
181 current_module->rename(current_wire, $4);
182 free($4);
183 };
184
185 wire_options:
186 wire_options TOK_WIDTH TOK_INT {
187 current_wire->width = $3;
188 } |
189 wire_options TOK_WIDTH TOK_INVALID {
190 rtlil_frontend_ilang_yyerror("ilang error: invalid wire width");
191 } |
192 wire_options TOK_UPTO {
193 current_wire->upto = true;
194 } |
195 wire_options TOK_OFFSET TOK_INT {
196 current_wire->start_offset = $3;
197 } |
198 wire_options TOK_INPUT TOK_INT {
199 current_wire->port_id = $3;
200 current_wire->port_input = true;
201 current_wire->port_output = false;
202 } |
203 wire_options TOK_OUTPUT TOK_INT {
204 current_wire->port_id = $3;
205 current_wire->port_input = false;
206 current_wire->port_output = true;
207 } |
208 wire_options TOK_INOUT TOK_INT {
209 current_wire->port_id = $3;
210 current_wire->port_input = true;
211 current_wire->port_output = true;
212 } |
213 /* empty */;
214
215 memory_stmt:
216 TOK_MEMORY {
217 current_memory = new RTLIL::Memory;
218 current_memory->attributes = attrbuf;
219 attrbuf.clear();
220 } memory_options TOK_ID EOL {
221 if (current_module->memories.count($4) != 0)
222 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str());
223 current_memory->name = $4;
224 current_module->memories[$4] = current_memory;
225 free($4);
226 };
227
228 memory_options:
229 memory_options TOK_WIDTH TOK_INT {
230 current_memory->width = $3;
231 } |
232 memory_options TOK_SIZE TOK_INT {
233 current_memory->size = $3;
234 } |
235 memory_options TOK_OFFSET TOK_INT {
236 current_memory->start_offset = $3;
237 } |
238 /* empty */;
239
240 cell_stmt:
241 TOK_CELL TOK_ID TOK_ID EOL {
242 if (current_module->cell($3) != nullptr)
243 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
244 current_cell = current_module->addCell($3, $2);
245 current_cell->attributes = attrbuf;
246 attrbuf.clear();
247 free($2);
248 free($3);
249 } cell_body TOK_END EOL;
250
251 cell_body:
252 cell_body TOK_PARAMETER TOK_ID constant EOL {
253 current_cell->parameters[$3] = *$4;
254 free($3);
255 delete $4;
256 } |
257 cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL {
258 current_cell->parameters[$4] = *$5;
259 current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED;
260 free($4);
261 delete $5;
262 } |
263 cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL {
264 current_cell->parameters[$4] = *$5;
265 current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL;
266 free($4);
267 delete $5;
268 } |
269 cell_body TOK_CONNECT TOK_ID sigspec EOL {
270 if (current_cell->hasPort($3))
271 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
272 current_cell->setPort($3, *$4);
273 delete $4;
274 free($3);
275 } |
276 /* empty */;
277
278 proc_stmt:
279 TOK_PROCESS TOK_ID EOL {
280 if (current_module->processes.count($2) != 0)
281 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str());
282 current_process = new RTLIL::Process;
283 current_process->name = $2;
284 current_process->attributes = attrbuf;
285 current_module->processes[$2] = current_process;
286 switch_stack.clear();
287 switch_stack.push_back(&current_process->root_case.switches);
288 case_stack.clear();
289 case_stack.push_back(&current_process->root_case);
290 attrbuf.clear();
291 free($2);
292 } case_body sync_list TOK_END EOL;
293
294 switch_stmt:
295 TOK_SWITCH sigspec EOL {
296 RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
297 rule->signal = *$2;
298 rule->attributes = attrbuf;
299 switch_stack.back()->push_back(rule);
300 attrbuf.clear();
301 delete $2;
302 } attr_list switch_body TOK_END EOL;
303
304 attr_list:
305 /* empty */ |
306 attr_list attr_stmt;
307
308 switch_body:
309 switch_body TOK_CASE {
310 RTLIL::CaseRule *rule = new RTLIL::CaseRule;
311 rule->attributes = attrbuf;
312 switch_stack.back()->back()->cases.push_back(rule);
313 switch_stack.push_back(&rule->switches);
314 case_stack.push_back(rule);
315 attrbuf.clear();
316 } compare_list EOL case_body {
317 switch_stack.pop_back();
318 case_stack.pop_back();
319 } |
320 /* empty */;
321
322 compare_list:
323 sigspec {
324 case_stack.back()->compare.push_back(*$1);
325 delete $1;
326 } |
327 compare_list ',' sigspec {
328 case_stack.back()->compare.push_back(*$3);
329 delete $3;
330 } |
331 /* empty */;
332
333 case_body:
334 case_body attr_stmt |
335 case_body switch_stmt |
336 case_body assign_stmt |
337 /* empty */;
338
339 assign_stmt:
340 TOK_ASSIGN sigspec sigspec EOL {
341 if (attrbuf.size() != 0)
342 rtlil_frontend_ilang_yyerror("dangling attribute");
343 case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
344 delete $2;
345 delete $3;
346 };
347
348 sync_list:
349 sync_list TOK_SYNC sync_type sigspec EOL {
350 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
351 rule->type = RTLIL::SyncType($3);
352 rule->signal = *$4;
353 current_process->syncs.push_back(rule);
354 delete $4;
355 } update_list |
356 sync_list TOK_SYNC TOK_ALWAYS EOL {
357 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
358 rule->type = RTLIL::SyncType::STa;
359 rule->signal = RTLIL::SigSpec();
360 current_process->syncs.push_back(rule);
361 } update_list |
362 sync_list TOK_SYNC TOK_GLOBAL EOL {
363 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
364 rule->type = RTLIL::SyncType::STg;
365 rule->signal = RTLIL::SigSpec();
366 current_process->syncs.push_back(rule);
367 } update_list |
368 sync_list TOK_SYNC TOK_INIT EOL {
369 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
370 rule->type = RTLIL::SyncType::STi;
371 rule->signal = RTLIL::SigSpec();
372 current_process->syncs.push_back(rule);
373 } update_list |
374 /* empty */;
375
376 sync_type:
377 TOK_LOW { $$ = RTLIL::ST0; } |
378 TOK_HIGH { $$ = RTLIL::ST1; } |
379 TOK_POSEDGE { $$ = RTLIL::STp; } |
380 TOK_NEGEDGE { $$ = RTLIL::STn; } |
381 TOK_EDGE { $$ = RTLIL::STe; };
382
383 update_list:
384 update_list TOK_UPDATE sigspec sigspec EOL {
385 current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4));
386 delete $3;
387 delete $4;
388 } |
389 /* empty */;
390
391 constant:
392 TOK_VALUE {
393 char *ep;
394 int width = strtol($1, &ep, 10);
395 std::list<RTLIL::State> bits;
396 while (*(++ep) != 0) {
397 RTLIL::State bit = RTLIL::Sx;
398 switch (*ep) {
399 case '0': bit = RTLIL::S0; break;
400 case '1': bit = RTLIL::S1; break;
401 case 'x': bit = RTLIL::Sx; break;
402 case 'z': bit = RTLIL::Sz; break;
403 case '-': bit = RTLIL::Sa; break;
404 case 'm': bit = RTLIL::Sm; break;
405 }
406 bits.push_front(bit);
407 }
408 if (bits.size() == 0)
409 bits.push_back(RTLIL::Sx);
410 while ((int)bits.size() < width) {
411 RTLIL::State bit = bits.back();
412 if (bit == RTLIL::S1)
413 bit = RTLIL::S0;
414 bits.push_back(bit);
415 }
416 while ((int)bits.size() > width)
417 bits.pop_back();
418 $$ = new RTLIL::Const;
419 for (auto it = bits.begin(); it != bits.end(); it++)
420 $$->bits.push_back(*it);
421 free($1);
422 } |
423 TOK_INT {
424 $$ = new RTLIL::Const($1, 32);
425 } |
426 TOK_STRING {
427 $$ = new RTLIL::Const($1);
428 free($1);
429 };
430
431 sigspec:
432 constant {
433 $$ = new RTLIL::SigSpec(*$1);
434 delete $1;
435 } |
436 TOK_ID {
437 if (current_module->wire($1) == nullptr)
438 rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
439 $$ = new RTLIL::SigSpec(current_module->wire($1));
440 free($1);
441 } |
442 sigspec '[' TOK_INT ']' {
443 if ($3 >= $1->size() || $3 < 0)
444 rtlil_frontend_ilang_yyerror("bit index out of range");
445 $$ = new RTLIL::SigSpec($1->extract($3));
446 delete $1;
447 } |
448 sigspec '[' TOK_INT ':' TOK_INT ']' {
449 if ($3 >= $1->size() || $3 < 0 || $3 < $5)
450 rtlil_frontend_ilang_yyerror("invalid slice");
451 $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1));
452 delete $1;
453 } |
454 '{' sigspec_list '}' {
455 $$ = $2;
456 };
457
458 sigspec_list_reversed:
459 sigspec_list_reversed sigspec {
460 $$->push_back(*$2);
461 delete $2;
462 } |
463 /* empty */ {
464 $$ = new std::vector<RTLIL::SigSpec>;
465 };
466
467 sigspec_list: sigspec_list_reversed {
468 $$ = new RTLIL::SigSpec;
469 for (auto it = $1->rbegin(); it != $1->rend(); it++)
470 $$->append(*it);
471 delete $1;
472 };
473
474 conn_stmt:
475 TOK_CONNECT sigspec sigspec EOL {
476 if (attrbuf.size() != 0)
477 rtlil_frontend_ilang_yyerror("dangling attribute");
478 current_module->connect(*$2, *$3);
479 delete $2;
480 delete $3;
481 };