| /* |
| * 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 (as generated by the 'ilang' backend). |
| * |
| */ |
| |
| %{ |
| #include <list> |
| #include "frontends/ilang/ilang_frontend.h" |
| YOSYS_NAMESPACE_BEGIN |
| namespace ILANG_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 ILANG_FRONTEND; |
| YOSYS_NAMESPACE_END |
| USING_YOSYS_NAMESPACE |
| %} |
| |
| %define api.prefix {rtlil_frontend_ilang_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/ilang/ilang_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_ilang_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("\\blackbox") && attrbuf.at("\\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("\\blackbox")) { |
| rtlil_frontend_ilang_yyerror(stringf("ilang 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("\\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_ilang_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 | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; |
| |
| param_stmt: |
| TOK_PARAMETER TOK_ID EOL { |
| current_module->avail_parameters.insert($2); |
| 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("$__ilang_frontend_tmp__"); |
| current_wire->attributes = attrbuf; |
| attrbuf.clear(); |
| } wire_options TOK_ID EOL { |
| if (current_module->wires_.count($4) != 0) |
| rtlil_frontend_ilang_yyerror(stringf("ilang 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_UPTO { |
| current_wire->upto = 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_ilang_yyerror(stringf("ilang 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->cells_.count($3) != 0) |
| rtlil_frontend_ilang_yyerror(stringf("ilang 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_ilang_yyerror(stringf("ilang 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_ilang_yyerror(stringf("ilang 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_ilang_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->wires_.count($1) == 0) |
| rtlil_frontend_ilang_yyerror(stringf("ilang error: wire %s not found", $1).c_str()); |
| $$ = new RTLIL::SigSpec(current_module->wires_[$1]); |
| free($1); |
| } | |
| sigspec '[' TOK_INT ']' { |
| $$ = new RTLIL::SigSpec($1->extract($3)); |
| delete $1; |
| } | |
| sigspec '[' TOK_INT ':' TOK_INT ']' { |
| $$ = 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_ilang_yyerror("dangling attribute"); |
| current_module->connect(*$2, *$3); |
| delete $2; |
| delete $3; |
| }; |