ab763b2b175ddc95192eaa65a3a6d13a9ddfda79
[yosys.git] / frontends / 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 "ilang_frontend.h"
28 YOSYS_NAMESPACE_BEGIN
29 namespace ILANG_FRONTEND {
30 RTLIL::Design *current_design;
31 RTLIL::Module *current_module;
32 RTLIL::Wire *current_wire;
33 RTLIL::Memory *current_memory;
34 RTLIL::Cell *current_cell;
35 RTLIL::Process *current_process;
36 std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack;
37 std::vector<RTLIL::CaseRule*> case_stack;
38 std::map<RTLIL::IdString, RTLIL::Const> attrbuf;
39 }
40 using namespace ILANG_FRONTEND;
41 YOSYS_NAMESPACE_END
42 USING_YOSYS_NAMESPACE
43 %}
44
45 %name-prefix "rtlil_frontend_ilang_yy"
46
47 %union {
48 char *string;
49 int integer;
50 YOSYS_NAMESPACE_PREFIX RTLIL::Const *data;
51 YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec;
52 }
53
54 %token <string> TOK_ID TOK_VALUE TOK_STRING
55 %token <integer> TOK_INT
56 %token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT
57 %token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC
58 %token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_INIT
59 %token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET
60 %token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_UPTO
61
62 %type <sigspec> sigspec sigspec_list
63 %type <integer> sync_type
64 %type <data> constant
65
66 %expect 0
67 %debug
68
69 %%
70
71 input:
72 optional_eol {
73 attrbuf.clear();
74 } design {
75 if (attrbuf.size() != 0)
76 rtlil_frontend_ilang_yyerror("dangling attribute");
77 };
78
79 EOL:
80 optional_eol TOK_EOL;
81
82 optional_eol:
83 optional_eol TOK_EOL | /* empty */;
84
85 design:
86 design module |
87 design attr_stmt |
88 design autoidx_stmt |
89 /* empty */;
90
91 module:
92 TOK_MODULE TOK_ID EOL {
93 if (current_design->modules_.count($2) != 0)
94 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str());
95 current_module = new RTLIL::Module;
96 current_module->name = $2;
97 current_module->attributes = attrbuf;
98 current_design->modules_[$2] = current_module;
99 attrbuf.clear();
100 free($2);
101 } module_body TOK_END {
102 if (attrbuf.size() != 0)
103 rtlil_frontend_ilang_yyerror("dangling attribute");
104 } EOL;
105
106 module_body:
107 module_body module_stmt |
108 /* empty */;
109
110 module_stmt:
111 attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt;
112
113 attr_stmt:
114 TOK_ATTRIBUTE TOK_ID constant EOL {
115 attrbuf[$2] = *$3;
116 delete $3;
117 free($2);
118 };
119
120 autoidx_stmt:
121 TOK_AUTOIDX TOK_INT EOL {
122 autoidx = std::max(autoidx, $2);
123 };
124
125 wire_stmt:
126 TOK_WIRE {
127 current_wire = current_module->addWire("$__ilang_frontend_tmp__");
128 current_wire->attributes = attrbuf;
129 attrbuf.clear();
130 } wire_options TOK_ID EOL {
131 if (current_module->wires_.count($4) != 0)
132 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of wire %s.", $4).c_str());
133 current_module->rename(current_wire, $4);
134 free($4);
135 };
136
137 wire_options:
138 wire_options TOK_WIDTH TOK_INT {
139 current_wire->width = $3;
140 } |
141 wire_options TOK_UPTO {
142 current_wire->upto = true;
143 } |
144 wire_options TOK_OFFSET TOK_INT {
145 current_wire->start_offset = $3;
146 } |
147 wire_options TOK_INPUT TOK_INT {
148 current_wire->port_id = $3;
149 current_wire->port_input = true;
150 current_wire->port_output = false;
151 } |
152 wire_options TOK_OUTPUT TOK_INT {
153 current_wire->port_id = $3;
154 current_wire->port_input = false;
155 current_wire->port_output = true;
156 } |
157 wire_options TOK_INOUT TOK_INT {
158 current_wire->port_id = $3;
159 current_wire->port_input = true;
160 current_wire->port_output = true;
161 } |
162 /* empty */;
163
164 memory_stmt:
165 TOK_MEMORY {
166 current_memory = new RTLIL::Memory;
167 current_memory->attributes = attrbuf;
168 attrbuf.clear();
169 } memory_options TOK_ID EOL {
170 if (current_module->memories.count($4) != 0)
171 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of memory %s.", $4).c_str());
172 current_memory->name = $4;
173 current_module->memories[$4] = current_memory;
174 free($4);
175 };
176
177 memory_options:
178 memory_options TOK_WIDTH TOK_INT {
179 current_memory->width = $3;
180 } |
181 memory_options TOK_SIZE TOK_INT {
182 current_memory->size = $3;
183 } |
184 /* empty */;
185
186 cell_stmt:
187 TOK_CELL TOK_ID TOK_ID EOL {
188 if (current_module->cells_.count($3) != 0)
189 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell %s.", $3).c_str());
190 current_cell = current_module->addCell($3, $2);
191 current_cell->attributes = attrbuf;
192 attrbuf.clear();
193 free($2);
194 free($3);
195 } cell_body TOK_END EOL;
196
197 cell_body:
198 cell_body TOK_PARAMETER TOK_ID constant EOL {
199 current_cell->parameters[$3] = *$4;
200 free($3);
201 delete $4;
202 } |
203 cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL {
204 current_cell->parameters[$4] = *$5;
205 current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED;
206 free($4);
207 delete $5;
208 } |
209 cell_body TOK_CONNECT TOK_ID sigspec EOL {
210 if (current_cell->has($3))
211 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of cell port %s.", $3).c_str());
212 current_cell->set($3, *$4);
213 delete $4;
214 free($3);
215 } |
216 /* empty */;
217
218 proc_stmt:
219 TOK_PROCESS TOK_ID EOL {
220 if (current_module->processes.count($2) != 0)
221 rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of process %s.", $2).c_str());
222 current_process = new RTLIL::Process;
223 current_process->name = $2;
224 current_process->attributes = attrbuf;
225 current_module->processes[$2] = current_process;
226 switch_stack.clear();
227 switch_stack.push_back(&current_process->root_case.switches);
228 case_stack.clear();
229 case_stack.push_back(&current_process->root_case);
230 attrbuf.clear();
231 free($2);
232 } case_body sync_list TOK_END EOL;
233
234 switch_stmt:
235 attr_list TOK_SWITCH sigspec EOL {
236 RTLIL::SwitchRule *rule = new RTLIL::SwitchRule;
237 rule->signal = *$3;
238 rule->attributes = attrbuf;
239 switch_stack.back()->push_back(rule);
240 attrbuf.clear();
241 delete $3;
242 } switch_body TOK_END EOL;
243
244 attr_list:
245 /* empty */ |
246 attr_list attr_stmt;
247
248 switch_body:
249 switch_body TOK_CASE {
250 RTLIL::CaseRule *rule = new RTLIL::CaseRule;
251 switch_stack.back()->back()->cases.push_back(rule);
252 switch_stack.push_back(&rule->switches);
253 case_stack.push_back(rule);
254 } compare_list EOL case_body {
255 switch_stack.pop_back();
256 case_stack.pop_back();
257 } |
258 /* empty */;
259
260 compare_list:
261 sigspec {
262 case_stack.back()->compare.push_back(*$1);
263 delete $1;
264 } |
265 compare_list ',' sigspec {
266 case_stack.back()->compare.push_back(*$3);
267 delete $3;
268 } |
269 /* empty */;
270
271 case_body:
272 switch_stmt case_body |
273 assign_stmt case_body |
274 /* empty */;
275
276 assign_stmt:
277 TOK_ASSIGN sigspec sigspec EOL {
278 case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3));
279 delete $2;
280 delete $3;
281 };
282
283 sync_list:
284 sync_list TOK_SYNC sync_type sigspec EOL {
285 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
286 rule->type = RTLIL::SyncType($3);
287 rule->signal = *$4;
288 current_process->syncs.push_back(rule);
289 delete $4;
290 } update_list |
291 sync_list TOK_SYNC TOK_ALWAYS EOL {
292 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
293 rule->type = RTLIL::SyncType::STa;
294 rule->signal = RTLIL::SigSpec();
295 current_process->syncs.push_back(rule);
296 } update_list |
297 sync_list TOK_SYNC TOK_INIT EOL {
298 RTLIL::SyncRule *rule = new RTLIL::SyncRule;
299 rule->type = RTLIL::SyncType::STi;
300 rule->signal = RTLIL::SigSpec();
301 current_process->syncs.push_back(rule);
302 } update_list |
303 /* empty */;
304
305 sync_type:
306 TOK_LOW { $$ = RTLIL::ST0; } |
307 TOK_HIGH { $$ = RTLIL::ST1; } |
308 TOK_POSEDGE { $$ = RTLIL::STp; } |
309 TOK_NEGEDGE { $$ = RTLIL::STn; } |
310 TOK_EDGE { $$ = RTLIL::STe; };
311
312 update_list:
313 update_list TOK_UPDATE sigspec sigspec EOL {
314 current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4));
315 delete $3;
316 delete $4;
317 } |
318 /* empty */;
319
320 constant:
321 TOK_VALUE {
322 char *ep;
323 int width = strtol($1, &ep, 10);
324 std::list<RTLIL::State> bits;
325 while (*(++ep) != 0) {
326 RTLIL::State bit = RTLIL::Sx;
327 switch (*ep) {
328 case '0': bit = RTLIL::S0; break;
329 case '1': bit = RTLIL::S1; break;
330 case 'x': bit = RTLIL::Sx; break;
331 case 'z': bit = RTLIL::Sz; break;
332 case '-': bit = RTLIL::Sa; break;
333 case 'm': bit = RTLIL::Sm; break;
334 }
335 bits.push_front(bit);
336 }
337 if (bits.size() == 0)
338 bits.push_back(RTLIL::Sx);
339 while ((int)bits.size() < width) {
340 RTLIL::State bit = bits.back();
341 if (bit == RTLIL::S1)
342 bit = RTLIL::S0;
343 bits.push_back(bit);
344 }
345 while ((int)bits.size() > width)
346 bits.pop_back();
347 $$ = new RTLIL::Const;
348 for (auto it = bits.begin(); it != bits.end(); it++)
349 $$->bits.push_back(*it);
350 free($1);
351 } |
352 TOK_INT {
353 $$ = new RTLIL::Const($1, 32);
354 } |
355 TOK_STRING {
356 $$ = new RTLIL::Const($1);
357 free($1);
358 };
359
360 sigspec:
361 constant {
362 $$ = new RTLIL::SigSpec(*$1);
363 delete $1;
364 } |
365 TOK_ID {
366 if (current_module->wires_.count($1) == 0)
367 rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
368 $$ = new RTLIL::SigSpec(current_module->wires_[$1]);
369 free($1);
370 } |
371 TOK_ID '[' TOK_INT ']' {
372 if (current_module->wires_.count($1) == 0)
373 rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
374 $$ = new RTLIL::SigSpec(current_module->wires_[$1], $3);
375 free($1);
376 } |
377 TOK_ID '[' TOK_INT ':' TOK_INT ']' {
378 if (current_module->wires_.count($1) == 0)
379 rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str());
380 $$ = new RTLIL::SigSpec(current_module->wires_[$1], $5, $3 - $5 + 1);
381 free($1);
382 } |
383 '{' sigspec_list '}' {
384 $$ = $2;
385 };
386
387 sigspec_list:
388 sigspec_list sigspec {
389 $$ = new RTLIL::SigSpec;
390 $$->append(*$2);
391 $$->append(*$1);
392 delete $1;
393 delete $2;
394 } |
395 /* empty */ {
396 $$ = new RTLIL::SigSpec;
397 };
398
399 conn_stmt:
400 TOK_CONNECT sigspec sigspec EOL {
401 if (attrbuf.size() != 0)
402 rtlil_frontend_ilang_yyerror("dangling attribute");
403 current_module->connect(*$2, *$3);
404 delete $2;
405 delete $3;
406 };
407