diff options
Diffstat (limited to 'frontends/rtlil/rtlil_parser.y')
-rw-r--r-- | frontends/rtlil/rtlil_parser.y | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y new file mode 100644 index 000000000..646489196 --- /dev/null +++ b/frontends/rtlil/rtlil_parser.y @@ -0,0 +1,484 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * --- + * + * A very simple and straightforward frontend for the RTLIL text + * representation. + * + */ + +%{ +#include <list> +#include "frontends/rtlil/rtlil_frontend.h" +YOSYS_NAMESPACE_BEGIN +namespace RTLIL_FRONTEND { + std::istream *lexin; + RTLIL::Design *current_design; + RTLIL::Module *current_module; + RTLIL::Wire *current_wire; + RTLIL::Memory *current_memory; + RTLIL::Cell *current_cell; + RTLIL::Process *current_process; + std::vector<std::vector<RTLIL::SwitchRule*>*> switch_stack; + std::vector<RTLIL::CaseRule*> case_stack; + dict<RTLIL::IdString, RTLIL::Const> attrbuf; + bool flag_nooverwrite, flag_overwrite, flag_lib; + bool delete_current_module; +} +using namespace RTLIL_FRONTEND; +YOSYS_NAMESPACE_END +USING_YOSYS_NAMESPACE +%} + +%define api.prefix {rtlil_frontend_yy} + +/* The union is defined in the header, so we need to provide all the + * includes it requires + */ +%code requires { +#include <string> +#include <vector> +#include "frontends/rtlil/rtlil_frontend.h" +} + +%union { + char *string; + int integer; + YOSYS_NAMESPACE_PREFIX RTLIL::Const *data; + YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec *sigspec; + std::vector<YOSYS_NAMESPACE_PREFIX RTLIL::SigSpec> *rsigspec; +} + +%token <string> TOK_ID TOK_VALUE TOK_STRING +%token <integer> TOK_INT +%token TOK_AUTOIDX TOK_MODULE TOK_WIRE TOK_WIDTH TOK_INPUT TOK_OUTPUT TOK_INOUT +%token TOK_CELL TOK_CONNECT TOK_SWITCH TOK_CASE TOK_ASSIGN TOK_SYNC +%token TOK_LOW TOK_HIGH TOK_POSEDGE TOK_NEGEDGE TOK_EDGE TOK_ALWAYS TOK_GLOBAL TOK_INIT +%token TOK_UPDATE TOK_PROCESS TOK_END TOK_INVALID TOK_EOL TOK_OFFSET +%token TOK_PARAMETER TOK_ATTRIBUTE TOK_MEMORY TOK_SIZE TOK_SIGNED TOK_REAL TOK_UPTO + +%type <rsigspec> sigspec_list_reversed +%type <sigspec> sigspec sigspec_list +%type <integer> sync_type +%type <data> constant + +%expect 0 +%debug + +%% + +input: + optional_eol { + attrbuf.clear(); + } design { + if (attrbuf.size() != 0) + rtlil_frontend_yyerror("dangling attribute"); + }; + +EOL: + optional_eol TOK_EOL; + +optional_eol: + optional_eol TOK_EOL | /* empty */; + +design: + design module | + design attr_stmt | + design autoidx_stmt | + /* empty */; + +module: + TOK_MODULE TOK_ID EOL { + delete_current_module = false; + if (current_design->has($2)) { + RTLIL::Module *existing_mod = current_design->module($2); + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { + log("Ignoring blackbox re-definition of module %s.\n", $2); + delete_current_module = true; + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of module %s.", $2).c_str()); + } else if (flag_nooverwrite) { + log("Ignoring re-definition of module %s.\n", $2); + delete_current_module = true; + } else { + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); + current_design->remove(existing_mod); + } + } + current_module = new RTLIL::Module; + current_module->name = $2; + current_module->attributes = attrbuf; + if (!delete_current_module) + current_design->add(current_module); + attrbuf.clear(); + free($2); + } module_body TOK_END { + if (attrbuf.size() != 0) + rtlil_frontend_yyerror("dangling attribute"); + current_module->fixup_ports(); + if (delete_current_module) + delete current_module; + else if (flag_lib) + current_module->makeblackbox(); + current_module = nullptr; + } EOL; + +module_body: + module_body module_stmt | + /* empty */; + +module_stmt: + param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; + +param_stmt: + TOK_PARAMETER TOK_ID EOL { + current_module->avail_parameters($2); + free($2); + }; + +param_defval_stmt: + TOK_PARAMETER TOK_ID constant EOL { + current_module->avail_parameters($2); + current_module->parameter_default_values[$2] = *$3; + free($2); + }; + +attr_stmt: + TOK_ATTRIBUTE TOK_ID constant EOL { + attrbuf[$2] = *$3; + delete $3; + free($2); + }; + +autoidx_stmt: + TOK_AUTOIDX TOK_INT EOL { + autoidx = max(autoidx, $2); + }; + +wire_stmt: + TOK_WIRE { + current_wire = current_module->addWire("$__rtlil_frontend_tmp__"); + current_wire->attributes = attrbuf; + attrbuf.clear(); + } wire_options TOK_ID EOL { + if (current_module->wire($4) != nullptr) + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of wire %s.", $4).c_str()); + current_module->rename(current_wire, $4); + free($4); + }; + +wire_options: + wire_options TOK_WIDTH TOK_INT { + current_wire->width = $3; + } | + wire_options TOK_WIDTH TOK_INVALID { + rtlil_frontend_yyerror("RTLIL error: invalid wire width"); + } | + wire_options TOK_UPTO { + current_wire->upto = true; + } | + wire_options TOK_SIGNED { + current_wire->is_signed = true; + } | + wire_options TOK_OFFSET TOK_INT { + current_wire->start_offset = $3; + } | + wire_options TOK_INPUT TOK_INT { + current_wire->port_id = $3; + current_wire->port_input = true; + current_wire->port_output = false; + } | + wire_options TOK_OUTPUT TOK_INT { + current_wire->port_id = $3; + current_wire->port_input = false; + current_wire->port_output = true; + } | + wire_options TOK_INOUT TOK_INT { + current_wire->port_id = $3; + current_wire->port_input = true; + current_wire->port_output = true; + } | + /* empty */; + +memory_stmt: + TOK_MEMORY { + current_memory = new RTLIL::Memory; + current_memory->attributes = attrbuf; + attrbuf.clear(); + } memory_options TOK_ID EOL { + if (current_module->memories.count($4) != 0) + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of memory %s.", $4).c_str()); + current_memory->name = $4; + current_module->memories[$4] = current_memory; + free($4); + }; + +memory_options: + memory_options TOK_WIDTH TOK_INT { + current_memory->width = $3; + } | + memory_options TOK_SIZE TOK_INT { + current_memory->size = $3; + } | + memory_options TOK_OFFSET TOK_INT { + current_memory->start_offset = $3; + } | + /* empty */; + +cell_stmt: + TOK_CELL TOK_ID TOK_ID EOL { + if (current_module->cell($3) != nullptr) + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell %s.", $3).c_str()); + current_cell = current_module->addCell($3, $2); + current_cell->attributes = attrbuf; + attrbuf.clear(); + free($2); + free($3); + } cell_body TOK_END EOL; + +cell_body: + cell_body TOK_PARAMETER TOK_ID constant EOL { + current_cell->parameters[$3] = *$4; + free($3); + delete $4; + } | + cell_body TOK_PARAMETER TOK_SIGNED TOK_ID constant EOL { + current_cell->parameters[$4] = *$5; + current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_SIGNED; + free($4); + delete $5; + } | + cell_body TOK_PARAMETER TOK_REAL TOK_ID constant EOL { + current_cell->parameters[$4] = *$5; + current_cell->parameters[$4].flags |= RTLIL::CONST_FLAG_REAL; + free($4); + delete $5; + } | + cell_body TOK_CONNECT TOK_ID sigspec EOL { + if (current_cell->hasPort($3)) + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of cell port %s.", $3).c_str()); + current_cell->setPort($3, *$4); + delete $4; + free($3); + } | + /* empty */; + +proc_stmt: + TOK_PROCESS TOK_ID EOL { + if (current_module->processes.count($2) != 0) + rtlil_frontend_yyerror(stringf("RTLIL error: redefinition of process %s.", $2).c_str()); + current_process = new RTLIL::Process; + current_process->name = $2; + current_process->attributes = attrbuf; + current_module->processes[$2] = current_process; + switch_stack.clear(); + switch_stack.push_back(¤t_process->root_case.switches); + case_stack.clear(); + case_stack.push_back(¤t_process->root_case); + attrbuf.clear(); + free($2); + } case_body sync_list TOK_END EOL; + +switch_stmt: + TOK_SWITCH sigspec EOL { + RTLIL::SwitchRule *rule = new RTLIL::SwitchRule; + rule->signal = *$2; + rule->attributes = attrbuf; + switch_stack.back()->push_back(rule); + attrbuf.clear(); + delete $2; + } attr_list switch_body TOK_END EOL; + +attr_list: + /* empty */ | + attr_list attr_stmt; + +switch_body: + switch_body TOK_CASE { + RTLIL::CaseRule *rule = new RTLIL::CaseRule; + rule->attributes = attrbuf; + switch_stack.back()->back()->cases.push_back(rule); + switch_stack.push_back(&rule->switches); + case_stack.push_back(rule); + attrbuf.clear(); + } compare_list EOL case_body { + switch_stack.pop_back(); + case_stack.pop_back(); + } | + /* empty */; + +compare_list: + sigspec { + case_stack.back()->compare.push_back(*$1); + delete $1; + } | + compare_list ',' sigspec { + case_stack.back()->compare.push_back(*$3); + delete $3; + } | + /* empty */; + +case_body: + case_body attr_stmt | + case_body switch_stmt | + case_body assign_stmt | + /* empty */; + +assign_stmt: + TOK_ASSIGN sigspec sigspec EOL { + if (attrbuf.size() != 0) + rtlil_frontend_yyerror("dangling attribute"); + case_stack.back()->actions.push_back(RTLIL::SigSig(*$2, *$3)); + delete $2; + delete $3; + }; + +sync_list: + sync_list TOK_SYNC sync_type sigspec EOL { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + rule->type = RTLIL::SyncType($3); + rule->signal = *$4; + current_process->syncs.push_back(rule); + delete $4; + } update_list | + sync_list TOK_SYNC TOK_ALWAYS EOL { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + rule->type = RTLIL::SyncType::STa; + rule->signal = RTLIL::SigSpec(); + current_process->syncs.push_back(rule); + } update_list | + sync_list TOK_SYNC TOK_GLOBAL EOL { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + rule->type = RTLIL::SyncType::STg; + rule->signal = RTLIL::SigSpec(); + current_process->syncs.push_back(rule); + } update_list | + sync_list TOK_SYNC TOK_INIT EOL { + RTLIL::SyncRule *rule = new RTLIL::SyncRule; + rule->type = RTLIL::SyncType::STi; + rule->signal = RTLIL::SigSpec(); + current_process->syncs.push_back(rule); + } update_list | + /* empty */; + +sync_type: + TOK_LOW { $$ = RTLIL::ST0; } | + TOK_HIGH { $$ = RTLIL::ST1; } | + TOK_POSEDGE { $$ = RTLIL::STp; } | + TOK_NEGEDGE { $$ = RTLIL::STn; } | + TOK_EDGE { $$ = RTLIL::STe; }; + +update_list: + update_list TOK_UPDATE sigspec sigspec EOL { + current_process->syncs.back()->actions.push_back(RTLIL::SigSig(*$3, *$4)); + delete $3; + delete $4; + } | + /* empty */; + +constant: + TOK_VALUE { + char *ep; + int width = strtol($1, &ep, 10); + std::list<RTLIL::State> bits; + while (*(++ep) != 0) { + RTLIL::State bit = RTLIL::Sx; + switch (*ep) { + case '0': bit = RTLIL::S0; break; + case '1': bit = RTLIL::S1; break; + case 'x': bit = RTLIL::Sx; break; + case 'z': bit = RTLIL::Sz; break; + case '-': bit = RTLIL::Sa; break; + case 'm': bit = RTLIL::Sm; break; + } + bits.push_front(bit); + } + if (bits.size() == 0) + bits.push_back(RTLIL::Sx); + while ((int)bits.size() < width) { + RTLIL::State bit = bits.back(); + if (bit == RTLIL::S1) + bit = RTLIL::S0; + bits.push_back(bit); + } + while ((int)bits.size() > width) + bits.pop_back(); + $$ = new RTLIL::Const; + for (auto it = bits.begin(); it != bits.end(); it++) + $$->bits.push_back(*it); + free($1); + } | + TOK_INT { + $$ = new RTLIL::Const($1, 32); + } | + TOK_STRING { + $$ = new RTLIL::Const($1); + free($1); + }; + +sigspec: + constant { + $$ = new RTLIL::SigSpec(*$1); + delete $1; + } | + TOK_ID { + if (current_module->wire($1) == nullptr) + rtlil_frontend_yyerror(stringf("RTLIL error: wire %s not found", $1).c_str()); + $$ = new RTLIL::SigSpec(current_module->wire($1)); + free($1); + } | + sigspec '[' TOK_INT ']' { + if ($3 >= $1->size() || $3 < 0) + rtlil_frontend_yyerror("bit index out of range"); + $$ = new RTLIL::SigSpec($1->extract($3)); + delete $1; + } | + sigspec '[' TOK_INT ':' TOK_INT ']' { + if ($3 >= $1->size() || $3 < 0 || $3 < $5) + rtlil_frontend_yyerror("invalid slice"); + $$ = new RTLIL::SigSpec($1->extract($5, $3 - $5 + 1)); + delete $1; + } | + '{' sigspec_list '}' { + $$ = $2; + }; + +sigspec_list_reversed: + sigspec_list_reversed sigspec { + $$->push_back(*$2); + delete $2; + } | + /* empty */ { + $$ = new std::vector<RTLIL::SigSpec>; + }; + +sigspec_list: sigspec_list_reversed { + $$ = new RTLIL::SigSpec; + for (auto it = $1->rbegin(); it != $1->rend(); it++) + $$->append(*it); + delete $1; + }; + +conn_stmt: + TOK_CONNECT sigspec sigspec EOL { + if (attrbuf.size() != 0) + rtlil_frontend_yyerror("dangling attribute"); + current_module->connect(*$2, *$3); + delete $2; + delete $3; + }; |