From d738b2c1272b02d8799e9feda83b1eae8ba10c07 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 2 Mar 2021 10:43:53 -0500 Subject: sv: support for parameters without default values - Modules with a parameter without a default value will be automatically deferred until the hierarchy pass - Allows for parameters without defaults as module items, rather than just int the `parameter_port_list`, despite being forbidden in the LRM - Check for parameters without defaults that haven't been overriden - Add location info to parameter/localparam declarations --- frontends/ast/ast.cc | 29 +++++++++++++++++++++++++++-- frontends/verilog/verilog_parser.y | 24 +++++++++++++++++++++--- 2 files changed, 48 insertions(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 57552d86c..7fb61bb34 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -968,6 +968,14 @@ void AST::set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast) obj->attributes[ID::src] = ast->loc_string(); } +static bool param_has_no_default(const AstNode *param) { + const auto &children = param->children; + log_assert(param->type == AST_PARAMETER); + log_assert(children.size() <= 2); + return children.empty() || + (children.size() == 1 && children[0]->type == AST_RANGE); +} + // create a new AstModule from an AST_MODULE AST node static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) { @@ -1006,6 +1014,10 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast if (!defer) { + for (const AstNode *node : ast->children) + if (node->type == AST_PARAMETER && param_has_no_default(node)) + log_file_error(node->filename, node->location.first_line, "Parameter `%s' has no default value and has not been overridden!\n", node->str.c_str()); + bool blackbox_module = flag_lib; if (!blackbox_module && !flag_noblackbox) { @@ -1229,7 +1241,18 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump if (flag_icells && (*it)->str.compare(0, 2, "\\$") == 0) (*it)->str = (*it)->str.substr(1); - if (defer) + bool defer_local = defer; + if (!defer_local) + for (const AstNode *node : (*it)->children) + if (node->type == AST_PARAMETER && param_has_no_default(node)) + { + log("Deferring `%s' because it contains parameter(s) without defaults.\n", ast->str.c_str()); + defer_local = true; + break; + } + + + if (defer_local) (*it)->str = "$abstract" + (*it)->str; if (design->has((*it)->str)) { @@ -1248,7 +1271,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } } - design->add(process_module(*it, defer)); + design->add(process_module(*it, defer_local)); current_ast_mod = nullptr; } else if ((*it)->type == AST_PACKAGE) { @@ -1619,6 +1642,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictchildren.insert(child->children.begin(), nullptr); delete child->children.at(0); if ((it->second.flags & RTLIL::CONST_FLAG_REAL) != 0) { child->children[0] = new AstNode(AST_REALVALUE); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index bcba9b76a..ea8cc0765 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1462,7 +1462,26 @@ param_decl_list: single_param_decl | param_decl_list ',' single_param_decl; single_param_decl: - TOK_ID '=' expr { + single_param_decl_ident '=' expr { + AstNode *decl = ast_stack.back()->children.back(); + log_assert(decl->type == AST_PARAMETER || decl->type == AST_LOCALPARAM); + delete decl->children[0]; + decl->children[0] = $3; + } | + single_param_decl_ident { + AstNode *decl = ast_stack.back()->children.back(); + if (decl->type != AST_PARAMETER) { + log_assert(decl->type == AST_LOCALPARAM); + frontend_verilog_yyerror("localparam initialization is missing!"); + } + if (!sv_mode) + frontend_verilog_yyerror("Parameter defaults can only be omitted in SystemVerilog mode!"); + delete decl->children[0]; + decl->children.erase(decl->children.begin()); + }; + +single_param_decl_ident: + TOK_ID { AstNode *node; if (astbuf1 == nullptr) { if (!sv_mode) @@ -1473,10 +1492,9 @@ single_param_decl: node = astbuf1->clone(); } node->str = *$1; - delete node->children[0]; - node->children[0] = $3; ast_stack.back()->children.push_back(node); delete $1; + SET_AST_NODE_LOC(node, @1, @1); }; defparam_decl: -- cgit v1.2.3 From 6c56c083f8c55d28a3dc0dc8e17a611fd31a2261 Mon Sep 17 00:00:00 2001 From: Claire Xen Date: Thu, 4 Mar 2021 16:43:30 +0100 Subject: Update README --- frontends/verific/README | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/README b/frontends/verific/README index c37d76343..952fb1e0c 100644 --- a/frontends/verific/README +++ b/frontends/verific/README @@ -1,11 +1,11 @@ This directory contains Verific bindings for Yosys. -Use Symbiotic EDA Suite if you need Yosys+Verifc. -https://www.symbioticeda.com/seda-suite +Use Tabby CAD Suite from YosysHQ if you need Yosys+Verifc. +https://www.yosyshq.com/ -Contact office@symbioticeda.com for free evaluation -binaries of Symbiotic EDA Suite. +Contact YosysHQ at contact@yosyshq.com for free evaluation +binaries of Tabby CAD Suite. Verific Features that should be enabled in your Verific library -- cgit v1.2.3 From c18ddbcd822410095d28c4be1c3ac3c6358622d2 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 4 Mar 2021 15:08:16 -0500 Subject: verilog: impose limit on maximum expression width Designs with unreasonably wide expressions would previously get stuck allocating memory forever. --- frontends/ast/genrtlil.cc | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index d4299bf69..e0a522430 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1000,6 +1000,12 @@ void AstNode::detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real if (found_real) *found_real = false; detectSignWidthWorker(width_hint, sign_hint, found_real); + + constexpr int kWidthLimit = 1 << 24; + if (width_hint >= kWidthLimit) + log_file_error(filename, location.first_line, + "Expression width %d exceeds implementation limit of %d!\n", + width_hint, kWidthLimit); } static void check_unique_id(RTLIL::Module *module, RTLIL::IdString id, -- cgit v1.2.3 From b1a8e73a609d3065f1caf7a230529443b54295bc Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 3 Mar 2021 14:36:19 -0500 Subject: sv: fix some edge cases for unbased unsized literals - Fix explicit size cast of unbased unsized literals - Fix unbased unsized literal bound directly to port - Output `is_unsized` flag in `dumpAst` --- frontends/ast/ast.cc | 2 ++ frontends/ast/simplify.cc | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 57552d86c..88e6aa1c9 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -317,6 +317,8 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " reg"); if (is_signed) fprintf(f, " signed"); + if (is_unsized) + fprintf(f, " unsized"); if (basic_prep) fprintf(f, " basic_prep"); if (lookahead) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5c4dd290f..e7f897b3c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -915,6 +915,22 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + if (type == AST_ARGUMENT) + { + if (children.size() == 1 && children[0]->type == AST_CONSTANT) + { + // HACK: For port bindings using unbased unsized literals, mark them + // signed so they sign-extend. The hierarchy will still incorrectly + // generate a warning complaining about resizing the expression. + // This also doesn't handle the complex of something like a ternary + // expression bound to a port, where the actual size of the port is + // needed to resolve the expression correctly. + AstNode *arg = children[0]; + if (arg->is_unsized) + arg->is_signed = true; + } + } + int backup_width_hint = width_hint; bool backup_sign_hint = sign_hint; @@ -3773,7 +3789,11 @@ replace_fcall_later:; case AST_CAST_SIZE: if (children.at(0)->type == AST_CONSTANT && children.at(1)->type == AST_CONSTANT) { int width = children[0]->bitsAsConst().as_int(); - RTLIL::Const val = children[1]->bitsAsConst(width); + RTLIL::Const val; + if (children[1]->is_unsized) + val = children[1]->bitsAsUnsizedConst(width); + else + val = children[1]->bitsAsConst(width); newNode = mkconst_bits(val.bits, children[1]->is_signed); } break; -- cgit v1.2.3 From bdc4fd0e92913961c6e3728d8d4976022514dc23 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sun, 7 Mar 2021 16:06:25 -0500 Subject: Fix param without default log line --- frontends/ast/ast.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index af5e326ad..0cfde0fc3 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1248,7 +1248,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump for (const AstNode *node : (*it)->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) { - log("Deferring `%s' because it contains parameter(s) without defaults.\n", ast->str.c_str()); + log("Deferring `%s' because it contains parameter(s) without defaults.\n", (*it)->str.c_str()); defer_local = true; break; } -- cgit v1.2.3 From 4e03865d5bf3fafe0bd3735c88431675d53d2663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 23 Feb 2021 00:21:46 +0100 Subject: Add support for memory writes in processes. --- frontends/rtlil/rtlil_lexer.l | 1 + frontends/rtlil/rtlil_parser.y | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l index beef220f6..897ebf667 100644 --- a/frontends/rtlil/rtlil_lexer.l +++ b/frontends/rtlil/rtlil_lexer.l @@ -79,6 +79,7 @@ USING_YOSYS_NAMESPACE "global" { return TOK_GLOBAL; } "init" { return TOK_INIT; } "update" { return TOK_UPDATE; } +"memwr" { return TOK_MEMWR; } "process" { return TOK_PROCESS; } "end" { return TOK_END; } diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y index 646489196..7a8f508bf 100644 --- a/frontends/rtlil/rtlil_parser.y +++ b/frontends/rtlil/rtlil_parser.y @@ -69,7 +69,7 @@ USING_YOSYS_NAMESPACE %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_UPDATE TOK_MEMWR 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 sigspec_list_reversed @@ -155,6 +155,7 @@ param_defval_stmt: TOK_PARAMETER TOK_ID constant EOL { current_module->avail_parameters($2); current_module->parameter_default_values[$2] = *$3; + delete $3; free($2); }; @@ -389,6 +390,22 @@ update_list: delete $3; delete $4; } | + update_list attr_list TOK_MEMWR TOK_ID sigspec sigspec sigspec constant EOL { + RTLIL::MemWriteAction act; + act.attributes = attrbuf; + act.memid = $4; + act.address = *$5; + act.data = *$6; + act.enable = *$7; + act.priority_mask = *$8; + current_process->syncs.back()->mem_write_actions.push_back(std::move(act)); + attrbuf.clear(); + free($4); + delete $5; + delete $6; + delete $7; + delete $8; + } | /* empty */; constant: -- cgit v1.2.3 From 89c74ffd7189d4898feb476ff70376385d516eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 23 Feb 2021 16:48:29 +0100 Subject: verilog: Use proc memory writes in the frontend. --- frontends/ast/ast.cc | 2 ++ frontends/ast/ast.h | 2 ++ frontends/ast/genrtlil.cc | 56 ++++++++++++++++++++++++++++++--------------- frontends/ast/simplify.cc | 58 ++++++++++++++++++++++++++++++++++++++--------- 4 files changed, 89 insertions(+), 29 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index af5e326ad..3b6319071 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -54,6 +54,8 @@ namespace AST_INTERNAL { AstNode *current_always, *current_top_block, *current_block, *current_block_child; AstModule *current_module; bool current_always_clocked; + dict current_memwr_count; + dict> current_memwr_visible; } // convert node types to string diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 1c9a6ee47..1447bf568 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -381,6 +381,8 @@ namespace AST_INTERNAL extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; extern AST::AstModule *current_module; extern bool current_always_clocked; + extern dict current_memwr_count; + extern dict> current_memwr_visible; struct LookaheadRewriter; struct ProcessGenerator; } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index e0a522430..ad5814f1b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -399,6 +399,9 @@ struct AST_INTERNAL::ProcessGenerator if (child->type == AST_BLOCK) processAst(child); + for (auto sync: proc->syncs) + processMemWrites(sync); + if (initSyncSignals.size() > 0) { RTLIL::SyncRule *sync = new RTLIL::SyncRule; @@ -698,6 +701,34 @@ struct AST_INTERNAL::ProcessGenerator log_abort(); } } + + void processMemWrites(RTLIL::SyncRule *sync) + { + // Maps per-memid AST_MEMWR IDs to indices in the mem_write_actions array. + dict, int> port_map; + for (auto child : always->children) + if (child->type == AST_MEMWR) + { + std::string memid = child->str; + int portid = child->children[3]->asInt(false); + int cur_idx = GetSize(sync->mem_write_actions); + RTLIL::MemWriteAction action; + set_src_attr(&action, child); + action.memid = memid; + action.address = child->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); + action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, &subst_rvalue_map.stdmap()); + action.enable = child->children[2]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); + RTLIL::Const orig_priority_mask = child->children[4]->bitsAsConst(); + RTLIL::Const priority_mask = RTLIL::Const(0, cur_idx); + for (int i = 0; i < portid; i++) { + int new_bit = port_map[std::make_pair(memid, i)]; + priority_mask.bits[new_bit] = orig_priority_mask.bits[i]; + } + action.priority_mask = priority_mask; + sync->mem_write_actions.push_back(action); + port_map[std::make_pair(memid, portid)] = cur_idx; + } + } }; // detect sign and width of an expression @@ -1644,26 +1675,22 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) return RTLIL::SigSpec(wire); } - // generate $memwr cells for memory write ports - case AST_MEMWR: + // generate $meminit cells case AST_MEMINIT: { std::stringstream sstr; - sstr << (type == AST_MEMWR ? "$memwr$" : "$meminit$") << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + sstr << "$meminit$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), type == AST_MEMWR ? ID($memwr) : ID($meminit)); + RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($meminit)); set_src_attr(cell, this); int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); - int num_words = 1; - if (type == AST_MEMINIT) { - if (children[2]->type != AST_CONSTANT) - log_file_error(filename, location.first_line, "Memory init with non-constant word count!\n"); - num_words = int(children[2]->asInt(false)); - cell->parameters[ID::WORDS] = RTLIL::Const(num_words); - } + if (children[2]->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Memory init with non-constant word count!\n"); + int num_words = int(children[2]->asInt(false)); + cell->parameters[ID::WORDS] = RTLIL::Const(num_words); SigSpec addr_sig = children[0]->genRTLIL(); @@ -1674,13 +1701,6 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) cell->parameters[ID::ABITS] = RTLIL::Const(GetSize(addr_sig)); cell->parameters[ID::WIDTH] = RTLIL::Const(current_module->memories[str]->width); - if (type == AST_MEMWR) { - cell->setPort(ID::CLK, RTLIL::SigSpec(RTLIL::State::Sx, 1)); - cell->setPort(ID::EN, children[2]->genRTLIL()); - cell->parameters[ID::CLK_ENABLE] = RTLIL::Const(0); - cell->parameters[ID::CLK_POLARITY] = RTLIL::Const(0); - } - cell->parameters[ID::PRIORITY] = RTLIL::Const(autoidx-1); } break; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e7f897b3c..e0ac58f20 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1217,6 +1217,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } + dict> backup_memwr_visible; + dict> final_memwr_visible; + + if (type == AST_CASE && stage == 2) { + backup_memwr_visible = current_memwr_visible; + final_memwr_visible = current_memwr_visible; + } + // simplify all children first // (iterate by index as e.g. auto wires can add new children in the process) for (size_t i = 0; i < children.size(); i++) { @@ -1279,11 +1287,25 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } flag_autowire = backup_flag_autowire; unevaluated_tern_branch = backup_unevaluated_tern_branch; + if (stage == 2 && type == AST_CASE) { + for (auto &x : current_memwr_visible) { + for (int y : x.second) + final_memwr_visible[x.first].insert(y); + } + current_memwr_visible = backup_memwr_visible; + } } for (auto &attr : attributes) { while (attr.second->simplify(true, false, false, stage, -1, false, true)) did_something = true; } + if (type == AST_CASE && stage == 2) { + current_memwr_visible = final_memwr_visible; + } + if (type == AST_ALWAYS && stage == 2) { + current_memwr_visible.clear(); + current_memwr_count.clear(); + } if (reset_width_after_children) { width_hint = backup_width_hint; @@ -2570,12 +2592,12 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_addr->str] = wire_addr; while (wire_addr->simplify(true, false, false, 1, -1, false, false)) { } - AstNode *assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); + AstNode *assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_addr, false)); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; defNode->children.push_back(assign_addr); - assign_addr = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); + assign_addr = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[0]->children[0]->children[0]->clone()); assign_addr->children[0]->str = id_addr; assign_addr->children[0]->was_checked = true; newNode->children.push_back(assign_addr); @@ -2596,7 +2618,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_data->str] = wire_data; while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } - AstNode *assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); + AstNode *assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bits_data, false)); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; defNode->children.push_back(assign_data); @@ -2616,7 +2638,7 @@ skip_dynamic_range_lvalue_expansion:; current_scope[wire_en->str] = wire_en; while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + AstNode *assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; defNode->children.push_back(assign_en); @@ -2642,7 +2664,7 @@ skip_dynamic_range_lvalue_expansion:; std::vector padding_x(offset, RTLIL::State::Sx); - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_CONCAT, mkconst_bits(padding_x, false), children[1]->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; @@ -2650,7 +2672,7 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -2671,7 +2693,7 @@ skip_dynamic_range_lvalue_expansion:; log_file_error(filename, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); int width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, children[1]->clone(), offset_ast->clone())); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; @@ -2679,7 +2701,7 @@ skip_dynamic_range_lvalue_expansion:; if (current_always->type != AST_INITIAL) { for (int i = 0; i < mem_width; i++) set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; @@ -2693,13 +2715,13 @@ skip_dynamic_range_lvalue_expansion:; else { if (!(children[0]->children.size() == 1 && children[1]->isConst())) { - assign_data = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), children[1]->clone()); + assign_data = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), children[1]->clone()); assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; } if (current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); assign_en->children[0]->str = id_en; assign_en->children[0]->was_checked = true; } @@ -2712,7 +2734,21 @@ skip_dynamic_range_lvalue_expansion:; AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR, node_addr, node_data, node_en); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; - current_ast_mod->children.push_back(wrnode); + wrnode->location = location; + if (wrnode->type == AST_MEMWR) { + int portid = current_memwr_count[wrnode->str]++; + wrnode->children.push_back(mkconst_int(portid, false)); + std::vector priority_mask; + for (int i = 0; i < portid; i++) { + bool has_prio = current_memwr_visible[wrnode->str].count(i); + priority_mask.push_back(State(has_prio)); + } + wrnode->children.push_back(mkconst_bits(priority_mask, false)); + current_memwr_visible[wrnode->str].insert(portid); + current_always->children.push_back(wrnode); + } else { + current_ast_mod->children.push_back(wrnode); + } if (newNode->children.empty()) { delete newNode; -- cgit v1.2.3 From cb9f3b6abfbc769589e5e5ceb2497955a155065c Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 11 Mar 2021 11:49:15 -0500 Subject: verilog: disallow overriding global parameters It was previously possible to override global parameters on a per-instance basis. This could be dangerous when using positional parameter bindings, hiding oversupplied parameters. --- frontends/ast/ast.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index b601d2e25..06e2e23a8 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1286,6 +1286,8 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } else { // must be global definition + if ((*it)->type == AST_PARAMETER) + (*it)->type = AST_LOCALPARAM; // cannot be overridden (*it)->simplify(false, false, false, 1, -1, false, false); //process enum/other declarations design->verilog_globals.push_back((*it)->clone()); current_scope.clear(); -- cgit v1.2.3 From 640b9927fae23d3127cc9ecb56ccbc8a2c66afbe Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 11 Mar 2021 13:05:04 -0500 Subject: sv: allow globals in one file to depend on globals in another This defers the simplification of globals so that globals in one file may depend on globals in other files. Adds a simplify() call downstream because globals are appended at the end. --- frontends/ast/ast.cc | 1 - frontends/ast/simplify.cc | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 06e2e23a8..7aa391c93 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1288,7 +1288,6 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump // must be global definition if ((*it)->type == AST_PARAMETER) (*it)->type = AST_LOCALPARAM; // cannot be overridden - (*it)->simplify(false, false, false, 1, -1, false, false); //process enum/other declarations design->verilog_globals.push_back((*it)->clone()); current_scope.clear(); } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index e0ac58f20..d68b13b2a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -192,6 +192,7 @@ void AstNode::annotateTypedEnums(AstNode *template_node) log_assert(current_scope.count(enum_type) == 1); AstNode *enum_node = current_scope.at(enum_type); log_assert(enum_node->type == AST_ENUM); + while (enum_node->simplify(true, false, false, 1, -1, false, true)) { } //get width from 1st enum item: log_assert(enum_node->children.size() >= 1); AstNode *enum_item0 = enum_node->children[0]; -- cgit v1.2.3 From 3d9698153fc7f01cef0dec99cc834ffecec766a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 9 Mar 2021 20:42:14 +0100 Subject: json: Add support for memories. Previously, memories were silently discarded by the JSON backend, making round-tripping modules with them crash. Since there are already some users using JSON to implement custom external passes that use memories (and infer width/size from memory ports), let's fix this by just making JSON backend and frontend support memories as first-class objects. Processes are still not supported, and will now cause a hard error. Fixes #1908. --- frontends/json/jsonparse.cc | 46 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'frontends') diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index 312f6d3be..d897ac20b 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -539,6 +539,52 @@ void json_import(Design *design, string &modname, JsonNode *node) json_parse_attr_param(cell->parameters, cell_node->data_dict.at("parameters")); } } + + if (node->data_dict.count("memories")) + { + JsonNode *memories_node = node->data_dict.at("memories"); + + if (memories_node->type != 'D') + log_error("JSON memories node is not a dictionary.\n"); + + for (auto &memory_node_it : memories_node->data_dict) + { + IdString memory_name = RTLIL::escape_id(memory_node_it.first.c_str()); + JsonNode *memory_node = memory_node_it.second; + + RTLIL::Memory *mem = new RTLIL::Memory; + mem->name = memory_name; + + if (memory_node->type != 'D') + log_error("JSON memory node '%s' is not a dictionary.\n", log_id(memory_name)); + + if (memory_node->data_dict.count("width") == 0) + log_error("JSON memory node '%s' has no width attribute.\n", log_id(memory_name)); + JsonNode *width_node = memory_node->data_dict.at("width"); + if (width_node->type != 'N') + log_error("JSON memory node '%s' has a non-number width.\n", log_id(memory_name)); + mem->width = width_node->data_number; + + if (memory_node->data_dict.count("size") == 0) + log_error("JSON memory node '%s' has no size attribute.\n", log_id(memory_name)); + JsonNode *size_node = memory_node->data_dict.at("size"); + if (size_node->type != 'N') + log_error("JSON memory node '%s' has a non-number size.\n", log_id(memory_name)); + mem->size = size_node->data_number; + + mem->start_offset = 0; + if (memory_node->data_dict.count("start_offset") != 0) { + JsonNode *val = memory_node->data_dict.at("start_offset"); + if (val->type == 'N') + mem->start_offset = val->data_number; + } + + if (memory_node->data_dict.count("attributes")) + json_parse_attr_param(mem->attributes, memory_node->data_dict.at("attributes")); + + module->memories[mem->name] = mem; + } + } } struct JsonFrontend : public Frontend { -- cgit v1.2.3 From 4f187d53c5a0580275857ec308b41f57808ec727 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 4 Mar 2021 14:07:56 -0500 Subject: verilog: support module scope identifiers in parametric modules --- frontends/ast/simplify.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d68b13b2a..d9eae3a06 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1691,11 +1691,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_IDENTIFIER) { if (current_scope.count(str) == 0) { AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; - const std::string& mod_scope = current_scope_ast->str; - if (str[0] == '\\' && str.substr(0, mod_scope.size()) == mod_scope) { - std::string new_str = "\\" + str.substr(mod_scope.size() + 1); + size_t pos = str.find('.', 1); + if (str[0] == '\\' && pos != std::string::npos) { + std::string new_str = "\\" + str.substr(pos + 1); if (current_scope.count(new_str)) { - str = new_str; + std::string prefix = str.substr(0, pos); + auto it = current_scope_ast->attributes.find(ID::hdlname); + if ((it != current_scope_ast->attributes.end() && it->second->str == prefix) + || prefix == current_scope_ast->str) + str = new_str; } } for (auto node : current_scope_ast->children) { -- cgit v1.2.3 From 092e923330ce23adffa7843a27bdba8a0b139e58 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 17 Mar 2021 00:18:36 +0100 Subject: verilog: fix buf/not primitives with multiple outputs From IEEE1364-2005, section 7.3 buf and not gates: > These two logic gates shall have one input and one or more outputs. > The last terminal in the terminal list shall connect to the input of the > logic gate, and the other terminals shall connect to the outputs of > the logic gate. yosys does not follow this and instead interprets the first argument as the output, the second as the input and ignores the rest. --- frontends/ast/simplify.cc | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index d9eae3a06..b9965ba99 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2223,6 +2223,21 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, children.push_back(node); did_something = true; } + else if (str == "buf" || str == "not") + { + AstNode *input = children_list.back(); + if (str == "not") + input = new AstNode(AST_BIT_NOT, input); + + newNode = new AstNode(AST_GENBLOCK); + for (auto it = children_list.begin(); it != std::prev(children_list.end()); it++) { + newNode->children.push_back(new AstNode(AST_ASSIGN, *it, input->clone())); + newNode->children.back()->was_checked = true; + } + delete input; + + did_something = true; + } else { AstNodeType op_type = AST_NONE; @@ -2240,10 +2255,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, op_type = AST_BIT_XOR; if (str == "xnor") op_type = AST_BIT_XOR, invert_results = true; - if (str == "buf") - op_type = AST_POS; - if (str == "not") - op_type = AST_POS, invert_results = true; log_assert(op_type != AST_NONE); AstNode *node = children_list[1]; -- cgit v1.2.3 From f71c2dcca6b63ad3cbd3d5b6f51f67f9cd85f03e Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 16 Mar 2021 11:06:40 -0400 Subject: sv: carry over global typedefs from previous files This breaks the ability to use a global typename as a standard identifier in a subsequent input file. This is otherwise backwards compatible, including for sources which previously included conflicting typedefs in each input file. --- frontends/verilog/verilog_frontend.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index e2aecd99b..5907707c8 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -61,8 +61,11 @@ static void add_package_types(dict &user_types, std } } } - user_type_stack.clear(); - user_type_stack.push_back(new UserTypeMap()); + + // carry over typedefs from previous files, but allow them to be overridden + // note that these type maps are currently never reclaimed + if (user_type_stack.empty() || !user_type_stack.back()->empty()) + user_type_stack.push_back(new UserTypeMap()); } struct VerilogFrontend : public Frontend { -- cgit v1.2.3 From 8740fdf1d799fd8a3196bac28fe4e418e74f2acc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 17 Mar 2021 18:30:49 +0100 Subject: ast: Use better parameter serialization for paramod names. Calling log_signal is problematic for several reasons: - with recent changes, empty string is serialized as { }, which violates the "no spaces in IdString" rule - the type (plain / real / signed / string) is dropped, wrongly conflating functionally different values and potentially introducing a subtle elaboration bug Instead, use a custom simple serialization scheme. --- frontends/ast/ast.cc | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 7aa391c93..84a4de41c 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1575,6 +1575,29 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict= 0; i--) { + switch (val.bits[i]) { + case RTLIL::State::S0: res.push_back('0'); break; + case RTLIL::State::S1: res.push_back('1'); break; + case RTLIL::State::Sx: res.push_back('x'); break; + case RTLIL::State::Sz: res.push_back('z'); break; + case RTLIL::State::Sa: res.push_back('?'); break; + case RTLIL::State::Sm: res.push_back('m'); break; + } + } + return res; +} + // create a new parametric module (when needed) and return the name of the generated module std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet) { @@ -1594,14 +1617,14 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictstr.c_str(), log_signal(it->second)); - para_info += stringf("%s=%s", child->str.c_str(), log_signal(it->second)); + para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str()); continue; } it = parameters.find(stringf("$%d", para_counter)); if (it != parameters.end()) { if (!quiet) log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(it->second)); - para_info += stringf("%s=%s", child->str.c_str(), log_signal(it->second)); + para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str()); continue; } } -- cgit v1.2.3 From 0c66141ed25b0af229551f9ce8fe844be1e88bf3 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 16 Mar 2021 16:42:14 +0100 Subject: verilog: rebuild user_type_stack from globals before parsing file This was actually a ticking UB bomb: after running the parser, the type maps contain pointers to children of the current AST, which is recursively deleted after the pass has executed. This leaves the pointers in user_type_stack dangling, which just happened to never be a problem due to another bug that causes typedefs from higher-level type maps to never be considered. Rebuilding the type stack from the design's globals ensures the AstNode pointers are valid. --- frontends/verilog/verilog_frontend.cc | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 5907707c8..84ac73e91 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -61,11 +61,6 @@ static void add_package_types(dict &user_types, std } } } - - // carry over typedefs from previous files, but allow them to be overridden - // note that these type maps are currently never reclaimed - if (user_type_stack.empty() || !user_type_stack.back()->empty()) - user_type_stack.push_back(new UserTypeMap()); } struct VerilogFrontend : public Frontend { @@ -487,6 +482,19 @@ struct VerilogFrontend : public Frontend { // make package typedefs available to parser add_package_types(pkg_user_types, design->verilog_packages); + UserTypeMap *global_types_map = new UserTypeMap(); + for (auto def : design->verilog_globals) { + if (def->type == AST::AST_TYPEDEF) { + (*global_types_map)[def->str] = def; + } + } + + log_assert(user_type_stack.empty()); + // use previous global typedefs as bottom level of user type stack + user_type_stack.push_back(global_types_map); + // add a new empty type map to allow overriding existing global definitions + user_type_stack.push_back(new UserTypeMap()); + frontend_verilog_yyset_lineno(1); frontend_verilog_yyrestart(NULL); frontend_verilog_yyparse(); @@ -509,6 +517,14 @@ struct VerilogFrontend : public Frontend { if (!flag_nopp) delete lexin; + // only the previous and new global type maps remain + log_assert(user_type_stack.size() == 2); + for (auto it : user_type_stack) { + // the global typedefs have to remain valid for future invocations, so just drop the map without deleting values + delete it; + } + user_type_stack.clear(); + delete current_ast; current_ast = NULL; -- cgit v1.2.3 From 4f4e70876f06738fa7dda24e01ac296fe318264a Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 18 Mar 2021 13:38:25 -0400 Subject: sv: allow typenames as function return types --- frontends/verilog/verilog_parser.y | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index ea8cc0765..91b7afddf 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -861,6 +861,7 @@ task_func_decl: outreg->children.push_back($4); outreg->is_signed = $4->is_signed; $4->is_signed = false; + outreg->is_custom_type = $4->type == AST_WIRETYPE; } current_function_or_task->children.push_back(outreg); current_function_or_task_port_id = 1; @@ -871,6 +872,11 @@ task_func_decl: }; func_return_type: + hierarchical_type_id { + $$ = new AstNode(AST_WIRETYPE); + $$->str = *$1; + delete $1; + } | opt_type_vec opt_signedness_default_unsigned { $$ = makeRange(0, 0, $2); } | -- cgit v1.2.3 From 92d5550a90558a0292c8ac63cecabb2de30eb6aa Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 18 Mar 2021 21:53:02 +0100 Subject: verilog: check entire user type stack for type definition --- frontends/verilog/verilog_parser.y | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 91b7afddf..e4b3258c2 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -163,12 +163,18 @@ static bool isInLocalScope(const std::string *name) static AstNode *getTypeDefinitionNode(std::string type_name) { - // return the definition nodes from the typedef statement - auto user_types = user_type_stack.back(); - log_assert(user_types->count(type_name) > 0); - auto typedef_node = (*user_types)[type_name]; - log_assert(typedef_node->type == AST_TYPEDEF); - return typedef_node->children[0]; + // check current scope then outer scopes for a name + for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { + if ((*it)->count(type_name) > 0) { + // return the definition nodes from the typedef statement + auto typedef_node = (**it)[type_name]; + log_assert(typedef_node->type == AST_TYPEDEF); + return typedef_node->children[0]; + } + } + + // The lexer recognized the name as a TOK_USER_TYPE, but now we can't find it anymore? + log_error("typedef for user type `%s' not found", type_name.c_str()); } static AstNode *copyTypeDefinition(std::string type_name) -- cgit v1.2.3 From c58bb1d2e1e7ff3181c7b5d4d0a0d10d95d3b6fe Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 23 Mar 2021 12:49:11 -0400 Subject: ast: make design available to process_module() --- frontends/ast/ast.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 84a4de41c..614c9bcef 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -980,8 +980,8 @@ static bool param_has_no_default(const AstNode *param) { (children.size() == 1 && children[0]->type == AST_RANGE); } -// create a new AstModule from an AST_MODULE AST node -static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) +// create and add a new AstModule from an AST_MODULE AST node +static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) { log_assert(current_scope.empty()); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); @@ -1039,6 +1039,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast } } + // TODO(zachjs): make design available to simplify() in the future while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } if (flag_dump_ast2) { @@ -1190,7 +1191,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast log("--- END OF RTLIL DUMP ---\n"); } - return current_module; + design->add(current_module); } // create AstModule instances for all modules in the AST tree and add them to 'design' @@ -1275,7 +1276,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } } - design->add(process_module(*it, defer_local)); + process_module(design, *it, defer_local); current_ast_mod = nullptr; } else if ((*it)->type == AST_PACKAGE) { @@ -1456,9 +1457,8 @@ void AstModule::reprocess_module(RTLIL::Design *design, const dictadd(newmod); RTLIL::Module* mod = design->module(original_name); if (is_top) mod->set_bool_attribute(ID::top); @@ -1514,7 +1514,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dictadd(process_module(new_ast, false)); + process_module(design, new_ast, false); design->module(modname)->check(); RTLIL::Module* mod = design->module(modname); @@ -1565,7 +1565,7 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dicthas(modname)) { new_ast->str = modname; - design->add(process_module(new_ast, false, NULL, quiet)); + process_module(design, new_ast, false, NULL, quiet); design->module(modname)->check(); } else if (!quiet) { log("Found cached RTLIL representation for module `%s'.\n", modname.c_str()); -- cgit v1.2.3 From 0505c604e70c6d9621eb6ace6a9d8a3a5ac71eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Tue, 30 Mar 2021 01:15:49 +0200 Subject: preproc: Fix up conditional handling. Fixes #2710. Fixes #2711. --- frontends/verilog/preproc.cc | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 84966e501..568224da2 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -726,8 +726,16 @@ frontend_verilog_preproc(std::istream &f, defines.merge(global_defines_cache); std::vector filename_stack; + // We are inside pass_level levels of satisfied ifdefs, and then within + // fail_level levels of unsatisfied ifdefs. The unsatisfied ones are + // always within satisfied ones — even if some condition within is true, + // the parent condition failing renders it moot. int ifdef_fail_level = 0; int ifdef_pass_level = 0; + // For the outermost unsatisfied ifdef, true iff that ifdef already + // had a satisfied branch, and further elsif/else branches should be + // considered unsatisfied even if the condition is true. + // Meaningless if ifdef_fail_level == 0. bool ifdef_already_satisfied = false; output_code.clear(); @@ -745,7 +753,7 @@ frontend_verilog_preproc(std::istream &f, if (ifdef_fail_level > 0) ifdef_fail_level--; else if (ifdef_pass_level > 0) - ifdef_already_satisfied = --ifdef_pass_level; + ifdef_pass_level--; else log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); continue; @@ -755,8 +763,9 @@ frontend_verilog_preproc(std::istream &f, if (ifdef_fail_level == 0) { if (ifdef_pass_level == 0) log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); - log_assert(ifdef_already_satisfied); + ifdef_pass_level--; ifdef_fail_level = 1; + ifdef_already_satisfied = true; } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied) { ifdef_fail_level = 0; ifdef_pass_level++; @@ -771,8 +780,9 @@ frontend_verilog_preproc(std::istream &f, if (ifdef_fail_level == 0) { if (ifdef_pass_level == 0) log_error("Found %s outside of macro conditional branch!\n", tok.c_str()); - log_assert(ifdef_already_satisfied); + ifdef_pass_level--; ifdef_fail_level = 1; + ifdef_already_satisfied = true; } else if (ifdef_fail_level == 1 && !ifdef_already_satisfied && defines.find(name)) { ifdef_fail_level = 0; ifdef_pass_level++; @@ -931,6 +941,10 @@ frontend_verilog_preproc(std::istream &f, output_code.push_back(tok); } + if (ifdef_fail_level > 0 || ifdef_pass_level > 0) { + log_error("Unterminated preprocessor conditional!\n"); + } + std::string output; for (auto &str : output_code) output += str; -- cgit v1.2.3 From ba2ff1ea986b73d025938ab1cf102e1cf35d6773 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 29 Mar 2021 11:03:46 -0400 Subject: verilog: revise hot comment warnings --- frontends/verilog/verilog_lexer.l | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 66772a097..1a6dc96fd 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -431,8 +431,13 @@ supply1 { return TOK_SUPPLY1; } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { static bool printed_warning = false; if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) translate_off' comments.\n" - "Yosys does support them but it is recommended to use `ifdef constructs instead!\n"); + log_warning( + "Encountered `translate_off' comment! Such legacy hot " + "comments are supported by Yosys, but are not part of " + "any formal language specification. Using a portable " + "and standards-compliant construct such as `ifdef is " + "recommended!\n" + ); printed_warning = true; } BEGIN(SYNOPSYS_TRANSLATE_OFF); @@ -447,8 +452,13 @@ supply1 { return TOK_SUPPLY1; } full_case { static bool printed_warning = false; if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) full_case' comments.\n" - "Yosys does support them but it is recommended to use Verilog `full_case' attributes instead!\n"); + log_warning( + "Encountered `full_case' comment! Such legacy hot " + "comments are supported by Yosys, but are not part of " + "any formal language specification. Using the Verilog " + "`full_case' attribute or the SystemVerilog `unique' " + "or `unique0' keywords is recommended!\n" + ); printed_warning = true; } return TOK_SYNOPSYS_FULL_CASE; @@ -456,8 +466,13 @@ supply1 { return TOK_SUPPLY1; } parallel_case { static bool printed_warning = false; if (!printed_warning) { - log_warning("Found one of those horrible `(synopsys|synthesis) parallel_case' comments.\n" - "Yosys does support them but it is recommended to use Verilog `parallel_case' attributes instead!\n"); + log_warning( + "Encountered `parallel_case' comment! Such legacy hot " + "comments are supported by Yosys, but are not part of " + "any formal language specification. Using the Verilog " + "`parallel_case' attribute or the SystemVerilog " + "`unique' or `priority' keywords is recommended!\n" + ); printed_warning = true; } return TOK_SYNOPSYS_PARALLEL_CASE; -- cgit v1.2.3 From 58290c0c77e09aa40a098065ea999c85aaba398c Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Mon, 26 Apr 2021 16:31:44 +0200 Subject: Remove duplicates from conns array in JSON front-end, fixes #2736 --- frontends/json/jsonparse.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'frontends') diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index d897ac20b..cbfa038a1 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -585,6 +585,10 @@ void json_import(Design *design, string &modname, JsonNode *node) module->memories[mem->name] = mem; } } + + // remove duplicates from connections array + pool unique_connections(module->connections_.begin(), module->connections_.end()); + module->connections_ = std::vector(unique_connections.begin(), unique_connections.end()); } struct JsonFrontend : public Frontend { -- cgit v1.2.3 From 32a0ce9d6809d073abcbf19fe3eaf7a0cf936963 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Wed, 5 May 2021 20:31:27 +0200 Subject: blif: Use library cells' start_offset and upto for wideports. Fixes #2729. --- frontends/blif/blifparse.cc | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) (limited to 'frontends') diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index 9ae3fac2c..52b46c228 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -65,17 +65,21 @@ static std::pair wideports_split(std::string name) for (int i = 0; i+1 < GetSize(name); i++) { if (name[i] == '[') pos = i; - else if (name[i] < '0' || name[i] > '9') + else if (name[i] != '-' && (name[i] < '0' || name[i] > '9')) + pos = -1; + else if (name[i] == '-' && ((i != pos+1) || name[i+1] == ']')) + pos = -1; + else if (i == pos+2 && name[i] == '0' && name[i-1] == '-') pos = -1; else if (i == pos+1 && name[i] == '0' && name[i+1] != ']') pos = -1; } if (pos >= 0) - return std::pair("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1)+1); + return std::pair("\\" + name.substr(0, pos), atoi(name.c_str() + pos+1)); failed: - return std::pair("\\" + name, 0); + return std::pair(RTLIL::IdString(), 0); } void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool run_clean, bool sop_mode, bool wideports) @@ -263,8 +267,8 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool if (wideports) { std::pair wp = wideports_split(p); - if (wp.second > 0) { - wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second); + if (!wp.first.empty() && wp.second >= 0) { + wideports_cache[wp.first].first = std::max(wideports_cache[wp.first].first, wp.second + 1); wideports_cache[wp.first].second = !strcmp(cmd, ".inputs"); } } @@ -375,6 +379,7 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool IdString celltype = RTLIL::escape_id(p); RTLIL::Cell *cell = module->addCell(NEW_ID, celltype); + RTLIL::Module *cell_mod = design->module(celltype); dict> cell_wideports_cache; @@ -387,10 +392,10 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool if (wideports) { std::pair wp = wideports_split(p); - if (wp.second > 0) - cell_wideports_cache[wp.first][wp.second-1] = blif_wire(q); - else + if (wp.first.empty()) cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); + else + cell_wideports_cache[wp.first][wp.second] = blif_wire(q); } else { cell->setPort(RTLIL::escape_id(p), *q ? blif_wire(q) : SigSpec()); } @@ -399,14 +404,26 @@ void parse_blif(RTLIL::Design *design, std::istream &f, IdString dff_name, bool for (auto &it : cell_wideports_cache) { int width = 0; + int offset = 0; + bool upto = false; for (auto &b : it.second) width = std::max(width, b.first + 1); + if (cell_mod) { + Wire *cell_port = cell_mod->wire(it.first); + if (cell_port && (cell_port->port_input || cell_port->port_output)) { + offset = cell_port->start_offset; + upto = cell_port->upto; + width = cell_port->width; + } + } + SigSpec sig; for (int i = 0; i < width; i++) { - if (it.second.count(i)) - sig.append(it.second.at(i)); + int idx = offset + (upto ? width - 1 - i: i); + if (it.second.count(idx)) + sig.append(it.second.at(idx)); else sig.append(module->addWire(NEW_ID)); } -- cgit v1.2.3 From 445208086121ea343bdb80a9998637361c841bea Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 10 May 2021 11:06:02 -0400 Subject: sv: check validity of package end label --- frontends/verilog/verilog_parser.y | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index e4b3258c2..dd25f412f 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -579,6 +579,8 @@ package: append_attr(mod, $1); } ';' package_body TOK_ENDPACKAGE opt_label { ast_stack.pop_back(); + if ($4 != NULL && $9 != NULL && *$4 != *$9) + frontend_verilog_yyerror("Package name (%s) and end label (%s) don't match.", $4->c_str()+1, $9->c_str()+1); current_ast_mod = NULL; exitTypeScope(); }; -- cgit v1.2.3 From 51ed4a7149f64729edeb5ee8419f3303636180e7 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Mon, 20 Apr 2020 16:24:57 +0100 Subject: Use range-based for loop in AST::process No functional change: just get rid of the explicit iterator and replace (*it)-> with child->. It's even the same number of characters, but is hopefully a little easier to read. --- frontends/ast/ast.cc | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 614c9bcef..7e4f38aa9 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1219,12 +1219,12 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_autowire = autowire; log_assert(current_ast->type == AST_DESIGN); - for (auto it = current_ast->children.begin(); it != current_ast->children.end(); it++) + for (AstNode *child : current_ast->children) { - if ((*it)->type == AST_MODULE || (*it)->type == AST_INTERFACE) + if (child->type == AST_MODULE || child->type == AST_INTERFACE) { for (auto n : design->verilog_globals) - (*it)->children.push_back(n->clone()); + child->children.push_back(n->clone()); // append nodes from previous packages using package-qualified names for (auto &n : design->verilog_packages) { @@ -1239,57 +1239,57 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump } else { cloned_node->str = n->str + std::string("::") + cloned_node->str.substr(1); } - (*it)->children.push_back(cloned_node); + child->children.push_back(cloned_node); } } - if (flag_icells && (*it)->str.compare(0, 2, "\\$") == 0) - (*it)->str = (*it)->str.substr(1); + if (flag_icells && child->str.compare(0, 2, "\\$") == 0) + child->str = child->str.substr(1); bool defer_local = defer; if (!defer_local) - for (const AstNode *node : (*it)->children) + for (const AstNode *node : child->children) if (node->type == AST_PARAMETER && param_has_no_default(node)) { - log("Deferring `%s' because it contains parameter(s) without defaults.\n", (*it)->str.c_str()); + log("Deferring `%s' because it contains parameter(s) without defaults.\n", child->str.c_str()); defer_local = true; break; } if (defer_local) - (*it)->str = "$abstract" + (*it)->str; + child->str = "$abstract" + child->str; - if (design->has((*it)->str)) { - RTLIL::Module *existing_mod = design->module((*it)->str); + if (design->has(child->str)) { + RTLIL::Module *existing_mod = design->module(child->str); if (!nooverwrite && !overwrite && !existing_mod->get_blackbox_attribute()) { - log_file_error((*it)->filename, (*it)->location.first_line, "Re-definition of module `%s'!\n", (*it)->str.c_str()); + log_file_error(child->filename, child->location.first_line, "Re-definition of module `%s'!\n", child->str.c_str()); } else if (nooverwrite) { log("Ignoring re-definition of module `%s' at %s.\n", - (*it)->str.c_str(), (*it)->loc_string().c_str()); + child->str.c_str(), child->loc_string().c_str()); continue; } else { log("Replacing existing%s module `%s' at %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", - (*it)->str.c_str(), (*it)->loc_string().c_str()); + child->str.c_str(), child->loc_string().c_str()); design->remove(existing_mod); } } - process_module(design, *it, defer_local); + process_module(design, child, defer_local); current_ast_mod = nullptr; } - else if ((*it)->type == AST_PACKAGE) { + else if (child->type == AST_PACKAGE) { // process enum/other declarations - (*it)->simplify(true, false, false, 1, -1, false, false); - design->verilog_packages.push_back((*it)->clone()); + child->simplify(true, false, false, 1, -1, false, false); + design->verilog_packages.push_back(child->clone()); current_scope.clear(); } else { // must be global definition - if ((*it)->type == AST_PARAMETER) - (*it)->type = AST_LOCALPARAM; // cannot be overridden - design->verilog_globals.push_back((*it)->clone()); + if (child->type == AST_PARAMETER) + child->type = AST_LOCALPARAM; // cannot be overridden + design->verilog_globals.push_back(child->clone()); current_scope.clear(); } } -- cgit v1.2.3 From 3421979f00664443c77b0899d34438f979b4c51c Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Mon, 20 Apr 2020 14:41:55 +0100 Subject: Change the type of current_module to Module The current_module global is needed so that genRTLIL has somewhere to put cells and wires that it generates as it makes sense of expressions that it sees. However, that doesn't actually need to be an AstModule: the Module base class is enough. This patch should cause no functional change, but the point is that it's now possible to call genRTLIL with a module that isn't an AstModule as "current_module". This will be needed for 'bind' support. --- frontends/ast/ast.cc | 48 +++++++++++++++++++++++++----------------------- frontends/ast/ast.h | 2 +- 2 files changed, 26 insertions(+), 24 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 7e4f38aa9..7e5cc9411 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -52,7 +52,7 @@ namespace AST_INTERNAL { const dict *genRTLIL_subst_ptr = NULL; RTLIL::SigSpec ignoreThisSignalsInInitial; AstNode *current_always, *current_top_block, *current_block, *current_block_child; - AstModule *current_module; + Module *current_module; bool current_always_clocked; dict current_memwr_count; dict> current_memwr_visible; @@ -992,11 +992,13 @@ static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstN log("Generating RTLIL representation for module `%s'.\n", ast->str.c_str()); } - current_module = new AstModule; - current_module->ast = NULL; - current_module->name = ast->str; - set_src_attr(current_module, ast); - current_module->set_bool_attribute(ID::cells_not_processed); + AstModule *module = new AstModule; + current_module = module; + + module->ast = NULL; + module->name = ast->str; + set_src_attr(module, ast); + module->set_bool_attribute(ID::cells_not_processed); current_ast_mod = ast; AstNode *ast_before_simplify; @@ -1137,7 +1139,7 @@ static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstN for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) log_file_error(ast->filename, ast->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); - current_module->attributes[attr.first] = attr.second->asAttrConst(); + module->attributes[attr.first] = attr.second->asAttrConst(); } for (size_t i = 0; i < ast->children.size(); i++) { AstNode *node = ast->children[i]; @@ -1165,29 +1167,29 @@ static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstN for (auto &attr : ast->attributes) { if (attr.second->type != AST_CONSTANT) continue; - current_module->attributes[attr.first] = attr.second->asAttrConst(); + module->attributes[attr.first] = attr.second->asAttrConst(); } } if (ast->type == AST_INTERFACE) - current_module->set_bool_attribute(ID::is_interface); - current_module->ast = ast_before_simplify; - current_module->nolatches = flag_nolatches; - current_module->nomeminit = flag_nomeminit; - current_module->nomem2reg = flag_nomem2reg; - current_module->mem2reg = flag_mem2reg; - current_module->noblackbox = flag_noblackbox; - current_module->lib = flag_lib; - current_module->nowb = flag_nowb; - current_module->noopt = flag_noopt; - current_module->icells = flag_icells; - current_module->pwires = flag_pwires; - current_module->autowire = flag_autowire; - current_module->fixup_ports(); + module->set_bool_attribute(ID::is_interface); + module->ast = ast_before_simplify; + module->nolatches = flag_nolatches; + module->nomeminit = flag_nomeminit; + module->nomem2reg = flag_nomem2reg; + module->mem2reg = flag_mem2reg; + module->noblackbox = flag_noblackbox; + module->lib = flag_lib; + module->nowb = flag_nowb; + module->noopt = flag_noopt; + module->icells = flag_icells; + module->pwires = flag_pwires; + module->autowire = flag_autowire; + module->fixup_ports(); if (flag_dump_rtlil) { log("Dumping generated RTLIL:\n"); - log_module(current_module); + log_module(module); log("--- END OF RTLIL DUMP ---\n"); } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 1447bf568..069479353 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -379,7 +379,7 @@ namespace AST_INTERNAL extern const dict *genRTLIL_subst_ptr; extern RTLIL::SigSpec ignoreThisSignalsInInitial; extern AST::AstNode *current_always, *current_top_block, *current_block, *current_block_child; - extern AST::AstModule *current_module; + extern RTLIL::Module *current_module; extern bool current_always_clocked; extern dict current_memwr_count; extern dict> current_memwr_visible; -- cgit v1.2.3 From 15f35d6754af619accdf63030e0a5ad3085cec16 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sat, 27 Mar 2021 15:59:48 -0400 Subject: sv: support remaining assignment operators - Add support for: *=, /=, %=, <<=, >>=, <<<=, >>>= - Unify existing support for: +=, -=, &=, |=, ^= --- frontends/verilog/verilog_lexer.l | 15 ++++++--- frontends/verilog/verilog_parser.y | 68 +++++++++++++++++--------------------- 2 files changed, 41 insertions(+), 42 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 1a6dc96fd..f52928c77 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -544,11 +544,18 @@ import[ \t\r\n]+\"(DPI|DPI-C)\"[ \t\r\n]+function[ \t\r\n]+ { ".*" { return TOK_WILDCARD_CONNECT; } -"|=" { SV_KEYWORD(TOK_OR_ASSIGN); } -"&=" { SV_KEYWORD(TOK_AND_ASSIGN); } -"+=" { SV_KEYWORD(TOK_PLUS_ASSIGN); } +"|=" { SV_KEYWORD(TOK_BIT_OR_ASSIGN); } +"&=" { SV_KEYWORD(TOK_BIT_AND_ASSIGN); } +"+=" { SV_KEYWORD(TOK_ADD_ASSIGN); } "-=" { SV_KEYWORD(TOK_SUB_ASSIGN); } -"^=" { SV_KEYWORD(TOK_XOR_ASSIGN); } +"^=" { SV_KEYWORD(TOK_BIT_XOR_ASSIGN); } +"/=" { SV_KEYWORD(TOK_DIV_ASSIGN); } +"%=" { SV_KEYWORD(TOK_MOD_ASSIGN); } +"*=" { SV_KEYWORD(TOK_MUL_ASSIGN); } +"<<=" { SV_KEYWORD(TOK_SHL_ASSIGN); } +">>=" { SV_KEYWORD(TOK_SHR_ASSIGN); } +"<<<=" { SV_KEYWORD(TOK_SSHL_ASSIGN); } +">>>=" { SV_KEYWORD(TOK_SSHR_ASSIGN); } [-+]?[=*]> { if (!specify_mode) REJECT; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index dd25f412f..c2b43f45b 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -260,6 +260,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) bool boolean; char ch; int integer; + YOSYS_NAMESPACE_PREFIX AST::AstNodeType ast_node_type; } %token TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE @@ -272,7 +273,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP %token TOK_INTERFACE TOK_ENDINTERFACE TOK_MODPORT TOK_VAR TOK_WILDCARD_CONNECT %token TOK_INPUT TOK_OUTPUT TOK_INOUT TOK_WIRE TOK_WAND TOK_WOR TOK_REG TOK_LOGIC -%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_PLUS_ASSIGN TOK_ALWAYS TOK_INITIAL +%token TOK_INTEGER TOK_SIGNED TOK_ASSIGN TOK_ALWAYS TOK_INITIAL %token TOK_ALWAYS_FF TOK_ALWAYS_COMB TOK_ALWAYS_LATCH %token TOK_BEGIN TOK_END TOK_IF TOK_ELSE TOK_FOR TOK_WHILE TOK_REPEAT %token TOK_DPI_FUNCTION TOK_POSEDGE TOK_NEGEDGE TOK_OR TOK_AUTOMATIC @@ -286,7 +287,9 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_UNIQUE0 TOK_PRIORITY %token TOK_STRUCT TOK_PACKED TOK_UNSIGNED TOK_INT TOK_BYTE TOK_SHORTINT TOK_LONGINT TOK_UNION -%token TOK_OR_ASSIGN TOK_XOR_ASSIGN TOK_AND_ASSIGN TOK_SUB_ASSIGN +%token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN +%token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN +%token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN %type range range_or_multirange non_opt_range non_opt_multirange %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type @@ -298,6 +301,7 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) %type integer_atom_type %type attr case_attr %type struct_union +%type asgn_binop %type specify_target %type specify_triple specify_opt_triple @@ -2449,47 +2453,35 @@ simple_behavioral_stmt: SET_AST_NODE_LOC(node, @2, @5); append_attr(node, $1); } | - attr lvalue TOK_XOR_ASSIGN delay expr { - AstNode *xor_node = new AstNode(AST_BIT_XOR, $2->clone(), $5); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, xor_node); - SET_AST_NODE_LOC(xor_node, @2, @5); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - } | - attr lvalue TOK_OR_ASSIGN delay expr { - AstNode *or_node = new AstNode(AST_BIT_OR, $2->clone(), $5); - SET_AST_NODE_LOC(or_node, @2, @5); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, or_node); - SET_AST_NODE_LOC(node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - } | - attr lvalue TOK_PLUS_ASSIGN delay expr { - AstNode *add_node = new AstNode(AST_ADD, $2->clone(), $5); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, add_node); - SET_AST_NODE_LOC(node, @2, @5); - SET_AST_NODE_LOC(add_node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - } | - attr lvalue TOK_SUB_ASSIGN delay expr { - AstNode *sub_node = new AstNode(AST_SUB, $2->clone(), $5); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, sub_node); - SET_AST_NODE_LOC(node, @2, @5); - SET_AST_NODE_LOC(sub_node, @2, @5); - ast_stack.back()->children.push_back(node); - append_attr(node, $1); - } | - attr lvalue TOK_AND_ASSIGN delay expr { - AstNode *and_node = new AstNode(AST_BIT_AND, $2->clone(), $5); - AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, and_node); + attr lvalue asgn_binop delay expr { + AstNode *expr_node = $5; + if ($3 == AST_SHIFT_LEFT || $3 == AST_SHIFT_RIGHT || + $3 == AST_SHIFT_SLEFT || $3 == AST_SHIFT_SRIGHT) { + expr_node = new AstNode(AST_TO_UNSIGNED, expr_node); + SET_AST_NODE_LOC(expr_node, @5, @5); + } + AstNode *op_node = new AstNode($3, $2->clone(), expr_node); + AstNode *node = new AstNode(AST_ASSIGN_EQ, $2, op_node); + SET_AST_NODE_LOC(op_node, @2, @5); SET_AST_NODE_LOC(node, @2, @5); - SET_AST_NODE_LOC(and_node, @2, @5); ast_stack.back()->children.push_back(node); append_attr(node, $1); }; +asgn_binop: + TOK_BIT_OR_ASSIGN { $$ = AST_BIT_OR; } | + TOK_BIT_AND_ASSIGN { $$ = AST_BIT_AND; } | + TOK_BIT_XOR_ASSIGN { $$ = AST_BIT_XOR; } | + TOK_ADD_ASSIGN { $$ = AST_ADD; } | + TOK_SUB_ASSIGN { $$ = AST_SUB; } | + TOK_DIV_ASSIGN { $$ = AST_DIV; } | + TOK_MOD_ASSIGN { $$ = AST_MOD; } | + TOK_MUL_ASSIGN { $$ = AST_MUL; } | + TOK_SHL_ASSIGN { $$ = AST_SHIFT_LEFT; } | + TOK_SHR_ASSIGN { $$ = AST_SHIFT_RIGHT; } | + TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | + TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; + // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | -- cgit v1.2.3 From 0795b3ec076d8d2c0aa0d954b707271bd2f064bf Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 25 Mar 2021 14:06:05 -0400 Subject: verilog: fix case expression sign and width handling - The case expression and case item expressions are extended to the maximum width among them, and are only interpreted as signed if all of them are signed - Add overall width and sign detection for AST_CASE - Add sign argument to genWidthRTLIL helper - Coverage for both const and non-const case statements --- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 50 +++++++++++++++++++++++++++++++++++++---------- frontends/ast/simplify.cc | 9 ++++++++- 3 files changed, 49 insertions(+), 12 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 069479353..9887d24ea 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -291,7 +291,7 @@ namespace AST // for expressions the resulting signal vector is returned // all generated cell instances, etc. are written to the RTLIL::Module pointed to by AST_INTERNAL::current_module RTLIL::SigSpec genRTLIL(int width_hint = -1, bool sign_hint = false); - RTLIL::SigSpec genWidthRTLIL(int width, const dict *new_subst_ptr = NULL); + RTLIL::SigSpec genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr = NULL); // compare AST nodes bool operator==(const AstNode &other) const; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ad5814f1b..b8b9f715e 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -566,7 +566,7 @@ struct AST_INTERNAL::ProcessGenerator case AST_ASSIGN_LE: { RTLIL::SigSpec unmapped_lvalue = ast->children[0]->genRTLIL(), lvalue = unmapped_lvalue; - RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), &subst_rvalue_map.stdmap()); + RTLIL::SigSpec rvalue = ast->children[1]->genWidthRTLIL(lvalue.size(), true, &subst_rvalue_map.stdmap()); pool lvalue_sigbits; for (int i = 0; i < GetSize(lvalue); i++) { @@ -593,9 +593,13 @@ struct AST_INTERNAL::ProcessGenerator case AST_CASE: { + int width_hint; + bool sign_hint; + ast->detectSignWidth(width_hint, sign_hint); + RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; set_src_attr(sw, ast); - sw->signal = ast->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); + sw->signal = ast->children[0]->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap()); current_case->switches.push_back(sw); for (auto &attr : ast->attributes) { @@ -637,7 +641,7 @@ struct AST_INTERNAL::ProcessGenerator else if (node->type == AST_BLOCK) processAst(node); else - current_case->compare.push_back(node->genWidthRTLIL(sw->signal.size(), &subst_rvalue_map.stdmap())); + current_case->compare.push_back(node->genWidthRTLIL(width_hint, sign_hint, &subst_rvalue_map.stdmap())); } if (default_case != current_case) sw->cases.push_back(current_case); @@ -715,9 +719,9 @@ struct AST_INTERNAL::ProcessGenerator RTLIL::MemWriteAction action; set_src_attr(&action, child); action.memid = memid; - action.address = child->children[0]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); - action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, &subst_rvalue_map.stdmap()); - action.enable = child->children[2]->genWidthRTLIL(-1, &subst_rvalue_map.stdmap()); + action.address = child->children[0]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap()); + action.data = child->children[1]->genWidthRTLIL(current_module->memories[memid]->width, true, &subst_rvalue_map.stdmap()); + action.enable = child->children[2]->genWidthRTLIL(-1, true, &subst_rvalue_map.stdmap()); RTLIL::Const orig_priority_mask = child->children[4]->bitsAsConst(); RTLIL::Const priority_mask = RTLIL::Const(0, cur_idx); for (int i = 0; i < portid; i++) { @@ -954,6 +958,32 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun width_hint = max(width_hint, this_width); break; + case AST_CASE: + { + // This detects the _overall_ sign and width to be used for comparing + // the case expression with the case item expressions. The case + // expression and case item expressions are extended to the maximum + // width among them, and are only interpreted as signed if all of them + // are signed. + width_hint = -1; + sign_hint = true; + auto visit_case_expr = [&width_hint, &sign_hint] (AstNode *node) { + int sub_width_hint = -1; + bool sub_sign_hint = true; + node->detectSignWidth(sub_width_hint, sub_sign_hint); + width_hint = max(width_hint, sub_width_hint); + sign_hint &= sub_sign_hint; + }; + visit_case_expr(children[0]); + for (size_t i = 1; i < children.size(); i++) { + AstNode *child = children[i]; + for (AstNode *v : child->children) + if (v->type != AST_DEFAULT && v->type != AST_BLOCK) + visit_case_expr(v); + } + break; + } + case AST_FCALL: if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { if (GetSize(children) == 1) { @@ -1695,7 +1725,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) SigSpec addr_sig = children[0]->genRTLIL(); cell->setPort(ID::ADDR, addr_sig); - cell->setPort(ID::DATA, children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words)); + cell->setPort(ID::DATA, children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words, true)); cell->parameters[ID::MEMID] = RTLIL::Const(str); cell->parameters[ID::ABITS] = RTLIL::Const(GetSize(addr_sig)); @@ -1754,7 +1784,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) case AST_ASSIGN: { RTLIL::SigSpec left = children[0]->genRTLIL(); - RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size()); + RTLIL::SigSpec right = children[1]->genWidthRTLIL(left.size(), true); if (left.has_const()) { RTLIL::SigSpec new_left, new_right; for (int i = 0; i < GetSize(left); i++) @@ -1979,14 +2009,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // this is a wrapper for AstNode::genRTLIL() when a specific signal width is requested and/or // signals must be substituted before being used as input values (used by ProcessGenerator) // note that this is using some global variables to communicate this special settings to AstNode::genRTLIL(). -RTLIL::SigSpec AstNode::genWidthRTLIL(int width, const dict *new_subst_ptr) +RTLIL::SigSpec AstNode::genWidthRTLIL(int width, bool sgn, const dict *new_subst_ptr) { const dict *backup_subst_ptr = genRTLIL_subst_ptr; if (new_subst_ptr) genRTLIL_subst_ptr = new_subst_ptr; - bool sign_hint = true; + bool sign_hint = sgn; int width_hint = width; detectSignWidthWorker(width_hint, sign_hint); RTLIL::SigSpec sig = genRTLIL(width_hint, sign_hint); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index b9965ba99..305f67da8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1185,8 +1185,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (const_fold && type == AST_CASE) { + int width_hint; + bool sign_hint; + detectSignWidth(width_hint, sign_hint); while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { + RTLIL::Const case_expr = children[0]->bitsAsConst(width_hint, sign_hint); std::vector new_children; new_children.push_back(children[0]); for (int i = 1; i < GetSize(children); i++) { @@ -1199,7 +1203,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, continue; while (v->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } if (v->type == AST_CONSTANT && v->bits_only_01()) { - if (v->bits == children[0]->bits) { + RTLIL::Const case_item_expr = v->bitsAsConst(width_hint, sign_hint); + RTLIL::Const match = const_eq(case_expr, case_item_expr, sign_hint, sign_hint, 1); + log_assert(match.bits.size() == 1); + if (match.bits.front() == RTLIL::State::S1) { while (i+1 < GetSize(children)) delete children[++i]; goto keep_const_cond; -- cgit v1.2.3 From 8cfed1a97957e4c096d1e0a0304d978bcb27e116 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 27 May 2021 16:47:02 -0400 Subject: sv: support tasks and functions within packages --- frontends/ast/ast.cc | 20 ++++++++++++++++++++ frontends/ast/simplify.cc | 2 +- frontends/verilog/verilog_parser.y | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 7e5cc9411..7e53713e3 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1196,6 +1196,25 @@ static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstN design->add(current_module); } +// renames identifiers in tasks and functions within a package +static void rename_in_package_stmts(AstNode *pkg) +{ + std::unordered_set idents; + for (AstNode *item : pkg->children) + idents.insert(item->str); + std::function rename = + [&rename, &idents, pkg](AstNode *node) { + for (AstNode *child : node->children) { + if (idents.count(child->str)) + child->str = pkg->str + "::" + child->str.substr(1); + rename(child); + } + }; + for (AstNode *item : pkg->children) + if (item->type == AST_FUNCTION || item->type == AST_TASK) + rename(item); +} + // create AstModule instances for all modules in the AST tree and add them to 'design' void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool pwires, bool nooverwrite, bool overwrite, bool defer, bool autowire) @@ -1284,6 +1303,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump else if (child->type == AST_PACKAGE) { // process enum/other declarations child->simplify(true, false, false, 1, -1, false, false); + rename_in_package_stmts(child); design->verilog_packages.push_back(child->clone()); current_scope.clear(); } diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 305f67da8..517647afb 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -875,7 +875,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; // these nodes appear at the top level in a package and can define names - if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF) { + if (node->type == AST_PARAMETER || node->type == AST_LOCALPARAM || node->type == AST_TYPEDEF || node->type == AST_FUNCTION || node->type == AST_TASK) { current_scope[node->str] = node; } if (node->type == AST_ENUM) { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index c2b43f45b..93ddbec91 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -593,7 +593,7 @@ package_body: package_body package_body_stmt | %empty; package_body_stmt: - typedef_decl | localparam_decl | param_decl; + typedef_decl | localparam_decl | param_decl | task_func_decl; interface: TOK_INTERFACE { -- cgit v1.2.3 From 72787f52fc31954e4b7dc3dc34d86705fc4e9dd1 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Tue, 8 Jun 2021 00:39:36 +0200 Subject: Fixing old e-mail addresses and deadnames s/((Claire|Xen|Xenia|Clifford)\s+)+(Wolf|Xen)\s+<(claire|clifford)@(symbioticeda.com|clifford.at|yosyshq.com)>/Claire Xenia Wolf /gi; s/((Nina|Nak|N\.)\s+)+Engelhardt\s+/N. Engelhardt /gi; s/((David)\s+)+Shah\s+<(dave|david)@(symbioticeda.com|yosyshq.com|ds0.me)>/David Shah /gi; s/((Miodrag)\s+)+Milanovic\s+<(miodrag|micko)@(symbioticeda.com|yosyshq.com)>/Miodrag Milanovic /gi; s,https?://www.clifford.at/yosys/,http://yosyshq.net/yosys/,g; --- frontends/aiger/aigerparse.cc | 2 +- frontends/aiger/aigerparse.h | 2 +- frontends/ast/ast.cc | 2 +- frontends/ast/ast.h | 2 +- frontends/ast/dpicall.cc | 2 +- frontends/ast/genrtlil.cc | 2 +- frontends/ast/simplify.cc | 2 +- frontends/blif/blifparse.cc | 2 +- frontends/blif/blifparse.h | 2 +- frontends/json/jsonparse.cc | 2 +- frontends/liberty/liberty.cc | 2 +- frontends/rtlil/rtlil_frontend.cc | 2 +- frontends/rtlil/rtlil_frontend.h | 2 +- frontends/rtlil/rtlil_lexer.l | 2 +- frontends/rtlil/rtlil_parser.y | 2 +- frontends/verific/verific.cc | 2 +- frontends/verific/verific.h | 2 +- frontends/verific/verificsva.cc | 2 +- frontends/verilog/const2ast.cc | 2 +- frontends/verilog/preproc.cc | 2 +- frontends/verilog/preproc.h | 2 +- frontends/verilog/verilog_frontend.cc | 2 +- frontends/verilog/verilog_frontend.h | 2 +- frontends/verilog/verilog_lexer.l | 2 +- frontends/verilog/verilog_parser.y | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) (limited to 'frontends') diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index 463c5965b..cb19b8413 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * 2019 Eddie Hung * * Permission to use, copy, modify, and/or distribute this software for any diff --git a/frontends/aiger/aigerparse.h b/frontends/aiger/aigerparse.h index 251a24977..81b955947 100644 --- a/frontends/aiger/aigerparse.h +++ b/frontends/aiger/aigerparse.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * 2019 Eddie Hung * * Permission to use, copy, modify, and/or distribute this software for any diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 7e53713e3..f33b76785 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * Copyright (C) 2018 Ruben Undheim * * Permission to use, copy, modify, and/or distribute this software for any diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 9887d24ea..bb9f42a05 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -1,7 +1,7 @@ /* -*- c++ -*- * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/ast/dpicall.cc b/frontends/ast/dpicall.cc index 948c9083c..12a7e1183 100644 --- a/frontends/ast/dpicall.cc +++ b/frontends/ast/dpicall.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index b8b9f715e..902fbb01b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 517647afb..38ca5e063 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/blif/blifparse.cc b/frontends/blif/blifparse.cc index 52b46c228..19844bda6 100644 --- a/frontends/blif/blifparse.cc +++ b/frontends/blif/blifparse.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/blif/blifparse.h b/frontends/blif/blifparse.h index 2b84cb795..d7a3c96b1 100644 --- a/frontends/blif/blifparse.h +++ b/frontends/blif/blifparse.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/json/jsonparse.cc b/frontends/json/jsonparse.cc index cbfa038a1..50c25abda 100644 --- a/frontends/json/jsonparse.cc +++ b/frontends/json/jsonparse.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/liberty/liberty.cc b/frontends/liberty/liberty.cc index f77d7da56..abf8de4d1 100644 --- a/frontends/liberty/liberty.cc +++ b/frontends/liberty/liberty.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/rtlil/rtlil_frontend.cc b/frontends/rtlil/rtlil_frontend.cc index 00c34175e..5f85ca2b8 100644 --- a/frontends/rtlil/rtlil_frontend.cc +++ b/frontends/rtlil/rtlil_frontend.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/rtlil/rtlil_frontend.h b/frontends/rtlil/rtlil_frontend.h index a420778b0..189260605 100644 --- a/frontends/rtlil/rtlil_frontend.h +++ b/frontends/rtlil/rtlil_frontend.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/rtlil/rtlil_lexer.l b/frontends/rtlil/rtlil_lexer.l index 897ebf667..e16413216 100644 --- a/frontends/rtlil/rtlil_lexer.l +++ b/frontends/rtlil/rtlil_lexer.l @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y index 7a8f508bf..0e6eacf88 100644 --- a/frontends/rtlil/rtlil_parser.y +++ b/frontends/rtlil/rtlil_parser.y @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 7aa3ebcbb..979309248 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index f168a2588..f79d8042a 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 1f5da1b1d..1bbdcf016 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/const2ast.cc b/frontends/verilog/const2ast.cc index 230dfadbf..a4dfbc7ec 100644 --- a/frontends/verilog/const2ast.cc +++ b/frontends/verilog/const2ast.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 568224da2..4b9ebe0aa 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index 673d633c0..e1048156c 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 84ac73e91..ad0bb9ff7 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index aa7881038..30f1c1180 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index f52928c77..b29e625d6 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 93ddbec91..10d904dbd 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1,7 +1,7 @@ /* * yosys -- Yosys Open SYnthesis Suite * - * Copyright (C) 2012 Clifford Wolf + * Copyright (C) 2012 Claire Xenia Wolf * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- cgit v1.2.3 From c79fbfe0a130f1a2979413174c3e5688433bafe3 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 26 May 2021 18:22:31 -0400 Subject: mem2reg: tolerate out of bounds constant accesses This brings the mem2reg behavior in line with the nomem2reg behavior. --- frontends/ast/simplify.cc | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 517647afb..44b11da74 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1762,7 +1762,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // split memory access with bit select to individual statements - if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue) + if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE && !in_lvalue && stage == 2) { if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1) log_file_error(filename, location.first_line, "Invalid bit-select on memory access!\n"); @@ -4501,11 +4501,48 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, if (children[0]->children[0]->type == AST_CONSTANT) { int id = children[0]->children[0]->integer; - str = stringf("%s[%d]", str.c_str(), id); + int left = id2ast->children[1]->children[0]->integer; + int right = id2ast->children[1]->children[1]->integer; + bool valid_const_access = + (left <= id && id <= right) || + (right <= id && id <= left); + if (valid_const_access) + { + str = stringf("%s[%d]", str.c_str(), id); + delete_children(); + range_valid = false; + id2ast = NULL; + } + else + { + int width; + if (bit_part_sel) + { + bit_part_sel->dumpAst(nullptr, "? "); + if (bit_part_sel->children.size() == 1) + width = 0; + else + width = bit_part_sel->children[0]->integer - + bit_part_sel->children[1]->integer; + delete bit_part_sel; + bit_part_sel = nullptr; + } + else + { + width = id2ast->children[0]->children[0]->integer - + id2ast->children[0]->children[1]->integer; + } + width = abs(width) + 1; - delete_children(); - range_valid = false; - id2ast = NULL; + delete_children(); + + std::vector x_bits; + for (int i = 0; i < width; i++) + x_bits.push_back(RTLIL::State::Sx); + AstNode *constant = AstNode::mkconst_bits(x_bits, false); + constant->cloneInto(this); + delete constant; + } } else { -- cgit v1.2.3 From 2e697f5655455fd8ce5fec40b94683a11ade24e8 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Sat, 5 Jun 2021 16:21:09 -0400 Subject: verilog: check for module scope identifiers during width detection The recent fix for case expression width detection causes the width of the expressions to be queried before they are simplified. Because the logic supporting module scope identifiers only existed in simplify, looking them up would fail during width detection. This moves the logic to a common helper used in both simplify() and detectSignWidthWorker(). --- frontends/ast/ast.h | 3 +++ frontends/ast/genrtlil.cc | 11 +++++++++-- frontends/ast/simplify.cc | 29 ++++++++++++++++++----------- 3 files changed, 30 insertions(+), 13 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 9887d24ea..b6b15b738 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -326,6 +326,9 @@ namespace AST // helpers for locations std::string loc_string() const; + + // Helper for looking up identifiers which are prefixed with the current module name + std::string try_pop_module_prefix() const; }; // process an AST tree (ast must point to an AST_DESIGN node) and generate RTLIL code diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index b8b9f715e..e886844be 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -767,8 +767,15 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_IDENTIFIER: id_ast = id2ast; - if (id_ast == NULL && current_scope.count(str)) - id_ast = current_scope.at(str); + if (!id_ast) { + if (current_scope.count(str)) + id_ast = current_scope[str]; + else { + std::string alt = try_pop_module_prefix(); + if (current_scope.count(alt)) + id_ast = current_scope[alt]; + } + } if (!id_ast) log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", str.c_str()); if (id_ast->type == AST_PARAMETER || id_ast->type == AST_LOCALPARAM || id_ast->type == AST_ENUM_ITEM) { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 44b11da74..cd27a720a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1698,17 +1698,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (type == AST_IDENTIFIER) { if (current_scope.count(str) == 0) { AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; - size_t pos = str.find('.', 1); - if (str[0] == '\\' && pos != std::string::npos) { - std::string new_str = "\\" + str.substr(pos + 1); - if (current_scope.count(new_str)) { - std::string prefix = str.substr(0, pos); - auto it = current_scope_ast->attributes.find(ID::hdlname); - if ((it != current_scope_ast->attributes.end() && it->second->str == prefix) - || prefix == current_scope_ast->str) - str = new_str; - } - } + str = try_pop_module_prefix(); for (auto node : current_scope_ast->children) { //log("looking at mod scope child %s\n", type2str(node->type).c_str()); switch (node->type) { @@ -5124,4 +5114,21 @@ std::pair AstNode::get_tern_choice() return {choice, not_choice}; } +std::string AstNode::try_pop_module_prefix() const +{ + AstNode *current_scope_ast = (current_ast_mod == nullptr) ? current_ast : current_ast_mod; + size_t pos = str.find('.', 1); + if (str[0] == '\\' && pos != std::string::npos) { + std::string new_str = "\\" + str.substr(pos + 1); + if (current_scope.count(new_str)) { + std::string prefix = str.substr(0, pos); + auto it = current_scope_ast->attributes.find(ID::hdlname); + if ((it != current_scope_ast->attributes.end() && it->second->str == prefix) + || prefix == current_scope_ast->str) + return new_str; + } + } + return str; +} + YOSYS_NAMESPACE_END -- cgit v1.2.3 From 801ecc0e1d75f092981361632265edce67130a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 14 Jun 2021 16:28:10 +0200 Subject: verilog: Squash a memory leak. That was added in ecc22f7fedfa639482dbc55a05709da85116a60f --- frontends/verilog/verilog_frontend.cc | 12 ++++-------- frontends/verilog/verilog_frontend.h | 2 +- frontends/verilog/verilog_lexer.l | 2 +- frontends/verilog/verilog_parser.y | 17 ++++++++--------- 4 files changed, 14 insertions(+), 19 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index ad0bb9ff7..9b277c6b9 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -482,18 +482,18 @@ struct VerilogFrontend : public Frontend { // make package typedefs available to parser add_package_types(pkg_user_types, design->verilog_packages); - UserTypeMap *global_types_map = new UserTypeMap(); + UserTypeMap global_types_map; for (auto def : design->verilog_globals) { if (def->type == AST::AST_TYPEDEF) { - (*global_types_map)[def->str] = def; + global_types_map[def->str] = def; } } log_assert(user_type_stack.empty()); // use previous global typedefs as bottom level of user type stack - user_type_stack.push_back(global_types_map); + user_type_stack.push_back(std::move(global_types_map)); // add a new empty type map to allow overriding existing global definitions - user_type_stack.push_back(new UserTypeMap()); + user_type_stack.push_back(UserTypeMap()); frontend_verilog_yyset_lineno(1); frontend_verilog_yyrestart(NULL); @@ -519,10 +519,6 @@ struct VerilogFrontend : public Frontend { // only the previous and new global type maps remain log_assert(user_type_stack.size() == 2); - for (auto it : user_type_stack) { - // the global typedefs have to remain valid for future invocations, so just drop the map without deleting values - delete it; - } user_type_stack.clear(); delete current_ast; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 30f1c1180..8454e7999 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -47,7 +47,7 @@ namespace VERILOG_FRONTEND // names of locally typedef'ed types in a stack typedef std::map UserTypeMap; - extern std::vector user_type_stack; + extern std::vector user_type_stack; // names of package typedef'ed types extern dict pkg_user_types; diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index b29e625d6..55e8b48b9 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -103,7 +103,7 @@ static bool isUserType(std::string &s) { // check current scope then outer scopes for a name for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { - if ((*it)->count(s) > 0) { + if (it->count(s) > 0) { return true; } } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 10d904dbd..3f4bf5bfd 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -54,7 +54,7 @@ namespace VERILOG_FRONTEND { dict *attr_list, default_attr_list; std::stack *> attr_list_stack; dict *albuf; - std::vector user_type_stack; + std::vector user_type_stack; dict pkg_user_types; std::vector ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; @@ -132,8 +132,8 @@ static void addTypedefNode(std::string *name, AstNode *node) log_assert(node); auto *tnode = new AstNode(AST_TYPEDEF, node); tnode->str = *name; - auto user_types = user_type_stack.back(); - (*user_types)[*name] = tnode; + auto &user_types = user_type_stack.back(); + user_types[*name] = tnode; if (current_ast_mod && current_ast_mod->type == AST_PACKAGE) { // typedef inside a package so we need the qualified name auto qname = current_ast_mod->str + "::" + (*name).substr(1); @@ -145,8 +145,7 @@ static void addTypedefNode(std::string *name, AstNode *node) static void enterTypeScope() { - auto user_types = new UserTypeMap(); - user_type_stack.push_back(user_types); + user_type_stack.push_back(UserTypeMap()); } static void exitTypeScope() @@ -157,17 +156,17 @@ static void exitTypeScope() static bool isInLocalScope(const std::string *name) { // tests if a name was declared in the current block scope - auto user_types = user_type_stack.back(); - return (user_types->count(*name) > 0); + auto &user_types = user_type_stack.back(); + return (user_types.count(*name) > 0); } static AstNode *getTypeDefinitionNode(std::string type_name) { // check current scope then outer scopes for a name for (auto it = user_type_stack.rbegin(); it != user_type_stack.rend(); ++it) { - if ((*it)->count(type_name) > 0) { + if (it->count(type_name) > 0) { // return the definition nodes from the typedef statement - auto typedef_node = (**it)[type_name]; + auto typedef_node = (*it)[type_name]; log_assert(typedef_node->type == AST_TYPEDEF); return typedef_node->children[0]; } -- cgit v1.2.3 From 9ca5a91724e114ebb8c04be8edfc0f2f5e8073a9 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 17 Mar 2021 00:08:43 +0100 Subject: ast: fix error condition causing assert to fail type2str returns a string that doesn't start with $ or \, so it can't be assigned to an IdString. --- frontends/ast/genrtlil.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 52e057486..6b119b7ff 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -2006,8 +2006,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) default: for (auto f : log_files) current_ast_mod->dumpAst(f, "verilog-ast> "); - type_name = type2str(type); - log_file_error(filename, location.first_line, "Don't know how to generate RTLIL code for %s node!\n", type_name.c_str()); + log_file_error(filename, location.first_line, "Don't know how to generate RTLIL code for %s node!\n", type2str(type).c_str()); } return RTLIL::SigSpec(); -- cgit v1.2.3 From 091295a5a533c44a4ad20d297fdad1ec2a77903c Mon Sep 17 00:00:00 2001 From: Xiretza Date: Tue, 16 Mar 2021 16:43:03 +0100 Subject: verilog: fix leaking ASTNodes --- frontends/ast/simplify.cc | 5 +++++ frontends/verilog/verilog_parser.y | 17 ++++++++++------- 2 files changed, 15 insertions(+), 7 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 500288de0..8ef681069 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2303,6 +2303,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (left_at_zero_ast->type != AST_CONSTANT || right_at_zero_ast->type != AST_CONSTANT) log_file_error(filename, location.first_line, "Unsupported expression on dynamic range select on signal `%s'!\n", str.c_str()); result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; + delete left_at_zero_ast; + delete right_at_zero_ast; } bool use_case_method = false; @@ -3534,6 +3536,8 @@ skip_dynamic_range_lvalue_expansion:; // convert purely constant arguments into localparams if (child->is_input && child->type == AST_WIRE && arg->type == AST_CONSTANT && node_contains_assignment_to(decl, child)) { wire->type = AST_LOCALPARAM; + if (wire->attributes.count(ID::nosync)) + delete wire->attributes.at(ID::nosync); wire->attributes.erase(ID::nosync); wire->children.insert(wire->children.begin(), arg->clone()); // args without a range implicitly have width 1 @@ -3557,6 +3561,7 @@ skip_dynamic_range_lvalue_expansion:; } // updates the sizing while (wire->simplify(true, false, false, 1, -1, false, false)) { } + delete arg; continue; } AstNode *wire_id = new AstNode(AST_IDENTIFIER); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 3f4bf5bfd..4e601b51d 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -503,18 +503,19 @@ optional_comma: module_arg_opt_assignment: '=' expr { if (ast_stack.back()->children.size() > 0 && ast_stack.back()->children.back()->type == AST_WIRE) { - AstNode *wire = new AstNode(AST_IDENTIFIER); - wire->str = ast_stack.back()->children.back()->str; if (ast_stack.back()->children.back()->is_input) { AstNode *n = ast_stack.back()->children.back(); if (n->attributes.count(ID::defaultvalue)) delete n->attributes.at(ID::defaultvalue); n->attributes[ID::defaultvalue] = $2; - } else - if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) - ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); + } else { + AstNode *wire = new AstNode(AST_IDENTIFIER); + wire->str = ast_stack.back()->children.back()->str; + if (ast_stack.back()->children.back()->is_reg || ast_stack.back()->children.back()->is_logic) + ast_stack.back()->children.push_back(new AstNode(AST_INITIAL, new AstNode(AST_BLOCK, new AstNode(AST_ASSIGN_LE, wire, $2)))); + else + ast_stack.back()->children.push_back(new AstNode(AST_ASSIGN, wire, $2)); + } } else frontend_verilog_yyerror("SystemVerilog interface in module port list cannot have a default value."); } | @@ -1158,6 +1159,8 @@ specify_item: cell->children.back()->str = "\\DST"; delete $1; + delete limit; + delete limit2; }; specify_opt_triple: -- cgit v1.2.3 From 62a42c317c41590b654f59851b4730c89bfcd7ae Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 17 Mar 2021 00:14:27 +0100 Subject: ast: delete wires and localparams after finishing const evaluation --- frontends/ast/simplify.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 8ef681069..f85306423 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -4774,6 +4774,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) { std::map backup_scope = current_scope; std::map variables; + std::vector to_delete; AstNode *block = new AstNode(AST_BLOCK); AstNode *result = nullptr; @@ -4831,6 +4832,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) current_scope[stmt->str] = stmt; block->children.erase(block->children.begin()); + to_delete.push_back(stmt); continue; } @@ -4843,6 +4845,7 @@ AstNode *AstNode::eval_const_function(AstNode *fcall, bool must_succeed) current_scope[stmt->str] = stmt; block->children.erase(block->children.begin()); + to_delete.push_back(stmt); continue; } @@ -5038,6 +5041,11 @@ finished: delete block; current_scope = backup_scope; + for (auto it : to_delete) { + delete it; + } + to_delete.clear(); + return result; } -- cgit v1.2.3 From b57e47fad8b4ecd5438ee49c618fc8978a4bb058 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 18 Mar 2021 10:38:36 +0100 Subject: verilog: fix wildcard port connections leaking memory --- frontends/verilog/verilog_parser.y | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 4e601b51d..7d750ea28 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2084,6 +2084,7 @@ cell_port: if (!sv_mode) frontend_verilog_yyerror("Wildcard port connections are only supported in SystemVerilog mode."); astbuf2->attributes[ID::wildcard_port_conns] = AstNode::mkconst_int(1, false); + free_attr($1); }; always_comb_or_latch: -- cgit v1.2.3 From c6681508f1a2e35d41e8fc6f1f5dec41972ef6fd Mon Sep 17 00:00:00 2001 From: Xiretza Date: Thu, 18 Mar 2021 21:52:06 +0100 Subject: verilog: fix leaking of type names in parser --- frontends/verilog/verilog_parser.y | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 7d750ea28..1a76d0dea 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -692,6 +692,7 @@ wire_type_token: astbuf3->is_custom_type = true; astbuf3->children.push_back(new AstNode(AST_WIRETYPE)); astbuf3->children.back()->str = *$1; + delete $1; } | TOK_WOR { astbuf3->is_wor = true; @@ -1458,6 +1459,7 @@ param_type: astbuf1->is_custom_type = true; astbuf1->children.push_back(new AstNode(AST_WIRETYPE)); astbuf1->children.back()->str = *$1; + delete $1; }; param_decl: -- cgit v1.2.3 From c0d8da20d58d13ae5bb169ce587f05fbb851a8d0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 16 Jun 2021 11:21:44 +0200 Subject: Support command files in Verific --- frontends/verific/verific.cc | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 979309248..3e91673ac 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2084,6 +2084,11 @@ struct VerificPass : public Pass { log("Load the specified VHDL files into Verific.\n"); log("\n"); log("\n"); + log(" verific {-f|-F} \n"); + log("\n"); + log("Load and execute the specified command file.\n"); + log("\n"); + log("\n"); log(" verific [-work ] {-sv|-vhdl|...} \n"); log("\n"); log("Load the specified Verilog/SystemVerilog/VHDL file into the specified library.\n"); @@ -2407,6 +2412,25 @@ struct VerificPass : public Pass { break; } + if (GetSize(args) > argidx && (args[argidx] == "-f" || args[argidx] == "-F")) + { + unsigned verilog_mode = veri_file::VERILOG_95; // default recommended by Verific + + Verific::veri_file::f_file_flags flags = (args[argidx] == "-f") ? veri_file::F_FILE_NONE : veri_file::F_FILE_CAPITAL; + Array *file_names = veri_file::ProcessFFile(args[++argidx].c_str(), flags, verilog_mode); + + veri_file::DefineMacro("VERIFIC"); + + if (!veri_file::AnalyzeMultipleFiles(file_names, verilog_mode, work.c_str(), veri_file::MFCU)) { + verific_error_msg.clear(); + log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n"); + } + + delete file_names; + verific_import_pending = true; + goto check_error; + } + if (GetSize(args) > argidx && (args[argidx] == "-vlog95" || args[argidx] == "-vlog2k" || args[argidx] == "-sv2005" || args[argidx] == "-sv2009" || args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal")) { @@ -2963,6 +2987,11 @@ struct ReadPass : public Pass { log("Load the specified VHDL files. (Requires Verific.)\n"); log("\n"); log("\n"); + log(" read {-f|-F} \n"); + log("\n"); + log("Load and execute the specified command file. (Requires Verific.)\n"); + log("\n"); + log("\n"); log(" read -define [=]..\n"); log("\n"); log("Set global Verilog/SystemVerilog defines.\n"); @@ -3049,6 +3078,16 @@ struct ReadPass : public Pass { return; } + if (args[1] == "-f" || args[1] == "-F") { + if (use_verific) { + args[0] = "verific"; + Pass::call(design, args); + } else { + cmd_error(args, 1, "This version of Yosys is built without Verific support.\n"); + } + return; + } + if (args[1] == "-define") { if (use_verific) { args[0] = "verific"; -- cgit v1.2.3 From f2c2d73f36d7aaef90ded549143d1ee0c4d4a9f5 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 14 Jun 2021 15:32:01 -0400 Subject: sv: fix up end label checking - disallow [gen]blocks with an end label but not begin label - check validity of module end label - fix memory leak of package name and end label - fix memory leak of module end label --- frontends/verilog/verilog_parser.y | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 1a76d0dea..120a8bca3 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -235,6 +235,16 @@ static void rewriteAsMemoryNode(AstNode *node, AstNode *rangeNode) node->children.push_back(rangeNode); } +static void checkLabelsMatch(const char *element, const std::string *before, const std::string *after) +{ + if (!before && after) + frontend_verilog_yyerror("%s missing where end label (%s) was given.", + element, after->c_str() + 1); + if (before && after && *before != *after) + frontend_verilog_yyerror("%s (%s) and end label (%s) don't match.", + element, before->c_str() + 1, after->c_str() + 1); +} + %} %define api.prefix {frontend_verilog_yy} @@ -457,7 +467,6 @@ module: port_counter = 0; mod->str = *$4; append_attr(mod, $1); - delete $4; } module_para_opt module_args_opt ';' module_body TOK_ENDMODULE opt_label { if (port_stubs.size() != 0) frontend_verilog_yyerror("Missing details for module port `%s'.", @@ -465,7 +474,10 @@ module: SET_AST_NODE_LOC(ast_stack.back(), @2, @$); ast_stack.pop_back(); log_assert(ast_stack.size() == 1); + checkLabelsMatch("Module name", $4, $11); current_ast_mod = NULL; + delete $4; + delete $11; exitTypeScope(); }; @@ -583,9 +595,10 @@ package: append_attr(mod, $1); } ';' package_body TOK_ENDPACKAGE opt_label { ast_stack.pop_back(); - if ($4 != NULL && $9 != NULL && *$4 != *$9) - frontend_verilog_yyerror("Package name (%s) and end label (%s) don't match.", $4->c_str()+1, $9->c_str()+1); + checkLabelsMatch("Package name", $4, $9); current_ast_mod = NULL; + delete $4; + delete $9; exitTypeScope(); }; @@ -2526,8 +2539,7 @@ behavioral_stmt: node->str = *$4; } behavioral_stmt_list TOK_END opt_label { exitTypeScope(); - if ($4 != NULL && $8 != NULL && *$4 != *$8) - frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $4->c_str()+1, $8->c_str()+1); + checkLabelsMatch("Begin label", $4, $8); AstNode *node = ast_stack.back(); // In SystemVerilog, unnamed blocks with block item declarations // create an implicit hierarchy scope @@ -2863,8 +2875,7 @@ gen_block: ast_stack.push_back(node); } module_gen_body TOK_END opt_label { exitTypeScope(); - if ($3 != NULL && $7 != NULL && *$3 != *$7) - frontend_verilog_yyerror("Begin label (%s) and end label (%s) don't match.", $3->c_str()+1, $7->c_str()+1); + checkLabelsMatch("Begin label", $3, $7); delete $3; delete $7; SET_AST_NODE_LOC(ast_stack.back(), @1, @7); -- cgit v1.2.3 From 0dbb05a75e1bb92c194ce6305fee02bf2e5e0470 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 5 Jul 2021 09:16:54 +0200 Subject: Add additional help --- frontends/verific/verific.cc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 3e91673ac..9e99af680 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2088,6 +2088,27 @@ struct VerificPass : public Pass { log("\n"); log("Load and execute the specified command file.\n"); log("\n"); + log("Command file parser supports following commands:\n"); + log(" +define - defines macro\n"); + log(" -u - upper case all identifier (makes Verilog parser case insensitive)\n"); + log(" -v - register library name (file)\n"); + log(" -y - register library name (directory)\n"); + log(" +incdir - specify include dir\n"); + log(" +libext - specify library extension\n"); + log(" +liborder - add library in ordered list\n"); + log(" +librescan - unresolved modules will be always searched starting with the first\n"); + log(" library specified by -y/-v options.\n"); + log(" -f/-file - nested -f option\n"); + log(" -F - nested -F option\n"); + log("\n"); + log(" parse mode:\n"); + log(" -ams\n"); + log(" +systemverilogext\n"); + log(" +v2k\n"); + log(" +verilog1995ext\n"); + log(" +verilog2001ext\n"); + log(" -sverilog\n"); + log("\n"); log("\n"); log(" verific [-work ] {-sv|-vhdl|...} \n"); log("\n"); @@ -2990,6 +3011,7 @@ struct ReadPass : public Pass { log(" read {-f|-F} \n"); log("\n"); log("Load and execute the specified command file. (Requires Verific.)\n"); + log("Check verific command for more information about supported commands in file.\n"); log("\n"); log("\n"); log(" read -define [=]..\n"); -- cgit v1.2.3 From 4446cfa524cf06e84add450214f64b2de6e199c3 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 17 Jun 2021 15:59:59 -0400 Subject: sv: fix a few struct and enum memory leaks --- frontends/ast/simplify.cc | 7 +++++++ frontends/verilog/verilog_parser.y | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f85306423..695fc429d 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -331,6 +331,8 @@ static int size_packed_struct(AstNode *snode, int base_offset) } } // range nodes are now redundant + for (AstNode *child : node->children) + delete child; node->children.clear(); } else if (node->children.size() == 1 && node->children[0]->type == AST_MULTIRANGE) { @@ -345,6 +347,8 @@ static int size_packed_struct(AstNode *snode, int base_offset) save_struct_array_width(node, width); width *= array_count; // range nodes are now redundant + for (AstNode *child : node->children) + delete child; node->children.clear(); } else if (node->range_left < 0) { @@ -5052,6 +5056,9 @@ finished: void AstNode::allocateDefaultEnumValues() { log_assert(type==AST_ENUM); + log_assert(children.size() > 0); + if (children.front()->attributes.count(ID::enum_base_type)) + return; // already elaborated int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 120a8bca3..9558b0e87 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1711,10 +1711,12 @@ member_type_token: delete astbuf1; astbuf1 = template_node; } - | struct_union { + | { + delete astbuf1; + } struct_union { // stash state on ast_stack ast_stack.push_back(astbuf2); - astbuf2 = $1; + astbuf2 = $2; } struct_body { astbuf1 = astbuf2; // recover state -- cgit v1.2.3 From 7a5ac909858c22f2daf2f7ca63869c554dc3b9b5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 9 Jul 2021 09:02:27 +0200 Subject: Update to latest Verific with extensions for initial assertions --- frontends/verific/verific.cc | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 9e99af680..997a8e826 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -50,15 +50,13 @@ USING_YOSYS_NAMESPACE #include "VhdlUnits.h" #include "VeriLibrary.h" -#if defined(YOSYSHQ_VERIFIC_INITSTATE) || defined(YOSYSHQ_VERIFIC_TEMPLATES) || defined(YOSYSHQ_VERIFIC_FORMALAPPS) -#include "VeriExtensions.h" -#endif +#include "InitialAssertions.h" #ifndef YOSYSHQ_VERIFIC_API_VERSION # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210103 +#if YOSYSHQ_VERIFIC_API_VERSION < 20210602 # error "Please update your version of YosysHQ flavored Verific." #endif @@ -1474,9 +1472,10 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se continue; } -#ifdef YOSYSHQ_VERIFIC_INITSTATE if (inst->Type() == PRIM_YOSYSHQ_INITSTATE) { + if (verific_verbose) + log(" adding YosysHQ init state\n"); SigBit initstate = module->Initstate(new_verific_id(inst)); SigBit sig_o = net_map_at(inst->GetOutput()); module->connect(sig_o, initstate); @@ -1484,7 +1483,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se if (!mode_keep) continue; } -#endif + if (!mode_keep && verific_sva_prims.count(inst->Type())) { if (verific_verbose) log(" skipping SVA cell in non k-mode\n"); @@ -1962,10 +1961,8 @@ void verific_import(Design *design, const std::map &par for (const auto &i : parameters) verific_params.Insert(i.first.c_str(), i.second.c_str()); -#ifdef YOSYSHQ_VERIFIC_INITSTATE - InitialAssertionRewriter rw; - rw.RegisterCallBack(); -#endif + InitialAssertions::Rewrite("work"); + if (top.empty()) { netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); } @@ -2850,10 +2847,8 @@ struct VerificPass : public Pass { std::set top_mod_names; -#ifdef YOSYSHQ_VERIFIC_INITSTATE - InitialAssertionRewriter rw; - rw.RegisterCallBack(); -#endif + InitialAssertions::Rewrite(work); + if (mode_all) { log("Running hier_tree::ElaborateAll().\n"); -- cgit v1.2.3 From 009940f56ca71cc8655a13a514371eb5757b96ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Sun, 11 Jul 2021 23:57:53 +0200 Subject: rtlil: Make Process handling more uniform with Cell and Wire. - add a backlink to module from Process - make constructor and destructor protected, expose Module functions to add and remove processes --- frontends/ast/genrtlil.cc | 4 +--- frontends/rtlil/rtlil_parser.y | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 6b119b7ff..e6f7b30c1 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -319,16 +319,14 @@ struct AST_INTERNAL::ProcessGenerator LookaheadRewriter la_rewriter(always); // generate process and simple root case - proc = new RTLIL::Process; + proc = current_module->addProcess(stringf("$proc$%s:%d$%d", always->filename.c_str(), always->location.first_line, autoidx++)); set_src_attr(proc, always); - proc->name = stringf("$proc$%s:%d$%d", always->filename.c_str(), always->location.first_line, autoidx++); for (auto &attr : always->attributes) { if (attr.second->type != AST_CONSTANT) log_file_error(always->filename, always->location.first_line, "Attribute `%s' with non-constant value!\n", attr.first.c_str()); proc->attributes[attr.first] = attr.second->asAttrConst(); } - current_module->processes[proc->name] = proc; current_case = &proc->root_case; // create initial temporary signal for all output registers diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y index 0e6eacf88..67aeb10e0 100644 --- a/frontends/rtlil/rtlil_parser.y +++ b/frontends/rtlil/rtlil_parser.y @@ -283,10 +283,8 @@ 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 = current_module->addProcess($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(); -- cgit v1.2.3 From a9c8ca21d583c58a38931389f90bbaae0caec0d6 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 22 Jun 2021 10:39:57 -0400 Subject: sv: fix two struct access bugs - preserve signedness of struct members - fix initial width detection of struct members (e.g., in case expressions) --- frontends/ast/ast.h | 3 +++ frontends/ast/genrtlil.cc | 4 ++++ frontends/ast/simplify.cc | 4 +++- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 2bda8fa92..60c7de32d 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -370,6 +370,9 @@ namespace AST // Helper for setting the src attribute. void set_src_attr(RTLIL::AttrObject *obj, const AstNode *ast); + + // struct helper exposed from simplify for genrtlil + AstNode *make_struct_member_range(AstNode *node, AstNode *member_node); } namespace AST_INTERNAL diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index e6f7b30c1..29d0bddef 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -812,6 +812,10 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun this_width = id_ast->children[0]->range_left - id_ast->children[0]->range_right + 1; if (children.size() > 1) range = children[1]; + } else if (id_ast->type == AST_STRUCT_ITEM) { + AstNode *tmp_range = make_struct_member_range(this, id_ast); + this_width = tmp_range->range_left - tmp_range->range_right + 1; + delete tmp_range; } else log_file_error(filename, location.first_line, "Failed to detect width for identifier %s!\n", str.c_str()); if (range) { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 695fc429d..5845c0501 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -456,7 +456,7 @@ static AstNode *slice_range(AstNode *rnode, AstNode *snode) } -static AstNode *make_struct_member_range(AstNode *node, AstNode *member_node) +AstNode *AST::make_struct_member_range(AstNode *node, AstNode *member_node) { // Work out the range in the packed array that corresponds to a struct member // taking into account any range operations applicable to the current node @@ -1693,6 +1693,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode = new AstNode(AST_IDENTIFIER, range); newNode->str = sname; newNode->basic_prep = true; + if (item_node->is_signed) + newNode = new AstNode(AST_TO_SIGNED, newNode); goto apply_newNode; } } -- cgit v1.2.3 From 414154dd275b8cf9f0ffa071d12fc20fd6fee503 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Thu, 21 May 2020 17:36:29 +0100 Subject: Add support for parsing the SystemVerilog 'bind' construct This doesn't do anything useful yet: the patch just adds support for the syntax to the lexer and parser and adds some tests to check the syntax parses properly. This generates AST nodes, but doesn't yet generate RTLIL. Since our existing hierarchical_identifier parser doesn't allow bit selects (so you can't do something like foo[1].bar[2].baz), I've also not added support for a trailing bit select (the "constant_bit_select" non-terminal in "bind_target_instance" in the spec). If we turn out to need this in future, we'll want to augment hierarchical_identifier and its other users too. Note that you can't easily use the BNF from the spec: bind_directive ::= "bind" bind_target_scope [ : bind_target_instance_list] bind_instantiation ; | "bind" bind_target_instance bind_instantiation ; even if you fix the lookahead problem, because code like this matches both branches in the BNF: bind a b b_i (.*); The problem is that 'a' could either be a module name or a degenerate hierarchical reference. This seems to be a genuine syntactic ambiguity, which the spec resolves (p739) by saying that we have to wait until resolution time (the hierarchy pass) and take whatever is defined, treating 'a' as an instance name if it names both an instance and a module. To keep the parser simple, it currently accepts this invalid syntax: bind a.b : c d e (.*); This is invalid because we're in the first branch of the BNF above, so the "a.b" term should match bind_target_scope: a module or interface identifier, not an arbitrary hierarchical identifier. This will fail in the hierarchy pass (when it's implemented in a future patch). --- frontends/ast/ast.cc | 1 + frontends/ast/ast.h | 3 +- frontends/ast/genrtlil.cc | 5 +++ frontends/verilog/verilog_lexer.l | 1 + frontends/verilog/verilog_parser.y | 77 ++++++++++++++++++++++++++++++++++++-- 5 files changed, 83 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index f33b76785..e42cf0348 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -177,6 +177,7 @@ std::string AST::type2str(AstNodeType type) X(AST_STRUCT) X(AST_UNION) X(AST_STRUCT_ITEM) + X(AST_BIND) #undef X default: log_abort(); diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 60c7de32d..57ce5605f 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -160,7 +160,8 @@ namespace AST AST_TYPEDEF, AST_STRUCT, AST_UNION, - AST_STRUCT_ITEM + AST_STRUCT_ITEM, + AST_BIND }; struct AstSrcLocType { diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 29d0bddef..7fa751e24 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1963,6 +1963,11 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } } break; + case AST_BIND: { + // The bind construct. Currently unimplemented: just ignore it. + break; + } + case AST_FCALL: { if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 55e8b48b9..54fb65240 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -260,6 +260,7 @@ static bool isUserType(std::string &s) "const" { if (formal_mode) return TOK_CONST; SV_KEYWORD(TOK_CONST); } "checker" { if (formal_mode) return TOK_CHECKER; SV_KEYWORD(TOK_CHECKER); } "endchecker" { if (formal_mode) return TOK_ENDCHECKER; SV_KEYWORD(TOK_ENDCHECKER); } +"bind" { if (formal_mode) return TOK_BIND; SV_KEYWORD(TOK_BIND); } "final" { SV_KEYWORD(TOK_FINAL); } "logic" { SV_KEYWORD(TOK_LOGIC); } "var" { SV_KEYWORD(TOK_VAR); } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 9558b0e87..de463b47d 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -299,6 +299,7 @@ static void checkLabelsMatch(const char *element, const std::string *before, con %token TOK_BIT_OR_ASSIGN TOK_BIT_AND_ASSIGN TOK_BIT_XOR_ASSIGN TOK_ADD_ASSIGN %token TOK_SUB_ASSIGN TOK_DIV_ASSIGN TOK_MOD_ASSIGN TOK_MUL_ASSIGN %token TOK_SHL_ASSIGN TOK_SHR_ASSIGN TOK_SSHL_ASSIGN TOK_SSHR_ASSIGN +%token TOK_BIND %type range range_or_multirange non_opt_range non_opt_multirange %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type @@ -364,6 +365,7 @@ design: typedef_decl design | package design | interface design | + bind_directive design | %empty; attr: @@ -636,7 +638,67 @@ interface_body: interface_body_stmt: param_decl | localparam_decl | typedef_decl | defparam_decl | wire_decl | always_stmt | assign_stmt | - modport_stmt; + modport_stmt | bind_directive; + +bind_directive: + TOK_BIND { + AstNode *bnode = new AstNode(AST_BIND); + ast_stack.back()->children.push_back(bnode); + ast_stack.push_back(bnode); + } + bind_target { + // bind_target should have added at least one child + log_assert(ast_stack.back()->children.size() >= 1); + } + TOK_ID { + // The single_cell parser in cell_list_no_array uses astbuf1 as + // a sort of template for constructing cells. + astbuf1 = new AstNode(AST_CELL); + astbuf1->children.push_back(new AstNode(AST_CELLTYPE)); + astbuf1->children[0]->str = *$5; + delete $5; + } + cell_parameter_list_opt cell_list_no_array ';' { + // cell_list should have added at least one more child + log_assert(ast_stack.back()->children.size() >= 2); + delete astbuf1; + ast_stack.pop_back(); + }; + +// bind_target matches the target of the bind (everything before +// bind_instantiation in the IEEE 1800 spec). +// +// We can't use the BNF from the spec directly because it's ambiguous: +// something like "bind foo bar_i (.*)" can either be interpreted with "foo" as +// a module or interface identifier (matching bind_target_scope in the spec) or +// by considering foo as a degenerate hierarchical identifier with no '.' +// characters, followed by no bit select (which matches bind_target_instance in +// the spec). +// +// Instead, we resolve everything as an instance name and then deal with the +// ambiguity when converting to RTLIL / in the hierarchy pass. +bind_target: + bind_target_instance opt_bind_target_instance_list; + +// An optional list of target instances for a bind statement, introduced by a +// colon. +opt_bind_target_instance_list: + ':' bind_target_instance_list | + %empty; + +bind_target_instance_list: + bind_target_instance | + bind_target_instance_list ',' bind_target_instance; + +// A single target instance for a bind statement. The top of ast_stack will be +// the bind node where we should add it. +bind_target_instance: + hierarchical_id { + auto *node = new AstNode(AST_IDENTIFIER); + node->str = *$1; + delete $1; + ast_stack.back()->children.push_back(node); + }; mintypmax_expr: expr { delete $1; } | @@ -813,7 +875,7 @@ module_body: module_body_stmt: task_func_decl | specify_block | param_decl | localparam_decl | typedef_decl | defparam_decl | specparam_declaration | wire_decl | assign_stmt | cell_stmt | - enum_decl | struct_decl | + enum_decl | struct_decl | bind_directive | always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property | checker_decl | ignored_specify_block; checker_decl: @@ -1975,6 +2037,9 @@ cell_list: cell_list ',' single_cell; single_cell: + single_cell_no_array | single_cell_arraylist; + +single_cell_no_array: TOK_ID { astbuf2 = astbuf1->clone(); if (astbuf2->type != AST_PRIMITIVE) @@ -1983,7 +2048,9 @@ single_cell: ast_stack.back()->children.push_back(astbuf2); } '(' cell_port_list ')' { SET_AST_NODE_LOC(astbuf2, @1, @$); - } | + } + +single_cell_arraylist: TOK_ID non_opt_range { astbuf2 = astbuf1->clone(); if (astbuf2->type != AST_PRIMITIVE) @@ -1994,6 +2061,10 @@ single_cell: SET_AST_NODE_LOC(astbuf2, @1, @$); }; +cell_list_no_array: + single_cell_no_array | + cell_list_no_array ',' single_cell_no_array; + prim_list: single_prim | prim_list ',' single_prim; -- cgit v1.2.3 From 987fca5297d4e3290df64b7a54a3af9b6ddf11d9 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 21 Jul 2021 09:46:53 +0200 Subject: Update to latest verific --- frontends/verific/verific.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 997a8e826..357b88043 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -56,7 +56,7 @@ USING_YOSYS_NAMESPACE # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210602 +#if YOSYSHQ_VERIFIC_API_VERSION < 20210603 # error "Please update your version of YosysHQ flavored Verific." #endif @@ -1961,7 +1961,7 @@ void verific_import(Design *design, const std::map &par for (const auto &i : parameters) verific_params.Insert(i.first.c_str(), i.second.c_str()); - InitialAssertions::Rewrite("work"); + InitialAssertions::Rewrite("work", &verific_params); if (top.empty()) { netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); @@ -2847,7 +2847,7 @@ struct VerificPass : public Pass { std::set top_mod_names; - InitialAssertions::Rewrite(work); + InitialAssertions::Rewrite(work, ¶meters); if (mode_all) { -- cgit v1.2.3 From 8bdc019730c665f678fc1f3bdd8ed96cf2f513d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 21 May 2021 02:27:06 +0200 Subject: verilog: Emit $meminit_v2 cell. Fixes #2447. --- frontends/ast/ast.cc | 4 +- frontends/ast/ast.h | 2 +- frontends/ast/genrtlil.cc | 9 ++-- frontends/ast/simplify.cc | 119 ++++++++++++++++++++++++++++------------------ 4 files changed, 83 insertions(+), 51 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index e42cf0348..fe503c547 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -199,7 +199,7 @@ bool AstNode::get_bool_attribute(RTLIL::IdString id) // create new node (AstNode constructor) // (the optional child arguments make it easier to create AST trees) -AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3) +AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *child3, AstNode *child4) { static unsigned int hashidx_count = 123456789; hashidx_count = mkhash_xorshift(hashidx_count); @@ -236,6 +236,8 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch children.push_back(child2); if (child3) children.push_back(child3); + if (child4) + children.push_back(child4); } // create a (deep recursive) copy of a node diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 57ce5605f..ba5a11b96 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -221,7 +221,7 @@ namespace AST AstSrcLocType location; // creating and deleting nodes - AstNode(AstNodeType type = AST_NONE, AstNode *child1 = NULL, AstNode *child2 = NULL, AstNode *child3 = NULL); + AstNode(AstNodeType type = AST_NONE, AstNode *child1 = nullptr, AstNode *child2 = nullptr, AstNode *child3 = nullptr, AstNode *child4 = nullptr); AstNode *clone() const; void cloneInto(AstNode *other) const; void delete_children(); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 7fa751e24..90d5f1bba 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1720,21 +1720,24 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) std::stringstream sstr; sstr << "$meminit$" << str << "$" << filename << ":" << location.first_line << "$" << (autoidx++); - RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($meminit)); + SigSpec en_sig = children[2]->genRTLIL(); + + RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($meminit_v2)); set_src_attr(cell, this); int mem_width, mem_size, addr_bits; id2ast->meminfo(mem_width, mem_size, addr_bits); - if (children[2]->type != AST_CONSTANT) + if (children[3]->type != AST_CONSTANT) log_file_error(filename, location.first_line, "Memory init with non-constant word count!\n"); - int num_words = int(children[2]->asInt(false)); + int num_words = int(children[3]->asInt(false)); cell->parameters[ID::WORDS] = RTLIL::Const(num_words); SigSpec addr_sig = children[0]->genRTLIL(); cell->setPort(ID::ADDR, addr_sig); cell->setPort(ID::DATA, children[1]->genWidthRTLIL(current_module->memories[str]->width * num_words, true)); + cell->setPort(ID::EN, en_sig); cell->parameters[ID::MEMID] = RTLIL::Const(str); cell->parameters[ID::ABITS] = RTLIL::Const(GetSize(addr_sig)); diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 5845c0501..f713cf8e1 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -2648,25 +2648,20 @@ skip_dynamic_range_lvalue_expansion:; node_data->str = id_data; } - AstNode *node_en = nullptr; - if (current_always->type == AST_INITIAL) { - node_en = AstNode::mkconst_int(1, false); - } else { - AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); - wire_en->str = id_en; - wire_en->was_checked = true; - current_ast_mod->children.push_back(wire_en); - current_scope[wire_en->str] = wire_en; - while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - - AstNode *assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - defNode->children.push_back(assign_en); + AstNode *wire_en = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true))); + wire_en->str = id_en; + wire_en->was_checked = true; + current_ast_mod->children.push_back(wire_en); + current_scope[wire_en->str] = wire_en; + while (wire_en->simplify(true, false, false, 1, -1, false, false)) { } - node_en = new AstNode(AST_IDENTIFIER); - node_en->str = id_en; - } + AstNode *assign_en_first = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, mem_width)); + assign_en_first->children[0]->str = id_en; + assign_en_first->children[0]->was_checked = true; + defNode->children.push_back(assign_en_first); + + AstNode *node_en = new AstNode(AST_IDENTIFIER); + node_en->str = id_en; if (!defNode->children.empty()) current_top_block->children.insert(current_top_block->children.begin(), defNode); @@ -2690,13 +2685,11 @@ skip_dynamic_range_lvalue_expansion:; assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; - if (current_always->type != AST_INITIAL) { - for (int i = 0; i < mem_width; i++) - set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } + for (int i = 0; i < mem_width; i++) + set_bits_en[i] = offset <= i && i < offset+width ? RTLIL::State::S1 : RTLIL::State::S0; + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } else { @@ -2719,14 +2712,12 @@ skip_dynamic_range_lvalue_expansion:; assign_data->children[0]->str = id_data; assign_data->children[0]->was_checked = true; - if (current_always->type != AST_INITIAL) { - for (int i = 0; i < mem_width; i++) - set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } + for (int i = 0; i < mem_width; i++) + set_bits_en[i] = i < width ? RTLIL::State::S1 : RTLIL::State::S0; + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), + new AstNode(AST_SHIFT_LEFT, mkconst_bits(set_bits_en, false), offset_ast->clone())); + assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; delete left_at_zero_ast; delete right_at_zero_ast; @@ -2741,18 +2732,20 @@ skip_dynamic_range_lvalue_expansion:; assign_data->children[0]->was_checked = true; } - if (current_always->type != AST_INITIAL) { - assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); - assign_en->children[0]->str = id_en; - assign_en->children[0]->was_checked = true; - } + assign_en = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), mkconst_bits(set_bits_en, false)); + assign_en->children[0]->str = id_en; + assign_en->children[0]->was_checked = true; } if (assign_data) newNode->children.push_back(assign_data); if (assign_en) newNode->children.push_back(assign_en); - AstNode *wrnode = new AstNode(current_always->type == AST_INITIAL ? AST_MEMINIT : AST_MEMWR, node_addr, node_data, node_en); + AstNode *wrnode; + if (current_always->type == AST_INITIAL) + wrnode = new AstNode(AST_MEMINIT, node_addr, node_data, node_en, mkconst_int(1, false)); + else + wrnode = new AstNode(AST_MEMWR, node_addr, node_data, node_en); wrnode->str = children[0]->str; wrnode->id2ast = children[0]->id2ast; wrnode->location = location; @@ -3921,8 +3914,12 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m AstNode *meminit = nullptr; int next_meminit_cursor=0; vector meminit_bits; + vector en_bits; int meminit_size=0; + for (int i = 0; i < mem_width; i++) + en_bits.push_back(State::S1); + std::ifstream f; f.open(mem_filename.c_str()); if (f.fail()) { @@ -3996,12 +3993,13 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m { if (meminit != nullptr) { meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[2] = AstNode::mkconst_int(meminit_size, false); + meminit->children[3] = AstNode::mkconst_int(meminit_size, false); } meminit = new AstNode(AST_MEMINIT); meminit->children.push_back(AstNode::mkconst_int(cursor, false)); meminit->children.push_back(nullptr); + meminit->children.push_back(AstNode::mkconst_bits(en_bits, false)); meminit->children.push_back(nullptr); meminit->str = memory->str; meminit->id2ast = memory; @@ -4036,7 +4034,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m if (meminit != nullptr) { meminit->children[1] = AstNode::mkconst_bits(meminit_bits, false); - meminit->children[2] = AstNode::mkconst_int(meminit_size, false); + meminit->children[3] = AstNode::mkconst_int(meminit_size, false); } return block; @@ -4381,10 +4379,12 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, log_assert(children[0]->type == AST_CONSTANT); log_assert(children[1]->type == AST_CONSTANT); log_assert(children[2]->type == AST_CONSTANT); + log_assert(children[3]->type == AST_CONSTANT); int cursor = children[0]->asInt(false); Const data = children[1]->bitsAsConst(); - int length = children[2]->asInt(false); + Const en = children[2]->bitsAsConst(); + int length = children[3]->asInt(false); if (length != 0) { @@ -4395,10 +4395,37 @@ bool AstNode::mem2reg_as_needed_pass2(pool &mem2reg_set, AstNode *mod, int wordsz = GetSize(data) / length; for (int i = 0; i < length; i++) { - block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); - block->children.back()->children[0]->str = str; - block->children.back()->children[0]->id2ast = id2ast; - block->children.back()->children[0]->was_checked = true; + int pos = 0; + while (pos < wordsz) { + if (en[pos] != State::S1) { + pos++; + } else { + int epos = pos + 1; + while (epos < wordsz && en[epos] == State::S1) + epos++; + int clen = epos - pos; + AstNode *range = new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false)); + if (pos != 0 || epos != wordsz) { + int left; + int right; + AstNode *mrange = id2ast->children[0]; + if (mrange->range_left < mrange->range_right) { + right = mrange->range_right - pos; + left = mrange->range_right - epos + 1; + } else { + right = mrange->range_right + pos; + left = mrange->range_right + epos - 1; + } + range = new AstNode(AST_MULTIRANGE, range, new AstNode(AST_RANGE, AstNode::mkconst_int(left, true), AstNode::mkconst_int(right, true))); + } + AstNode *target = new AstNode(AST_IDENTIFIER, range); + target->str = str; + target->id2ast = id2ast; + target->was_checked = true; + block->children.push_back(new AstNode(AST_ASSIGN_EQ, target, mkconst_bits(data.extract(i*wordsz + pos, clen).bits, false))); + pos = epos; + } + } } } -- cgit v1.2.3 From 3156226233133f5da9dba15c63ca560b4794b831 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 15 Jul 2021 10:36:50 -0400 Subject: verilog: save and restore overwritten macro arguments --- frontends/verilog/preproc.cc | 34 ++++++++++++++++++++++++++++++---- frontends/verilog/preproc.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 4b9ebe0aa..17f567587 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -36,6 +36,7 @@ #include "verilog_frontend.h" #include "kernel/log.h" #include +#include #include #include #include @@ -334,6 +335,11 @@ define_map_t::add(const std::string &name, const std::string &txt, const arg_map defines[name] = std::unique_ptr(new define_body_t(txt, args)); } +void define_map_t::add(const std::string &name, const define_body_t &body) +{ + defines[name] = std::unique_ptr(new define_body_t(body)); +} + void define_map_t::merge(const define_map_t &map) { for (const auto &pr : map.defines) { @@ -440,7 +446,17 @@ static bool read_argument(std::string &dest) } } -static bool try_expand_macro(define_map_t &defines, std::string &tok) +using macro_arg_stack_t = std::stack>; + +static void restore_macro_arg(define_map_t &defines, macro_arg_stack_t ¯o_arg_stack) +{ + log_assert(!macro_arg_stack.empty()); + auto &overwritten_arg = macro_arg_stack.top(); + defines.add(overwritten_arg.first, overwritten_arg.second); + macro_arg_stack.pop(); +} + +static bool try_expand_macro(define_map_t &defines, macro_arg_stack_t ¯o_arg_stack, std::string &tok) { if (tok == "`\"") { std::string literal("\""); @@ -450,7 +466,7 @@ static bool try_expand_macro(define_map_t &defines, std::string &tok) if (ntok == "`\"") { insert_input(literal+"\""); return true; - } else if (!try_expand_macro(defines, ntok)) { + } else if (!try_expand_macro(defines, macro_arg_stack, ntok)) { literal += ntok; } } @@ -495,6 +511,10 @@ static bool try_expand_macro(define_map_t &defines, std::string &tok) args.push_back(arg); } for (const auto &pr : body->args.get_vals(name, args)) { + if (const define_body_t *existing = defines.find(pr.first)) { + macro_arg_stack.push({pr.first, *existing}); + insert_input("`__restore_macro_arg "); + } defines.add(pr.first, pr.second); } } else { @@ -725,6 +745,7 @@ frontend_verilog_preproc(std::istream &f, defines.merge(pre_defines); defines.merge(global_defines_cache); + macro_arg_stack_t macro_arg_stack; std::vector filename_stack; // We are inside pass_level levels of satisfied ifdefs, and then within // fail_level levels of unsatisfied ifdefs. The unsatisfied ones are @@ -828,7 +849,7 @@ frontend_verilog_preproc(std::istream &f, if (tok == "`include") { skip_spaces(); std::string fn = next_token(true); - while (try_expand_macro(defines, fn)) { + while (try_expand_macro(defines, macro_arg_stack, fn)) { fn = next_token(); } while (1) { @@ -935,7 +956,12 @@ frontend_verilog_preproc(std::istream &f, continue; } - if (try_expand_macro(defines, tok)) + if (tok == "`__restore_macro_arg") { + restore_macro_arg(defines, macro_arg_stack); + continue; + } + + if (try_expand_macro(defines, macro_arg_stack, tok)) continue; output_code.push_back(tok); diff --git a/frontends/verilog/preproc.h b/frontends/verilog/preproc.h index e1048156c..330855a92 100644 --- a/frontends/verilog/preproc.h +++ b/frontends/verilog/preproc.h @@ -42,6 +42,7 @@ struct define_map_t // Add a definition, overwriting any existing definition for name. void add(const std::string &name, const std::string &txt, const arg_map_t *args = nullptr); + void add(const std::string &name, const define_body_t &body); // Merge in another map of definitions (which take precedence // over anything currently defined). -- cgit v1.2.3 From 4fec3a85cd7d0fcd35f958bfc89090df25f7de3c Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 29 Jul 2021 12:35:22 -0400 Subject: genrtlil: add width detection for AST_PREFIX nodes --- frontends/ast/genrtlil.cc | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 90d5f1bba..45aab9d8e 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -993,6 +993,14 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun break; } + case AST_PREFIX: + // Prefix nodes always resolve to identifiers in generate loops, so we + // can simply perform the resolution to determine the sign and width. + simplify(true, false, false, 1, -1, false, false); + log_assert(type == AST_IDENTIFIER); + detectSignWidthWorker(width_hint, sign_hint, found_real); + break; + case AST_FCALL: if (str == "\\$anyconst" || str == "\\$anyseq" || str == "\\$allconst" || str == "\\$allseq") { if (GetSize(children) == 1) { -- cgit v1.2.3 From be04d8834ea5380a8926255cd6a9482806006b91 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 2 Aug 2021 10:29:16 +0200 Subject: Require latest verific --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 357b88043..5a10568c7 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -56,7 +56,7 @@ USING_YOSYS_NAMESPACE # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210603 +#if YOSYSHQ_VERIFIC_API_VERSION < 20210701 # error "Please update your version of YosysHQ flavored Verific." #endif -- cgit v1.2.3 From 52cbf1bea52b05c3fa57712ce201369c92400008 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Fri, 6 Aug 2021 20:49:41 +0200 Subject: verilog: Support tri/triand/trior wire types. These are, by the standard, just aliases for wire/wand/wor. Fixes #2918. --- frontends/verilog/verilog_lexer.l | 3 +++ 1 file changed, 3 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 54fb65240..0306f5494 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -277,8 +277,11 @@ static bool isUserType(std::string &s) "output" { return TOK_OUTPUT; } "inout" { return TOK_INOUT; } "wire" { return TOK_WIRE; } +"tri" { return TOK_WIRE; } "wor" { return TOK_WOR; } +"trior" { return TOK_WOR; } "wand" { return TOK_WAND; } +"triand" { return TOK_WAND; } "reg" { return TOK_REG; } "integer" { return TOK_INTEGER; } "signed" { return TOK_SIGNED; } -- cgit v1.2.3 From 681a1c07e52dc82449501f4939e6312f593449bd Mon Sep 17 00:00:00 2001 From: Michael Singer Date: Thu, 5 Aug 2021 21:02:35 +0200 Subject: Allow optional comma after last entry in enum --- frontends/verilog/verilog_parser.y | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index de463b47d..a5227cb09 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1624,17 +1624,18 @@ enum_type: TOK_ENUM { // create the template for the names astbuf1 = new AstNode(AST_ENUM_ITEM); astbuf1->children.push_back(AstNode::mkconst_int(0, true)); - } enum_base_type '{' enum_name_list '}' { // create template for the enum vars - auto tnode = astbuf1->clone(); - delete astbuf1; - astbuf1 = tnode; - tnode->type = AST_WIRE; - tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); - // drop constant but keep any range - delete tnode->children[0]; - tnode->children.erase(tnode->children.begin()); - $$ = astbuf1; } - ; + } enum_base_type '{' enum_name_list optional_comma '}' { + // create template for the enum vars + auto tnode = astbuf1->clone(); + delete astbuf1; + astbuf1 = tnode; + tnode->type = AST_WIRE; + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); + // drop constant but keep any range + delete tnode->children[0]; + tnode->children.erase(tnode->children.begin()); + $$ = astbuf1; + }; enum_base_type: type_atom type_signing | type_vec type_signing range { if ($3) astbuf1->children.push_back($3); } -- cgit v1.2.3 From 979053855c85b72c6344bf6350fb9a8360f3d092 Mon Sep 17 00:00:00 2001 From: Brett Witherspoon Date: Tue, 22 Jun 2021 09:51:41 -0500 Subject: sv: improve support for wire and var with user-defined types - User-defined types must be data types. Using a net type (e.g. wire) is a syntax error. - User-defined types without a net type are always variables (i.e. logic). - Nets and variables can now be explicitly declared using user-defined types: typedef logic [1:0] W; wire W w; typedef logic [1:0] V; var V v; Fixes #2846 --- frontends/verilog/verilog_parser.y | 55 ++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 11 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a5227cb09..b0c16c0f4 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -127,6 +127,15 @@ struct specify_rise_fall { specify_triple fall; }; +static void addWiretypeNode(std::string *name, AstNode *node) +{ + log_assert(node); + node->is_custom_type = true; + node->children.push_back(new AstNode(AST_WIRETYPE)); + node->children.back()->str = *name; + delete name; +} + static void addTypedefNode(std::string *name, AstNode *node) { log_assert(node); @@ -305,10 +314,10 @@ static void checkLabelsMatch(const char *element, const std::string *before, con %type wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list non_io_wire_type io_wire_type %type opt_label opt_sva_label tok_prim_wrapper hierarchical_id hierarchical_type_id integral_number %type type_name -%type opt_enum_init enum_type struct_type non_wire_data_type func_return_type +%type opt_enum_init enum_type struct_type enum_struct_type func_return_type typedef_base_type %type opt_property always_comb_or_latch always_or_always_ff %type opt_signedness_default_signed opt_signedness_default_unsigned -%type integer_atom_type +%type integer_atom_type integer_vector_type %type attr case_attr %type struct_union %type asgn_binop @@ -763,12 +772,6 @@ opt_wire_type_token: wire_type_token | %empty; wire_type_token: - hierarchical_type_id { - astbuf3->is_custom_type = true; - astbuf3->children.push_back(new AstNode(AST_WIRETYPE)); - astbuf3->children.back()->str = *$1; - delete $1; - } | TOK_WOR { astbuf3->is_wor = true; } | @@ -812,6 +815,9 @@ logic_type: astbuf3->range_left = $1 - 1; astbuf3->range_right = 0; astbuf3->is_signed = true; + } | + hierarchical_type_id { + addWiretypeNode($1, astbuf3); }; integer_atom_type: @@ -821,6 +827,10 @@ integer_atom_type: TOK_LONGINT { $$ = 64; } | TOK_BYTE { $$ = 8; } ; +integer_vector_type: + TOK_LOGIC { $$ = TOK_LOGIC; } | + TOK_REG { $$ = TOK_REG; } ; + non_opt_range: '[' expr ':' expr ']' { $$ = new AstNode(AST_RANGE); @@ -1985,7 +1995,7 @@ type_name: TOK_ID // first time seen ; typedef_decl: - TOK_TYPEDEF non_io_wire_type range type_name range_or_multirange ';' { + TOK_TYPEDEF typedef_base_type range type_name range_or_multirange ';' { astbuf1 = $2; astbuf2 = checkRange(astbuf1, $3); if (astbuf2) @@ -1998,10 +2008,33 @@ typedef_decl: rewriteAsMemoryNode(astbuf1, $5); } addTypedefNode($4, astbuf1); } - | TOK_TYPEDEF non_wire_data_type type_name ';' { addTypedefNode($3, $2); } + | TOK_TYPEDEF enum_struct_type type_name ';' { addTypedefNode($3, $2); } ; -non_wire_data_type: +typedef_base_type: + hierarchical_type_id { + $$ = new AstNode(AST_WIRE); + $$->is_logic = true; + addWiretypeNode($1, $$); + } | + integer_vector_type opt_signedness_default_unsigned { + $$ = new AstNode(AST_WIRE); + if ($1 == TOK_REG) { + $$->is_reg = true; + } else { + $$->is_logic = true; + } + $$->is_signed = $2; + } | + integer_atom_type opt_signedness_default_signed { + $$ = new AstNode(AST_WIRE); + $$->is_logic = true; + $$->is_signed = $2; + $$->range_left = $1 - 1; + $$->range_right = 0; + }; + +enum_struct_type: enum_type | struct_type ; -- cgit v1.2.3 From ee2b5b7ed186414897a8a570a9e503c438803ad8 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Mon, 20 Apr 2020 16:06:53 +0100 Subject: Generate an RTLIL representation of bind constructs This code now takes the AST nodes of type AST_BIND and generates a representation in the RTLIL for them. This is a little tricky, because a binding of the form: bind baz foo_t foo_i (.arg (1 + bar)); means "make an instance of foo_t called foo_i, instantiate it inside baz and connect the port arg to the result of the expression 1+bar". Of course, 1+bar needs a cell for the addition. Where should that cell live? With this patch, the Binding structure that represents the construct is itself an AST::AstModule module. This lets us put the adder cell inside it. We'll pull the contents out and plonk them into 'baz' when we actually do the binding operation as part of the hierarchy pass. Of course, we don't want RTLIL::Binding to contain an AST::AstModule (since kernel code shouldn't depend on a frontend), so we define RTLIL::Binding as an abstract base class and put the AST-specific code into an AST::Binding subclass. This is analogous to the AST::AstModule class. --- frontends/ast/Makefile.inc | 1 + frontends/ast/ast.cc | 5 +++ frontends/ast/ast.h | 3 ++ frontends/ast/ast_binding.cc | 49 +++++++++++++++++++++++++++ frontends/ast/ast_binding.h | 58 ++++++++++++++++++++++++++++++++ frontends/ast/genrtlil.cc | 79 ++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 193 insertions(+), 2 deletions(-) create mode 100644 frontends/ast/ast_binding.cc create mode 100644 frontends/ast/ast_binding.h (limited to 'frontends') diff --git a/frontends/ast/Makefile.inc b/frontends/ast/Makefile.inc index 91d917c91..9e6eee1e8 100644 --- a/frontends/ast/Makefile.inc +++ b/frontends/ast/Makefile.inc @@ -3,4 +3,5 @@ OBJS += frontends/ast/ast.o OBJS += frontends/ast/simplify.o OBJS += frontends/ast/genrtlil.o OBJS += frontends/ast/dpicall.o +OBJS += frontends/ast/ast_binding.o diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index fe503c547..4fbc238b0 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1310,6 +1310,11 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump design->verilog_packages.push_back(child->clone()); current_scope.clear(); } + else if (child->type == AST_BIND) { + // top-level bind construct + for (RTLIL::Binding *binding : child->genBindings()) + design->add(binding); + } else { // must be global definition if (child->type == AST_PARAMETER) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index ba5a11b96..63104bca4 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -284,6 +284,9 @@ namespace AST void dumpAst(FILE *f, std::string indent) const; void dumpVlog(FILE *f, std::string indent) const; + // Generate RTLIL for a bind construct + std::vector genBindings() const; + // used by genRTLIL() for detecting expression width and sign void detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real = NULL); void detectSignWidth(int &width_hint, bool &sign_hint, bool *found_real = NULL); diff --git a/frontends/ast/ast_binding.cc b/frontends/ast/ast_binding.cc new file mode 100644 index 000000000..c20d1df4d --- /dev/null +++ b/frontends/ast/ast_binding.cc @@ -0,0 +1,49 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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. + * + */ + +#include "ast_binding.h" +#include "ast.h" + +YOSYS_NAMESPACE_BEGIN + +using namespace AST_INTERNAL; + +AST::Binding::Binding(RTLIL::IdString target_type, + RTLIL::IdString target_name, + const AstNode &cell) + : RTLIL::Binding(target_type, target_name), + ast_node(cell.clone()) +{ + log_assert(cell.type == AST_CELL); +} + +std::string +AST::Binding::describe() const +{ + std::ostringstream oss; + oss << "directive to bind " << ast_node->str + << " to " << target_name.str(); + if (!target_type.empty()) + oss << " (target type: " + << target_type.str() + << ")"; + return oss.str(); +} + +PRIVATE_NAMESPACE_END diff --git a/frontends/ast/ast_binding.h b/frontends/ast/ast_binding.h new file mode 100644 index 000000000..641497d52 --- /dev/null +++ b/frontends/ast/ast_binding.h @@ -0,0 +1,58 @@ +/* -*- c++ -*- + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * + * 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. + * + * --- + * + * This header declares the AST::Binding class + * + * This is used to support the bind directive and is to RTLIL::Binding as + * AST::AstModule is to RTLIL::Module, holding a syntax-level representation of + * cells until we get to a stage where they make sense. In the case of a bind + * directive, this is when we elaborate the design in the hierarchy pass. + * + */ + +#ifndef AST_BINDING_H +#define AST_BINDING_H + +#include "kernel/rtlil.h" +#include "kernel/binding.h" + +#include + +YOSYS_NAMESPACE_BEGIN + +namespace AST +{ + class Binding : public RTLIL::Binding + { + public: + Binding(RTLIL::IdString target_type, + RTLIL::IdString target_name, + const AstNode &cell); + + std::string describe() const override; + + private: + // The syntax-level representation of the cell to be bound. + std::unique_ptr ast_node; + }; +} + +YOSYS_NAMESPACE_END + +#endif diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 45aab9d8e..c82664b98 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -28,8 +28,10 @@ #include "kernel/log.h" #include "kernel/utils.h" +#include "kernel/binding.h" #include "libs/sha1/sha1.h" #include "ast.h" +#include "ast_binding.h" #include #include @@ -733,6 +735,69 @@ struct AST_INTERNAL::ProcessGenerator } }; +// Generate RTLIL for a bind construct +// +// The AST node will have one or more AST_IDENTIFIER children, which were added +// by bind_target_instance in the parser. After these, it will have one or more +// cells, as parsed by single_cell. These have type AST_CELL. +// +// If there is more than one AST_IDENTIFIER, the first one should be considered +// a module identifier. If there is only one AST_IDENTIFIER, we can't tell at +// this point whether it's a module/interface name or the name of an instance +// because the correct interpretation depends on what's visible at elaboration +// time. For now, we just treat it as a target instance with unknown type, and +// we'll deal with the corner case in the hierarchy pass. +// +// To simplify downstream code, RTLIL::Binding only has a single target and +// single bound instance. If we see the syntax that allows more than one of +// either, we split it into multiple Binding objects. +std::vector AstNode::genBindings() const +{ + // Partition children into identifiers and cells + int num_ids = 0; + for (int i = 0; i < GetSize(children); ++i) { + if (children[i]->type != AST_IDENTIFIER) { + log_assert(i > 0); + num_ids = i; + break; + } + } + + // We should have found at least one child that's not an identifier + log_assert(num_ids > 0); + + // Make sense of the identifiers, extracting a possible type name and a + // list of hierarchical IDs. We represent an unknown type with an empty + // string. + RTLIL::IdString tgt_type; + int first_tgt_inst = 0; + if (num_ids > 1) { + tgt_type = children[0]->str; + first_tgt_inst = 1; + } + + std::vector ret; + + // At this point, we know that children with index >= first_tgt_inst and + // index < num_ids are (hierarchical?) names of target instances. Make a + // binding object for each of them, and fill in the generated instance + // cells each time. + for (int i = first_tgt_inst; i < num_ids; ++i) { + const AstNode &tgt_child = *children[i]; + + for (int j = num_ids; j < GetSize(children); ++j) { + const AstNode &cell_child = *children[j]; + + log_assert(cell_child.type == AST_CELL); + + ret.push_back(new AST::Binding(tgt_type, tgt_child.str, + cell_child)); + } + } + + return ret; +} + // detect sign and width of an expression void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *found_real) { @@ -1311,7 +1376,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) RTLIL::Wire *wire = current_module->addWire(str); set_src_attr(wire, this); wire->name = str; - if (flag_autowire) + + // If we are currently processing a bind directive which wires up + // signals or parameters explicitly, rather than with .*, then + // current_module will start out empty and we don't want to warn the + // user about it: we'll spot broken wiring later, when we run the + // hierarchy pass. + if (dynamic_cast(current_module)) { + /* nothing to do here */ + } else if (flag_autowire) log_file_warning(filename, location.first_line, "Identifier `%s' is implicitly declared.\n", str.c_str()); else log_file_error(filename, location.first_line, "Identifier `%s' is implicitly declared and `default_nettype is set to none.\n", str.c_str()); @@ -1975,7 +2048,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } break; case AST_BIND: { - // The bind construct. Currently unimplemented: just ignore it. + // Read a bind construct. This should have one or more cells as children. + for (RTLIL::Binding *binding : genBindings()) + current_module->add(binding); break; } -- cgit v1.2.3 From b59c42734837f6cb987e97d60e56e096c8d4d40a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 20 Aug 2021 10:19:04 +0200 Subject: Make Verific extensions optional --- frontends/verific/verific.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 5a10568c7..1b8bc1b51 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -50,7 +50,9 @@ USING_YOSYS_NAMESPACE #include "VhdlUnits.h" #include "VeriLibrary.h" +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS #include "InitialAssertions.h" +#endif #ifndef YOSYSHQ_VERIFIC_API_VERSION # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." @@ -1961,7 +1963,9 @@ void verific_import(Design *design, const std::map &par for (const auto &i : parameters) verific_params.Insert(i.first.c_str(), i.second.c_str()); +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS InitialAssertions::Rewrite("work", &verific_params); +#endif if (top.empty()) { netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, &verific_params); @@ -2847,8 +2851,9 @@ struct VerificPass : public Pass { std::set top_mod_names; +#ifdef YOSYSHQ_VERIFIC_EXTENSIONS InitialAssertions::Rewrite(work, ¶meters); - +#endif if (mode_all) { log("Running hier_tree::ElaborateAll().\n"); -- cgit v1.2.3 From f0a52e3dd275ee57a1b3ffd0a734b591bf21f668 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 30 Aug 2021 11:35:36 -0600 Subject: sv: support declaration in procedural for initialization In line with other tools, this adds an extra wrapping block around such for loops to appropriately scope the variable. --- frontends/verilog/verilog_parser.y | 49 +++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index b0c16c0f4..23404f844 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2607,6 +2607,53 @@ asgn_binop: TOK_SSHL_ASSIGN { $$ = AST_SHIFT_SLEFT; } | TOK_SSHR_ASSIGN { $$ = AST_SHIFT_SRIGHT; } ; +for_initialization: + TOK_ID '=' expr { + AstNode *ident = new AstNode(AST_IDENTIFIER); + ident->str = *$1; + AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @3); + } | + non_io_wire_type range TOK_ID { + frontend_verilog_yyerror("For loop variable declaration is missing initialization!"); + } | + non_io_wire_type range TOK_ID '=' expr { + if (!sv_mode) + frontend_verilog_yyerror("For loop inline variable declaration is only supported in SystemVerilog mode!"); + + // loop variable declaration + AstNode *wire = $1; + AstNode *range = checkRange(wire, $2); + if (range != nullptr) + wire->children.push_back(range); + SET_AST_NODE_LOC(wire, @1, @3); + SET_AST_NODE_LOC(range, @2, @2); + + AstNode *ident = new AstNode(AST_IDENTIFIER); + ident->str = *$3; + wire->str = *$3; + delete $3; + + AstNode *loop = ast_stack.back(); + AstNode *parent = ast_stack.at(ast_stack.size() - 2); + log_assert(parent->children.back() == loop); + + // loop variable initialization + AstNode *asgn = new AstNode(AST_ASSIGN_EQ, ident, $5); + loop->children.push_back(asgn); + SET_AST_NODE_LOC(asgn, @3, @5); + SET_AST_NODE_LOC(ident, @3, @3); + + // inject a wrapping block to declare the loop variable and + // contain the current loop + AstNode *wrapper = new AstNode(AST_BLOCK); + wrapper->str = "$fordecl_block$" + std::to_string(autoidx++); + wrapper->children.push_back(wire); + wrapper->children.push_back(loop); + parent->children.back() = wrapper; // replaces `loop` + }; + // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: defattr | assert | wire_decl | param_decl | localparam_decl | typedef_decl | @@ -2667,7 +2714,7 @@ behavioral_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); append_attr(node, $1); - } simple_behavioral_stmt ';' expr { + } for_initialization ';' expr { ast_stack.back()->children.push_back($7); } ';' simple_behavioral_stmt ')' { AstNode *block = new AstNode(AST_BLOCK); -- cgit v1.2.3 From b2e9717419e9a852f4e64f12891b8e9742900917 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 31 Aug 2021 11:45:02 -0600 Subject: sv: support declaration in generate for initialization This is accomplished by generating a unique name for the genvar, renaming references to the genvar only in the loop's initialization, guard, and incrementation, and finally adding a localparam inside the loop body with the original name so that the genvar can be shadowed as expected. --- frontends/verilog/verilog_parser.y | 96 +++++++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 23404f844..8d0ba4cf6 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -254,6 +254,65 @@ static void checkLabelsMatch(const char *element, const std::string *before, con element, before->c_str() + 1, after->c_str() + 1); } +// This transforms a loop like +// for (genvar i = 0; i < 10; i++) begin : blk +// to +// genvar _i; +// for (_i = 0; _i < 10; _i++) begin : blk +// localparam i = _i; +// where `_i` is actually some auto-generated name. +static void rewriteGenForDeclInit(AstNode *loop) +{ + // check if this generate for loop contains an inline declaration + log_assert(loop->type == AST_GENFOR); + AstNode *decl = loop->children[0]; + if (decl->type == AST_ASSIGN_EQ) + return; + log_assert(decl->type == AST_GENVAR); + log_assert(loop->children.size() == 5); + + // identify each component of the loop + AstNode *init = loop->children[1]; + AstNode *cond = loop->children[2]; + AstNode *incr = loop->children[3]; + AstNode *body = loop->children[4]; + log_assert(init->type == AST_ASSIGN_EQ); + log_assert(incr->type == AST_ASSIGN_EQ); + log_assert(body->type == AST_GENBLOCK); + + // create a unique name for the genvar + std::string old_str = decl->str; + std::string new_str = stringf("$genfordecl$%d$%s", autoidx++, old_str.c_str()); + + // rename and move the genvar declaration to the containing description + decl->str = new_str; + loop->children.erase(loop->children.begin()); + log_assert(current_ast_mod != nullptr); + current_ast_mod->children.push_back(decl); + + // create a new localparam with old name so that the items in the loop + // can simply use the old name and shadow it as necessary + AstNode *indirect = new AstNode(AST_LOCALPARAM); + indirect->str = old_str; + AstNode *ident = new AstNode(AST_IDENTIFIER); + ident->str = new_str; + indirect->children.push_back(ident); + + body->children.insert(body->children.begin(), indirect); + + // only perform the renaming for the initialization, guard, and + // incrementation to enable proper shadowing of the synthetic localparam + std::function substitute = [&](AstNode *node) { + if (node->type == AST_IDENTIFIER && node->str == old_str) + node->str = new_str; + for (AstNode *child : node->children) + substitute(child); + }; + substitute(init); + substitute(cond); + substitute(incr); +} + %} %define api.prefix {frontend_verilog_yy} @@ -321,6 +380,7 @@ static void checkLabelsMatch(const char *element, const std::string *before, con %type attr case_attr %type struct_union %type asgn_binop +%type genvar_identifier %type specify_target %type specify_triple specify_opt_triple @@ -2978,16 +3038,50 @@ gen_stmt_or_module_body_stmt: free_attr($1); }; +genvar_identifier: + TOK_ID { + $$ = new AstNode(AST_IDENTIFIER); + $$->str = *$1; + delete $1; + }; + +genvar_initialization: + TOK_GENVAR genvar_identifier { + frontend_verilog_yyerror("Generate for loop variable declaration is missing initialization!"); + } | + TOK_GENVAR genvar_identifier '=' expr { + if (!sv_mode) + frontend_verilog_yyerror("Generate for loop inline variable declaration is only supported in SystemVerilog mode!"); + AstNode *node = new AstNode(AST_GENVAR); + node->is_reg = true; + node->is_signed = true; + node->range_left = 31; + node->range_right = 0; + node->str = $2->str; + node->children.push_back(checkRange(node, nullptr)); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); + node = new AstNode(AST_ASSIGN_EQ, $2, $4); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @4); + } | + genvar_identifier '=' expr { + AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); + ast_stack.back()->children.push_back(node); + SET_AST_NODE_LOC(node, @1, @3); + }; + // this production creates the obligatory if-else shift/reduce conflict gen_stmt: TOK_FOR '(' { AstNode *node = new AstNode(AST_GENFOR); ast_stack.back()->children.push_back(node); ast_stack.push_back(node); - } simple_behavioral_stmt ';' expr { + } genvar_initialization ';' expr { ast_stack.back()->children.push_back($6); } ';' simple_behavioral_stmt ')' gen_stmt_block { SET_AST_NODE_LOC(ast_stack.back(), @1, @11); + rewriteGenForDeclInit(ast_stack.back()); ast_stack.pop_back(); } | TOK_IF '(' expr ')' { -- cgit v1.2.3 From c3d4bb4cc95c417225fec8b16147dec3453ab94d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 2 Sep 2021 14:59:16 +0200 Subject: update required verific version --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 1b8bc1b51..99094f099 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -58,7 +58,7 @@ USING_YOSYS_NAMESPACE # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210701 +#if YOSYSHQ_VERIFIC_API_VERSION < 20210801 # error "Please update your version of YosysHQ flavored Verific." #endif -- cgit v1.2.3 From 551ef85cd74c0d984322990b462a7835c7023dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcelina=20Ko=C5=9Bcielnicka?= Date: Mon, 13 Sep 2021 15:38:54 +0200 Subject: verilog: Squash flex-triggered warning. --- frontends/verilog/verilog_lexer.l | 2 ++ 1 file changed, 2 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 0306f5494..89c1aa895 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -37,6 +37,8 @@ #ifdef __clang__ // bison generates code using the 'register' storage class specifier #pragma clang diagnostic ignored "-Wdeprecated-register" +// flex generates weirdly-indented code +#pragma clang diagnostic ignored "-Wmisleading-indentation" #endif #include "kernel/log.h" -- cgit v1.2.3 From 6b7267b849abf7688938e5e53ae7017e8588ff18 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Mon, 2 Aug 2021 18:42:34 -0600 Subject: verilog: fix multiple AST_PREFIX scope resolution issues - Root AST_PREFIX nodes are now subject to genblk expansion to allow them to refer to a locally-visible generate block - Part selects on AST_PREFIX member leafs can now refer to generate block items (previously would not resolve and raise an error) - Add source location information to AST_PREFIX nodes --- frontends/ast/simplify.cc | 13 +++++++++---- frontends/verilog/verilog_parser.y | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f713cf8e1..607ca9a8b 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -4045,7 +4045,7 @@ AstNode *AstNode::readmem(bool is_readmemh, std::string mem_filename, AstNode *m // prefix is carried forward, but resolution of their children is deferred void AstNode::expand_genblock(const std::string &prefix) { - if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE) { + if (type == AST_IDENTIFIER || type == AST_FCALL || type == AST_TCALL || type == AST_WIRETYPE || type == AST_PREFIX) { log_assert(!str.empty()); // search starting in the innermost scope and then stepping outward @@ -4131,10 +4131,15 @@ void AstNode::expand_genblock(const std::string &prefix) for (size_t i = 0; i < children.size(); i++) { AstNode *child = children[i]; - // AST_PREFIX member names should not be prefixed; a nested AST_PREFIX - // still needs to recursed-into - if (type == AST_PREFIX && i == 1 && child->type == AST_IDENTIFIER) + // AST_PREFIX member names should not be prefixed; we recurse into them + // as normal to ensure indices and ranges are properly resolved, and + // then restore the previous string + if (type == AST_PREFIX && i == 1) { + std::string backup_scope_name = child->str; + child->expand_genblock(prefix); + child->str = backup_scope_name; continue; + } // functions/tasks may reference wires, constants, etc. in this scope if (child->type == AST_FUNCTION || child->type == AST_TASK) continue; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 8d0ba4cf6..91b1140e9 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2973,6 +2973,7 @@ rvalue: hierarchical_id '[' expr ']' '.' rvalue { $$ = new AstNode(AST_PREFIX, $3, $6); $$->str = *$1; + SET_AST_NODE_LOC($$, @1, @6); delete $1; } | hierarchical_id range { -- cgit v1.2.3 From d6fe6d4fb62be3bb5ec876f1f56356d757b65a41 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Fri, 13 Aug 2021 20:51:28 -0700 Subject: sv: support wand and wor of data types This enables the usage of declarations of wand or wor with a base type of logic, integer, or a typename. Note that declarations of nets with 2-state base types is still permitted, in violation of the spec. --- frontends/verilog/verilog_parser.y | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 91b1140e9..80b40f982 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -832,16 +832,10 @@ opt_wire_type_token: wire_type_token | %empty; wire_type_token: - TOK_WOR { - astbuf3->is_wor = true; + // nets + net_type { } | - TOK_WAND { - astbuf3->is_wand = true; - } | - // wires - TOK_WIRE { - } | - TOK_WIRE logic_type { + net_type logic_type { } | // regs TOK_REG { @@ -868,6 +862,15 @@ wire_type_token: astbuf3->range_right = 0; }; +net_type: + TOK_WOR { + astbuf3->is_wor = true; + } | + TOK_WAND { + astbuf3->is_wand = true; + } | + TOK_WIRE; + logic_type: TOK_LOGIC { } | -- cgit v1.2.3 From 9658d2e337a54fc06873de716d0ae5586ffd869b Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 23 Sep 2021 13:33:55 -0400 Subject: Fix TOK_ID memory leak in for_initialization --- frontends/verilog/verilog_parser.y | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 8d0ba4cf6..acb8b996c 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -2674,6 +2674,7 @@ for_initialization: AstNode *node = new AstNode(AST_ASSIGN_EQ, ident, $3); ast_stack.back()->children.push_back(node); SET_AST_NODE_LOC(node, @1, @3); + delete $1; } | non_io_wire_type range TOK_ID { frontend_verilog_yyerror("For loop variable declaration is missing initialization!"); -- cgit v1.2.3 From fbd70f28f044968fd59740e34652071c4ee01218 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Fri, 1 Oct 2021 14:41:11 -0600 Subject: Specify minimum bison version 3.0+ Yosys works with bison 3.0 (or newer), but not bison 2.7 (the previous release). Ideally, we would require "3" rather than "3.0" to give a better error message, but bison 2.3, which still ships with macOS, does not support major-only version requirements. With this change, building with an outdated bison yields: `frontends/rtlil/rtlil_parser.y:25.10-14: require bison 3.0, but have 2.3`. --- frontends/rtlil/rtlil_parser.y | 2 ++ frontends/verilog/verilog_parser.y | 2 ++ 2 files changed, 4 insertions(+) (limited to 'frontends') diff --git a/frontends/rtlil/rtlil_parser.y b/frontends/rtlil/rtlil_parser.y index 67aeb10e0..7d99b2c42 100644 --- a/frontends/rtlil/rtlil_parser.y +++ b/frontends/rtlil/rtlil_parser.y @@ -22,6 +22,8 @@ * */ +%require "3.0" + %{ #include #include "frontends/rtlil/rtlil_frontend.h" diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 5eb1115ce..171e098a5 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -33,6 +33,8 @@ * */ +%require "3.0" + %{ #include #include -- cgit v1.2.3 From abc5700628cff4fc9334e28fbaccc35c75dfa990 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 4 Oct 2021 16:48:33 +0200 Subject: verific set db_infer_set_reset_registers --- frontends/verific/verific.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 99094f099..231003753 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2313,6 +2313,7 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); + RuntimeFlags::SetVar("db_infer_set_reset_registers",1); RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); -- cgit v1.2.3 From 1602a0386419495993f25667c7c6e5fb55010592 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 8 Oct 2021 16:21:25 +0200 Subject: Add support for $aldff flip-flops to verific importer Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 55 +++++++++++++++++++++++++++++++++++++++++++- frontends/verific/verific.h | 1 + 2 files changed, 55 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 231003753..cbbae7417 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -410,6 +410,20 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == PRIM_DFF) + { + VerificClocking clocking(this, inst->GetClock()); + log_assert(clocking.disable_sig == State::S0); + log_assert(clocking.body_net == nullptr); + + if (inst->GetAsyncVal()->IsGnd()) + clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + else + clocking.addAldff(inst_name, net_map_at(inst->GetAsyncCond()), net_map_at(inst->GetAsyncVal()), + net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + return true; + } + return false; } @@ -792,6 +806,34 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == OPER_WIDE_DFF) + { + VerificClocking clocking(this, inst->GetClock()); + log_assert(clocking.disable_sig == State::S0); + log_assert(clocking.body_net == nullptr); + + RTLIL::SigSpec sig_d = IN; + RTLIL::SigSpec sig_q = OUT; + RTLIL::SigSpec sig_adata = IN1; + RTLIL::SigSpec sig_acond = IN2; + + if (sig_acond.is_fully_const() && !sig_acond.as_bool()) { + cell = clocking.addDff(inst_name, sig_d, sig_q); + import_attributes(cell->attributes, inst); + } else { + int offset = 0, width = 0; + for (offset = 0; offset < GetSize(sig_acond); offset += width) { + for (width = 1; offset+width < GetSize(sig_acond); width++) + if (sig_acond[offset] != sig_acond[offset+width]) break; + cell = clocking.addAldff(inst_name, sig_acond[offset], sig_adata.extract(offset, width), + sig_d.extract(offset, width), sig_q.extract(offset, width)); + import_attributes(cell->attributes, inst); + } + } + + return true; + } + #undef IN #undef IN1 #undef IN2 @@ -1806,6 +1848,17 @@ Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::Si return module->addDffsr(name, clock_sig, sig_set, sig_clr, sig_d, sig_q, posedge); } +Cell *VerificClocking::addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL::SigSpec sig_adata, SigSpec sig_d, SigSpec sig_q) +{ + log_assert(gclk == false); + log_assert(disable_sig == State::S0); + + if (enable_sig != State::S1) + sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); + + return module->addAldff(name, clock_sig, sig_aload, sig_d, sig_q, sig_adata, posedge); +} + // ================================================================== struct VerificExtNets @@ -2313,7 +2366,7 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); - RuntimeFlags::SetVar("db_infer_set_reset_registers",1); + RuntimeFlags::SetVar("db_infer_set_reset_registers", 1); RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index f79d8042a..9d5beb787 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -50,6 +50,7 @@ struct VerificClocking { RTLIL::Cell *addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const init_value = Const()); RTLIL::Cell *addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec sig_d, SigSpec sig_q, Const arst_value); RTLIL::Cell *addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::SigSpec sig_clr, SigSpec sig_d, SigSpec sig_q); + RTLIL::Cell *addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL::SigSpec sig_adata, SigSpec sig_d, SigSpec sig_q); bool property_matches_sequence(const VerificClocking &seq) const { if (clock_net != seq.clock_net) -- cgit v1.2.3 From 34f1df84357e8d053b930970ff53e24f35e1b1b9 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 8 Oct 2021 17:24:45 +0200 Subject: Fixes and add comments for open FIXME items Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index cbbae7417..59fdda068 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -410,13 +410,23 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == PRIM_DLATCHRS) + { + if (inst->GetSet()->IsGnd() && inst->GetReset()->IsGnd()) + module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + else + module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetSet()), net_map_at(inst->GetReset()), + net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + return true; + } + if (inst->Type() == PRIM_DFF) { VerificClocking clocking(this, inst->GetClock()); log_assert(clocking.disable_sig == State::S0); log_assert(clocking.body_net == nullptr); - if (inst->GetAsyncVal()->IsGnd()) + if (inst->GetAsyncCond()->IsGnd()) clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); else clocking.addAldff(inst_name, net_map_at(inst->GetAsyncCond()), net_map_at(inst->GetAsyncVal()), @@ -424,6 +434,8 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr return true; } + // FIXME: PRIM_DLATCH + return false; } @@ -534,6 +546,23 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == PRIM_DFF) + { + VerificClocking clocking(this, inst->GetClock()); + log_assert(clocking.disable_sig == State::S0); + log_assert(clocking.body_net == nullptr); + + if (inst->GetAsyncCond()->IsGnd()) + cell = clocking.addDff(inst_name, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + else + cell = clocking.addAldff(inst_name, net_map_at(inst->GetAsyncCond()), net_map_at(inst->GetAsyncVal()), + net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + import_attributes(cell->attributes, inst); + return true; + } + + // FIXME: PRIM_DLATCH + #define IN operatorInput(inst) #define IN1 operatorInput1(inst) #define IN2 operatorInput2(inst) @@ -806,6 +835,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + // FIXME: OPER_WIDE_DLATCHSR + if (inst->Type() == OPER_WIDE_DFF) { VerificClocking clocking(this, inst->GetClock()); @@ -834,6 +865,8 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + // FIXME: OPER_WIDE_DLATCH + #undef IN #undef IN1 #undef IN2 -- cgit v1.2.3 From 93fbc9fba4400814a859a9d9bfb05b3b92500e31 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Sun, 10 Oct 2021 10:01:45 +0200 Subject: Import module attributes from Verific --- frontends/verific/verific.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 231003753..c03e16eb2 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -917,6 +917,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se } else { log("Importing module %s.\n", RTLIL::id2cstr(module->name)); } + import_attributes(module->attributes, nl, nl); SetIter si; MapIter mi, mi2; -- cgit v1.2.3 From c8074769b081f26b2129910502dd9031acd01a2a Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Mon, 11 Oct 2021 10:00:20 +0200 Subject: Add Verific adffe/dffsre/aldffe FIXMEs Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 59fdda068..b8742e61d 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1864,6 +1864,7 @@ Cell *VerificClocking::addAdff(IdString name, RTLIL::SigSpec sig_arst, SigSpec s log_assert(gclk == false); log_assert(disable_sig == State::S0); + // FIXME: Adffe if (enable_sig != State::S1) sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); @@ -1875,6 +1876,7 @@ Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::Si log_assert(gclk == false); log_assert(disable_sig == State::S0); + // FIXME: Dffsre if (enable_sig != State::S1) sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); @@ -1886,6 +1888,7 @@ Cell *VerificClocking::addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL:: log_assert(gclk == false); log_assert(disable_sig == State::S0); + // FIXME: Aldffe if (enable_sig != State::S1) sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); -- cgit v1.2.3 From 1aa68969660549ae9c0fd683c0a328c499694b49 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 14 Oct 2021 13:04:32 +0200 Subject: Support PRIM_BUFIF1 primitive --- frontends/verific/verific.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 74638dc8d..fcacbd086 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -371,7 +371,7 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr return true; } - if (inst->Type() == PRIM_TRI) { + if ((inst->Type() == PRIM_TRI) || (inst->Type() == PRIM_BUFIF1)) { module->addMuxGate(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); return true; } @@ -497,7 +497,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } - if (inst->Type() == PRIM_TRI) { + if ((inst->Type() == PRIM_TRI) || (inst->Type() == PRIM_BUFIF1)) { cell = module->addMux(inst_name, RTLIL::State::Sz, net_map_at(inst->GetInput()), net_map_at(inst->GetControl()), net_map_at(inst->GetOutput())); import_attributes(cell->attributes, inst); return true; -- cgit v1.2.3 From 17269ae59bda6bcf60dbc9ad9d00afc69aa05499 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 20 Oct 2021 10:02:58 +0200 Subject: Option to disable verific VHDL support --- frontends/verific/Makefile.inc | 2 ++ frontends/verific/verific.cc | 54 +++++++++++++++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 11 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/Makefile.inc b/frontends/verific/Makefile.inc index 972f4f9f1..c82428613 100644 --- a/frontends/verific/Makefile.inc +++ b/frontends/verific/Makefile.inc @@ -10,9 +10,11 @@ EXTRA_TARGETS += share/verific share/verific: $(P) rm -rf share/verific.new $(Q) mkdir -p share/verific.new +ifneq ($(DISABLE_VERIFIC_VHDL),1) $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1987/. share/verific.new/vhdl_vdbs_1987 $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_1993/. share/verific.new/vhdl_vdbs_1993 $(Q) cp -r $(VERIFIC_DIR)/vhdl_packages/vdbs_2008/. share/verific.new/vhdl_vdbs_2008 +endif $(Q) chmod -R a+rX share/verific.new $(Q) mv share/verific.new share/verific diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index fcacbd086..a265dc8b4 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -43,13 +43,16 @@ USING_YOSYS_NAMESPACE #endif #include "veri_file.h" -#include "vhdl_file.h" #include "hier_tree.h" #include "VeriModule.h" #include "VeriWrite.h" -#include "VhdlUnits.h" #include "VeriLibrary.h" +#ifdef VERIFIC_VHDL_SUPPORT +#include "vhdl_file.h" +#include "VhdlUnits.h" +#endif + #ifdef YOSYSHQ_VERIFIC_EXTENSIONS #include "InitialAssertions.h" #endif @@ -175,8 +178,10 @@ void VerificImporter::import_attributes(dict &att return; if (!type_range->IsTypeEnum()) return; +#ifdef VERIFIC_VHDL_SUPPORT if (nl->IsFromVhdl() && strcmp(type_range->GetTypeName(), "STD_LOGIC") == 0) return; +#endif auto type_name = type_range->GetTypeName(); if (!type_name) return; @@ -202,6 +207,7 @@ void VerificImporter::import_attributes(dict &att log_error("Expected TypeRange value '%s' to be of form 'b.\n", v); attributes.emplace(stringf("\\enum_value_%s", p+2), RTLIL::escape_id(k)); } +#ifdef VERIFIC_VHDL_SUPPORT else if (nl->IsFromVhdl()) { // Expect "" or plain auto p = v; @@ -237,6 +243,7 @@ void VerificImporter::import_attributes(dict &att if (p == nullptr) log_error("Expected TypeRange value '%s' to be of form \"\" or .\n", v); } +#endif } } } @@ -2042,11 +2049,13 @@ void verific_import(Design *design, const std::map &par std::set nl_todo, nl_done; - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); VeriLibrary *veri_lib = veri_file::GetLibrary("work", 1); Array *netlists = NULL; Array veri_libs, vhdl_libs; +#ifdef VERIFIC_VHDL_SUPPORT + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary("work", 1); if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); +#endif if (veri_lib) veri_libs.InsertLast(veri_lib); Map verific_params(STRING_HASH); @@ -2077,12 +2086,13 @@ void verific_import(Design *design, const std::map &par } } +#ifdef VERIFIC_VHDL_SUPPORT if (vhdl_lib) { VhdlDesignUnit *vhdl_unit = vhdl_lib->GetPrimUnit(top.c_str()); if (vhdl_unit) vhdl_units.InsertLast(vhdl_unit); } - +#endif netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, &verific_params); } @@ -2119,7 +2129,9 @@ void verific_import(Design *design, const std::map &par } veri_file::Reset(); +#ifdef VERIFIC_VHDL_SUPPORT vhdl_file::Reset(); +#endif Libset::Reset(); verific_incdirs.clear(); verific_libdirs.clear(); @@ -2170,11 +2182,13 @@ struct VerificPass : public Pass { log("Like -sv, but define FORMAL instead of SYNTHESIS.\n"); log("\n"); log("\n"); +#ifdef VERIFIC_VHDL_SUPPORT log(" verific {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); log("\n"); log("Load the specified VHDL files into Verific.\n"); log("\n"); log("\n"); +#endif log(" verific {-f|-F} \n"); log("\n"); log("Load and execute the specified command file.\n"); @@ -2408,17 +2422,18 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); +#ifdef VERIFIC_VHDL_SUPPORT RuntimeFlags::SetVar("vhdl_extract_dualport_rams", 0); RuntimeFlags::SetVar("vhdl_extract_multiport_rams", 1); RuntimeFlags::SetVar("vhdl_support_variable_slice", 1); RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); - RuntimeFlags::SetVar("veri_preserve_assignments", 1); RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); - - RuntimeFlags::SetVar("veri_preserve_comments",1); //RuntimeFlags::SetVar("vhdl_preserve_comments",1); +#endif + RuntimeFlags::SetVar("veri_preserve_assignments", 1); + RuntimeFlags::SetVar("veri_preserve_comments",1); // Workaround for VIPER #13851 RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); @@ -2600,6 +2615,7 @@ struct VerificPass : public Pass { goto check_error; } +#ifdef VERIFIC_VHDL_SUPPORT if (GetSize(args) > argidx && args[argidx] == "-vhdl87") { vhdl_file::SetDefaultLibraryPath((proc_share_dirname() + "verific/vhdl_vdbs_1987").c_str()); for (argidx++; argidx < GetSize(args); argidx++) @@ -2635,6 +2651,7 @@ struct VerificPass : public Pass { verific_import_pending = true; goto check_error; } +#endif #ifdef YOSYSHQ_VERIFIC_FORMALAPPS if (argidx < GetSize(args) && args[argidx] == "-app") @@ -2737,10 +2754,12 @@ struct VerificPass : public Pass { const char* module = nullptr; bool mode_vhdl = false; for (argidx++; argidx < GetSize(args); argidx++) { +#ifdef VERIFIC_VHDL_SUPPORT if (args[argidx] == "-vhdl") { mode_vhdl = true; continue; } +#endif if (args[argidx] == "-verilog") { mode_vhdl = false; continue; @@ -2767,7 +2786,11 @@ struct VerificPass : public Pass { log_cmd_error("Filname must be specified.\n"); if (mode_vhdl) +#ifdef VERIFIC_VHDL_SUPPORT vhdl_file::PrettyPrint(filename, module, work.c_str()); +#else + goto check_error; +#endif else veri_file::PrettyPrint(filename, module, work.c_str()); goto check_error; @@ -2949,11 +2972,13 @@ struct VerificPass : public Pass { { log("Running hier_tree::ElaborateAll().\n"); - VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); VeriLibrary *veri_lib = veri_file::GetLibrary(work.c_str(), 1); Array veri_libs, vhdl_libs; +#ifdef VERIFIC_VHDL_SUPPORT + VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); +#endif if (veri_lib) veri_libs.InsertLast(veri_lib); Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters); @@ -2970,7 +2995,9 @@ struct VerificPass : public Pass { cmd_error(args, argidx, "No top module specified.\n"); VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); +#ifdef VERIFIC_VHDL_SUPPORT VhdlLibrary *vhdl_lib = vhdl_file::GetLibrary(work.c_str(), 1); +#endif Array veri_modules, vhdl_units; for (; argidx < GetSize(args); argidx++) @@ -2984,14 +3011,14 @@ struct VerificPass : public Pass { veri_modules.InsertLast(veri_module); continue; } - +#ifdef VERIFIC_VHDL_SUPPORT VhdlDesignUnit *vhdl_unit = vhdl_lib ? vhdl_lib->GetPrimUnit(name) : nullptr; if (vhdl_unit) { log("Adding VHDL unit '%s' to elaboration queue.\n", name); vhdl_units.InsertLast(vhdl_unit); continue; } - +#endif log_error("Can't find module/unit '%s'.\n", name); } @@ -3051,7 +3078,9 @@ struct VerificPass : public Pass { } veri_file::Reset(); +#ifdef VERIFIC_VHDL_SUPPORT vhdl_file::Reset(); +#endif Libset::Reset(); verific_incdirs.clear(); verific_libdirs.clear(); @@ -3094,11 +3123,13 @@ struct ReadPass : public Pass { log("the language version (and before file names) to set additional verilog defines.\n"); log("\n"); log("\n"); +#ifdef VERIFIC_VHDL_SUPPORT log(" read {-vhdl87|-vhdl93|-vhdl2k|-vhdl2008|-vhdl} ..\n"); log("\n"); log("Load the specified VHDL files. (Requires Verific.)\n"); log("\n"); log("\n"); +#endif log(" read {-f|-F} \n"); log("\n"); log("Load and execute the specified command file. (Requires Verific.)\n"); @@ -3181,6 +3212,7 @@ struct ReadPass : public Pass { return; } +#ifdef VERIFIC_VHDL_SUPPORT if (args[1] == "-vhdl87" || args[1] == "-vhdl93" || args[1] == "-vhdl2k" || args[1] == "-vhdl2008" || args[1] == "-vhdl") { if (use_verific) { args[0] = "verific"; @@ -3190,7 +3222,7 @@ struct ReadPass : public Pass { } return; } - +#endif if (args[1] == "-f" || args[1] == "-F") { if (use_verific) { args[0] = "verific"; -- cgit v1.2.3 From 16a177560f27c77ba490ac7dbe9eae3d3766ca1e Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Thu, 21 Oct 2021 05:42:47 +0200 Subject: Initial Verific impoter support for {PRIM,WIDE_OPER}_DLATCH{,RS} Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 59 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index a265dc8b4..6b303e4b6 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -441,7 +441,11 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr return true; } - // FIXME: PRIM_DLATCH + if (inst->Type() == PRIM_DLATCH) + { + module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + return true; + } return false; } @@ -568,7 +572,18 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } - // FIXME: PRIM_DLATCH + if (inst->Type() == PRIM_DLATCH) + { + if (inst->GetAsyncCond()->IsGnd()) { + cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + } else { + RTLIL::SigSpec sig_set = module->And(NEW_ID, net_map_at(inst->GetAsyncCond()), net_map_at(inst->GetAsyncVal())); + RTLIL::SigSpec sig_clr = module->And(NEW_ID, net_map_at(inst->GetAsyncCond()), module->Not(NEW_ID, net_map_at(inst->GetAsyncVal()))); + cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), sig_set, sig_clr, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + } + import_attributes(cell->attributes, inst); + return true; + } #define IN operatorInput(inst) #define IN1 operatorInput1(inst) @@ -842,7 +857,19 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } - // FIXME: OPER_WIDE_DLATCHSR + if (inst->Type() == OPER_WIDE_DLATCHRS) + { + RTLIL::SigSpec sig_set = operatorInport(inst, "set"); + RTLIL::SigSpec sig_reset = operatorInport(inst, "reset"); + + if (sig_set.is_fully_const() && !sig_set.as_bool() && sig_reset.is_fully_const() && !sig_reset.as_bool()) + cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), IN, OUT); + else + cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), sig_set, sig_reset, IN, OUT); + import_attributes(cell->attributes, inst); + + return true; + } if (inst->Type() == OPER_WIDE_DFF) { @@ -872,7 +899,31 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } - // FIXME: OPER_WIDE_DLATCH + if (inst->Type() == OPER_WIDE_DLATCH) + { + RTLIL::SigSpec sig_d = IN; + RTLIL::SigSpec sig_q = OUT; + RTLIL::SigSpec sig_adata = IN1; + RTLIL::SigSpec sig_acond = IN2; + + if (sig_acond.is_fully_const() && !sig_acond.as_bool()) { + cell = module->addDlatch(inst_name, net_map_at(inst->GetControl()), sig_d, sig_q); + import_attributes(cell->attributes, inst); + } else { + int offset = 0, width = 0; + for (offset = 0; offset < GetSize(sig_acond); offset += width) { + for (width = 1; offset+width < GetSize(sig_acond); width++) + if (sig_acond[offset] != sig_acond[offset+width]) break; + RTLIL::SigSpec sig_set = module->Mux(NEW_ID, RTLIL::SigSpec(0, width), sig_adata.extract(offset, width), sig_acond[offset]); + RTLIL::SigSpec sig_clr = module->Mux(NEW_ID, RTLIL::SigSpec(0, width), module->Not(NEW_ID, sig_adata.extract(offset, width)), sig_acond[offset]); + cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), sig_set, sig_clr, + sig_d.extract(offset, width), sig_q.extract(offset, width)); + import_attributes(cell->attributes, inst); + } + } + + return true; + } #undef IN #undef IN1 -- cgit v1.2.3 From 90b440f870a8ac2c91b3f716f38a4f538cad2549 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Thu, 21 Oct 2021 12:13:35 +0200 Subject: Fix verific.cc PRIM_DLATCH handling Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 6b303e4b6..18fba9b76 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -443,7 +443,13 @@ bool VerificImporter::import_netlist_instance_gates(Instance *inst, RTLIL::IdStr if (inst->Type() == PRIM_DLATCH) { - module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + if (inst->GetAsyncCond()->IsGnd()) { + module->addDlatch(inst_name, net_map_at(inst->GetControl()), net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + } else { + RTLIL::SigSpec sig_set = module->And(NEW_ID, net_map_at(inst->GetAsyncCond()), net_map_at(inst->GetAsyncVal())); + RTLIL::SigSpec sig_clr = module->And(NEW_ID, net_map_at(inst->GetAsyncCond()), module->Not(NEW_ID, net_map_at(inst->GetAsyncVal()))); + module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), sig_set, sig_clr, net_map_at(inst->GetInput()), net_map_at(inst->GetOutput())); + } return true; } -- cgit v1.2.3 From b8624ad2aef941776f5b4a08f66f8d43e70f8467 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Mon, 25 Oct 2021 09:04:43 +0200 Subject: Compile option for enabling async load verific support --- frontends/verific/verific.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 18fba9b76..47ddbc662 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2474,8 +2474,11 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); +#ifdef VERIFIC_ASYNC_LOAD + RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); +#else RuntimeFlags::SetVar("db_infer_set_reset_registers", 1); - +#endif RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); -- cgit v1.2.3 From bd16d01c0eed5c96a241e6ee9e56b8f7890319a1 Mon Sep 17 00:00:00 2001 From: Rupert Swarbrick Date: Tue, 19 Oct 2021 18:43:30 -0600 Subject: Split out logic for reprocessing an AstModule This will enable other features to use same core logic for replacing an existing AstModule with a newly elaborated version. --- frontends/ast/ast.cc | 67 ++++++++++++++++++++++++++++++++++------------------ frontends/ast/ast.h | 14 ++++++++++- 2 files changed, 57 insertions(+), 24 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 4fbc238b0..fe1f9e861 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -983,8 +983,7 @@ static bool param_has_no_default(const AstNode *param) { (children.size() == 1 && children[0]->type == AST_RANGE); } -// create and add a new AstModule from an AST_MODULE AST node -static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) +static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstNode *original_ast = NULL, bool quiet = false) { log_assert(current_scope.empty()); log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE); @@ -1197,6 +1196,42 @@ static void process_module(RTLIL::Design *design, AstNode *ast, bool defer, AstN } design->add(current_module); + return current_module; +} + +RTLIL::Module * +AST_INTERNAL::process_and_replace_module(RTLIL::Design *design, + RTLIL::Module *old_module, + AstNode *new_ast, + AstNode *original_ast) +{ + // The old module will be deleted. Rename and mark for deletion, using + // a static counter to make sure we get a unique name. + static unsigned counter; + std::ostringstream new_name; + new_name << old_module->name.str() + << "_before_process_and_replace_module_" + << counter; + ++counter; + + design->rename(old_module, new_name.str()); + old_module->set_bool_attribute(ID::to_delete); + + // Check if the module was the top module. If it was, we need to remove + // the top attribute and put it on the new module. + bool is_top = false; + if (old_module->get_bool_attribute(ID::initial_top)) { + old_module->attributes.erase(ID::initial_top); + is_top = true; + } + + // Generate RTLIL from AST for the new module and add to the design: + RTLIL::Module* new_module = process_module(design, new_ast, false, original_ast); + + if (is_top) + new_module->set_bool_attribute(ID::top); + + return new_module; } // renames identifiers in tasks and functions within a package @@ -1412,11 +1447,10 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule // When an interface instance is found in a module, the whole RTLIL for the module will be rederived again // from AST. The interface members are copied into the AST module with the prefix of the interface. -void AstModule::reprocess_module(RTLIL::Design *design, const dict &local_interfaces) +void AstModule::expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) { loadconfig(); - bool is_top = false; AstNode *new_ast = ast->clone(); for (auto &intf : local_interfaces) { std::string intfname = intf.first.str(); @@ -1473,28 +1507,15 @@ void AstModule::reprocess_module(RTLIL::Design *design, const dictname.str(); - std::string changed_name = original_name + "_before_replacing_local_interfaces"; - design->rename(this, changed_name); - this->set_bool_attribute(ID::to_delete); + // Generate RTLIL from AST for the new module and add to the design, + // renaming this module to move it out of the way. + RTLIL::Module* new_module = + process_and_replace_module(design, this, new_ast, ast_before_replacing_interface_ports); - // Check if the module was the top module. If it was, we need to remove the top attribute and put it on the - // new module. - if (this->get_bool_attribute(ID::initial_top)) { - this->attributes.erase(ID::initial_top); - is_top = true; - } - - // Generate RTLIL from AST for the new module and add to the design: - process_module(design, new_ast, false, ast_before_replacing_interface_ports); - delete(new_ast); - RTLIL::Module* mod = design->module(original_name); - if (is_top) - mod->set_bool_attribute(ID::top); + delete new_ast; // Set the attribute "interfaces_replaced_in_module" so that it does not happen again. - mod->set_bool_attribute(ID::interfaces_replaced_in_module); + new_module->set_bool_attribute(ID::interfaces_replaced_in_module); } // create a new parametric module (when needed) and return the name of the generated module - WITH support for interfaces diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 63104bca4..66bbdd7b4 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -348,7 +348,7 @@ namespace AST RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, bool mayfail) override; RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail) override; std::string derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet = false); - void reprocess_module(RTLIL::Design *design, const dict &local_interfaces) override; + void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; RTLIL::Module *clone() const override; void loadconfig() const; }; @@ -395,6 +395,18 @@ namespace AST_INTERNAL extern dict> current_memwr_visible; struct LookaheadRewriter; struct ProcessGenerator; + + // Create and add a new AstModule from new_ast, then use it to replace + // old_module in design, renaming old_module to move it out of the way. + // Return the new module. + // + // If original_ast is not null, it will be used as the AST node for the + // new module. Otherwise, new_ast will be used. + RTLIL::Module * + process_and_replace_module(RTLIL::Design *design, + RTLIL::Module *old_module, + AST::AstNode *new_ast, + AST::AstNode *original_ast = nullptr); } YOSYS_NAMESPACE_END -- cgit v1.2.3 From e833c6a418103feb30f0cc3e5c482da00ee9f820 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 19 Oct 2021 18:46:26 -0600 Subject: verilog: use derived module info to elaborate cell connections - Attempt to lookup a derived module if it potentially contains a port connection with elaboration ambiguities - Mark the cell if module has not yet been derived - This can be extended to implement automatic hierarchical port connections in a future change --- frontends/ast/ast.cc | 69 +++++++++++--- frontends/ast/ast.h | 14 ++- frontends/ast/genrtlil.cc | 23 +++-- frontends/ast/simplify.cc | 226 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 291 insertions(+), 41 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index fe1f9e861..7be8ab565 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -854,7 +854,7 @@ RTLIL::Const AstNode::bitsAsConst(int width) return bitsAsConst(width, is_signed); } -RTLIL::Const AstNode::asAttrConst() +RTLIL::Const AstNode::asAttrConst() const { log_assert(type == AST_CONSTANT); @@ -869,8 +869,17 @@ RTLIL::Const AstNode::asAttrConst() return val; } -RTLIL::Const AstNode::asParaConst() +RTLIL::Const AstNode::asParaConst() const { + if (type == AST_REALVALUE) + { + AstNode *strnode = AstNode::mkconst_str(stringf("%f", realvalue)); + RTLIL::Const val = strnode->asAttrConst(); + val.flags |= RTLIL::CONST_FLAG_REAL; + delete strnode; + return val; + } + RTLIL::Const val = asAttrConst(); if (is_signed) val.flags |= RTLIL::CONST_FLAG_SIGNED; @@ -1043,8 +1052,11 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d } } - // TODO(zachjs): make design available to simplify() in the future + // simplify this module or interface using the current design as context + // for lookup up ports and wires within cells + set_simplify_design_context(design); while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } + set_simplify_design_context(nullptr); if (flag_dump_ast2) { log("Dumping AST after simplification:\n"); @@ -1171,6 +1183,9 @@ static RTLIL::Module *process_module(RTLIL::Design *design, AstNode *ast, bool d continue; module->attributes[attr.first] = attr.second->asAttrConst(); } + for (const AstNode *node : ast->children) + if (node->type == AST_PARAMETER) + current_module->avail_parameters(node->str); } if (ast->type == AST_INTERFACE) @@ -1445,6 +1460,26 @@ void AST::explode_interface_port(AstNode *module_ast, RTLIL::Module * intfmodule } } +// AstModules may contain cells marked with ID::reprocess_after, which indicates +// that it should be reprocessed once the specified module has been elaborated. +bool AstModule::reprocess_if_necessary(RTLIL::Design *design) +{ + for (const RTLIL::Cell *cell : cells()) + { + std::string modname = cell->get_string_attribute(ID::reprocess_after); + if (modname.empty()) + continue; + if (design->module(modname) || design->module("$abstract" + modname)) { + log("Reprocessing module %s because instantiated module %s has become available.\n", + log_id(name), log_id(modname)); + loadconfig(); + process_and_replace_module(design, this, ast, NULL); + return true; + } + } + return false; +} + // When an interface instance is found in a module, the whole RTLIL for the module will be rederived again // from AST. The interface members are copied into the AST module with the prefix of the interface. void AstModule::expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) @@ -1649,6 +1684,17 @@ static std::string serialize_param_value(const RTLIL::Const &val) { return res; } +std::string AST::derived_module_name(std::string stripped_name, const std::vector> ¶meters) { + std::string para_info; + for (const auto &elem : parameters) + para_info += stringf("%s=%s", elem.first.c_str(), serialize_param_value(elem.second).c_str()); + + if (para_info.size() > 60) + return "$paramod$" + sha1(para_info) + stripped_name; + else + return "$paramod" + stripped_name + para_info; +} + // create a new parametric module (when needed) and return the name of the generated module std::string AstModule::derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet) { @@ -1657,9 +1703,8 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dict> named_parameters; for (const auto child : ast->children) { if (child->type != AST_PARAMETER) continue; @@ -1668,25 +1713,21 @@ std::string AstModule::derive_common(RTLIL::Design *design, const dictstr.c_str(), log_signal(it->second)); - para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str()); + named_parameters.emplace_back(child->str, it->second); continue; } it = parameters.find(stringf("$%d", para_counter)); if (it != parameters.end()) { if (!quiet) log("Parameter %d (%s) = %s\n", para_counter, child->str.c_str(), log_signal(it->second)); - para_info += stringf("%s=%s", child->str.c_str(), serialize_param_value(it->second).c_str()); + named_parameters.emplace_back(child->str, it->second); continue; } } - std::string modname; - if (parameters.size() == 0) - modname = stripped_name; - else if (para_info.size() > 60) - modname = "$paramod$" + sha1(para_info) + stripped_name; - else - modname = "$paramod" + stripped_name + para_info; + std::string modname = stripped_name; + if (parameters.size()) // not named_parameters to cover hierarchical defparams + modname = derived_module_name(stripped_name, named_parameters); if (design->has(modname)) return modname; diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 66bbdd7b4..48ec9a063 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -262,6 +262,7 @@ namespace AST void mem2reg_remove(pool &mem2reg_set, vector &delnodes); void meminfo(int &mem_width, int &mem_size, int &addr_bits); bool detect_latch(const std::string &var); + const RTLIL::Module* lookup_cell_module(); // additional functionality for evaluating constant functions struct varinfo_t { @@ -313,8 +314,8 @@ namespace AST RTLIL::Const bitsAsConst(int width, bool is_signed); RTLIL::Const bitsAsConst(int width = -1); RTLIL::Const bitsAsUnsizedConst(int width); - RTLIL::Const asAttrConst(); - RTLIL::Const asParaConst(); + RTLIL::Const asAttrConst() const; + RTLIL::Const asParaConst() const; uint64_t asInt(bool is_signed); bool bits_only_01() const; bool asBool() const; @@ -349,6 +350,7 @@ namespace AST RTLIL::IdString derive(RTLIL::Design *design, const dict ¶meters, const dict &interfaces, const dict &modports, bool mayfail) override; std::string derive_common(RTLIL::Design *design, const dict ¶meters, AstNode **new_ast_out, bool quiet = false); void expand_interfaces(RTLIL::Design *design, const dict &local_interfaces) override; + bool reprocess_if_necessary(RTLIL::Design *design) override; RTLIL::Module *clone() const override; void loadconfig() const; }; @@ -377,6 +379,14 @@ namespace AST // struct helper exposed from simplify for genrtlil AstNode *make_struct_member_range(AstNode *node, AstNode *member_node); + + // generate standard $paramod... derived module name; parameters should be + // in the order they are declared in the instantiated module + std::string derived_module_name(std::string stripped_name, const std::vector> ¶meters); + + // used to provide simplify() access to the current design for looking up + // modules, ports, wires, etc. + void set_simplify_design_context(const RTLIL::Design *design); } namespace AST_INTERNAL diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index c82664b98..a68bcd9ee 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1917,21 +1917,15 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) continue; } if (child->type == AST_PARASET) { - int extra_const_flags = 0; IdString paraname = child->str.empty() ? stringf("$%d", ++para_counter) : child->str; - if (child->children[0]->type == AST_REALVALUE) { + const AstNode *value = child->children[0]; + if (value->type == AST_REALVALUE) log_file_warning(filename, location.first_line, "Replacing floating point parameter %s.%s = %f with string.\n", - log_id(cell), log_id(paraname), child->children[0]->realvalue); - extra_const_flags = RTLIL::CONST_FLAG_REAL; - auto strnode = AstNode::mkconst_str(stringf("%f", child->children[0]->realvalue)); - strnode->cloneInto(child->children[0]); - delete strnode; - } - if (child->children[0]->type != AST_CONSTANT) + log_id(cell), log_id(paraname), value->realvalue); + else if (value->type != AST_CONSTANT) log_file_error(filename, location.first_line, "Parameter %s.%s with non-constant value!\n", log_id(cell), log_id(paraname)); - cell->parameters[paraname] = child->children[0]->asParaConst(); - cell->parameters[paraname].flags |= extra_const_flags; + cell->parameters[paraname] = value->asParaConst(); continue; } if (child->type == AST_ARGUMENT) { @@ -1948,7 +1942,12 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (sig.is_wire()) { // if the resulting SigSpec is a wire, its // signedness should match that of the AstNode - log_assert(arg->is_signed == sig.as_wire()->is_signed); + if (arg->type == AST_IDENTIFIER && arg->id2ast && arg->id2ast->is_signed && !arg->is_signed) + // fully-sliced signed wire will be resolved + // once the module becomes available + log_assert(attributes.count(ID::reprocess_after)); + else + log_assert(arg->is_signed == sig.as_wire()->is_signed); } else if (arg->is_signed) { // non-trivial signed nodes are indirected through // signed wires to enable sign extension diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 607ca9a8b..64d0fe475 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -564,6 +564,115 @@ static std::string prefix_id(const std::string &prefix, const std::string &str) return prefix + str; } +// direct access to this global should be limited to the following two functions +static const RTLIL::Design *simplify_design_context = nullptr; + +void AST::set_simplify_design_context(const RTLIL::Design *design) +{ + log_assert(!simplify_design_context || !design); + simplify_design_context = design; +} + +// lookup the module with the given name in the current design context +static const RTLIL::Module* lookup_module(const std::string &name) +{ + return simplify_design_context->module(name); +} + +const RTLIL::Module* AstNode::lookup_cell_module() +{ + log_assert(type == AST_CELL); + + auto reprocess_after = [this] (const std::string &modname) { + if (!attributes.count(ID::reprocess_after)) + attributes[ID::reprocess_after] = AstNode::mkconst_str(modname); + }; + + const AstNode *celltype = nullptr; + for (const AstNode *child : children) + if (child->type == AST_CELLTYPE) { + celltype = child; + break; + } + log_assert(celltype != nullptr); + + const RTLIL::Module *module = lookup_module(celltype->str); + if (!module) + module = lookup_module("$abstract" + celltype->str); + if (!module) { + if (celltype->str.at(0) != '$') + reprocess_after(celltype->str); + return nullptr; + } + + // build a mapping from true param name to param value + size_t para_counter = 0; + dict cell_params_map; + for (AstNode *child : children) { + if (child->type != AST_PARASET) + continue; + + if (child->str.empty() && para_counter >= module->avail_parameters.size()) + return nullptr; // let hierarchy handle this error + IdString paraname = child->str.empty() ? module->avail_parameters[para_counter++] : child->str; + + const AstNode *value = child->children[0]; + if (value->type != AST_REALVALUE && value->type != AST_CONSTANT) + return nullptr; // let genrtlil handle this error + cell_params_map[paraname] = value->asParaConst(); + } + + // put the parameters in order and generate the derived module name + std::vector> named_parameters; + for (RTLIL::IdString param : module->avail_parameters) { + auto it = cell_params_map.find(param); + if (it != cell_params_map.end()) + named_parameters.emplace_back(it->first, it->second); + } + std::string modname = celltype->str; + if (cell_params_map.size()) // not named_parameters to cover hierarchical defparams + modname = derived_module_name(celltype->str, named_parameters); + + // try to find the resolved module + module = lookup_module(modname); + if (!module) { + reprocess_after(modname); + return nullptr; + } + return module; +} + +// returns whether an expression contains an unbased unsized literal; does not +// check the literal exists in a self-determined context +static bool contains_unbased_unsized(const AstNode *node) +{ + if (node->type == AST_CONSTANT) + return node->is_unsized; + for (const AstNode *child : node->children) + if (contains_unbased_unsized(child)) + return true; + return false; +} + +// adds a wire to the current module with the given name that matches the +// dimensions of the given wire reference +void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) +{ + AstNode *left = AstNode::mkconst_int(ref->width - 1 + ref->start_offset, true); + AstNode *right = AstNode::mkconst_int(ref->start_offset, true); + if (ref->upto) + std::swap(left, right); + AstNode *range = new AstNode(AST_RANGE, left, right); + + AstNode *wire = new AstNode(AST_WIRE, range); + wire->is_signed = ref->is_signed; + wire->is_logic = true; + wire->str = str; + + current_ast_mod->children.push_back(wire); + current_scope[str] = wire; +} + // convert the AST into a simpler AST that has all parameters substituted by their // values, unrolled for-loops, expanded generate blocks, etc. when this function // is done with an AST it can be converted into RTLIL using genRTLIL(). @@ -920,19 +1029,110 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } - if (type == AST_ARGUMENT) - { - if (children.size() == 1 && children[0]->type == AST_CONSTANT) - { - // HACK: For port bindings using unbased unsized literals, mark them - // signed so they sign-extend. The hierarchy will still incorrectly - // generate a warning complaining about resizing the expression. - // This also doesn't handle the complex of something like a ternary - // expression bound to a port, where the actual size of the port is - // needed to resolve the expression correctly. - AstNode *arg = children[0]; - if (arg->is_unsized) - arg->is_signed = true; + if (type == AST_CELL) { + bool lookup_suggested = false; + + for (AstNode *child : children) { + // simplify any parameters to constants + if (child->type == AST_PARASET) + while (child->simplify(true, false, false, 1, -1, false, true)) { } + + // look for patterns which _may_ indicate ambiguity requiring + // resolution of the underlying module + if (child->type == AST_ARGUMENT) { + if (child->children.size() != 1) + continue; + const AstNode *value = child->children[0]; + if (value->type == AST_IDENTIFIER) { + const AstNode *elem = value->id2ast; + if (elem == nullptr) { + if (current_scope.count(value->str)) + elem = current_scope.at(value->str); + else + continue; + } + if (elem->type == AST_MEMORY) + // need to determine is the is a read or wire + lookup_suggested = true; + else if (elem->type == AST_WIRE && elem->is_signed && !value->children.empty()) + // this may be a fully sliced signed wire which needs + // to be indirected to produce an unsigned connection + lookup_suggested = true; + } + else if (contains_unbased_unsized(value)) + // unbased unsized literals extend to width of the context + lookup_suggested = true; + } + } + + const RTLIL::Module *module = nullptr; + if (lookup_suggested) + module = lookup_cell_module(); + if (module) { + size_t port_counter = 0; + for (AstNode *child : children) { + if (child->type != AST_ARGUMENT) + continue; + + // determine the full name of port this argument is connected to + RTLIL::IdString port_name; + if (child->str.size()) + port_name = child->str; + else { + if (port_counter >= module->ports.size()) + log_file_error(filename, location.first_line, + "Cell instance has more ports than the module!\n"); + port_name = module->ports[port_counter++]; + } + + // find the port's wire in the underlying module + const RTLIL::Wire *ref = module->wire(port_name); + if (ref == nullptr) + log_file_error(filename, location.first_line, + "Cell instance refers to port %s which does not exist in module %s!.\n", + log_id(port_name), log_id(module->name)); + + // select the argument, if present + log_assert(child->children.size() <= 1); + if (child->children.empty()) + continue; + AstNode *arg = child->children[0]; + + // plain identifiers never need indirection; this also prevents + // adding infinite levels of indirection + if (arg->type == AST_IDENTIFIER && arg->children.empty()) + continue; + + // only add indirection for standard inputs or outputs + if (ref->port_input == ref->port_output) + continue; + + did_something = true; + + // create the indirection wire + std::stringstream sstr; + sstr << "$indirect$" << ref->name.c_str() << "$" << filename << ":" << location.first_line << "$" << (autoidx++); + std::string tmp_str = sstr.str(); + add_wire_for_ref(ref, tmp_str); + + AstNode *asgn = new AstNode(AST_ASSIGN); + current_ast_mod->children.push_back(asgn); + + AstNode *ident = new AstNode(AST_IDENTIFIER); + ident->str = tmp_str; + child->children[0] = ident->clone(); + + if (ref->port_input && !ref->port_output) { + asgn->children.push_back(ident); + asgn->children.push_back(arg); + } else { + log_assert(!ref->port_input && ref->port_output); + asgn->children.push_back(arg); + asgn->children.push_back(ident); + } + } + + } } -- cgit v1.2.3 From 32673edfeae7878a902883575d6b369a5ed8b0a5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 27 Oct 2021 15:55:43 +0200 Subject: Revert "Compile option for enabling async load verific support" This reverts commit b8624ad2aef941776f5b4a08f66f8d43e70f8467. --- frontends/verific/verific.cc | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 47ddbc662..18fba9b76 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2474,11 +2474,8 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); -#ifdef VERIFIC_ASYNC_LOAD - RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); -#else RuntimeFlags::SetVar("db_infer_set_reset_registers", 1); -#endif + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); -- cgit v1.2.3 From f7cc388bb57b66a97ece786697de6c992072a438 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 27 Oct 2021 15:56:56 +0200 Subject: Enable async load dff emit by default in Verific --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 18fba9b76..2d0574cf9 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2474,7 +2474,7 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_preserve_user_nets", 1); RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); - RuntimeFlags::SetVar("db_infer_set_reset_registers", 1); + RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); -- cgit v1.2.3 From 83118bfb9e0fb21788d523cc0a1daece6dc82982 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Sun, 31 Oct 2021 17:12:29 +0100 Subject: Fix verific gclk handling for async-load FFs Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 79 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 12 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 2d0574cf9..eb9f37678 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1897,30 +1897,62 @@ Cell *VerificClocking::addDff(IdString name, SigSpec sig_d, SigSpec sig_q, Const { log_assert(GetSize(sig_d) == GetSize(sig_q)); - if (GetSize(init_value) != 0) { - log_assert(GetSize(sig_q) == GetSize(init_value)); - if (sig_q.is_wire()) { - sig_q.as_wire()->attributes[ID::init] = init_value; + auto set_init_attribute = [&](SigSpec &s) { + if (GetSize(init_value) == 0) + return; + log_assert(GetSize(s) == GetSize(init_value)); + if (s.is_wire()) { + s.as_wire()->attributes[ID::init] = init_value; } else { - Wire *w = module->addWire(NEW_ID, GetSize(sig_q)); + Wire *w = module->addWire(NEW_ID, GetSize(s)); w->attributes[ID::init] = init_value; - module->connect(sig_q, w); - sig_q = w; + module->connect(s, w); + s = w; } - } + }; if (enable_sig != State::S1) sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); if (disable_sig != State::S0) { - log_assert(gclk == false); log_assert(GetSize(sig_q) == GetSize(init_value)); + + if (gclk) { + Wire *pre_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *post_q_w = module->addWire(NEW_ID, GetSize(sig_q)); + + Const initval(State::Sx, GetSize(sig_q)); + int offset = 0; + for (auto c : sig_q.chunks()) { + if (c.wire && c.wire->attributes.count(ID::init)) { + Const val = c.wire->attributes.at(ID::init); + for (int i = 0; i < GetSize(c); i++) + initval[offset+i] = val[c.offset+i]; + } + offset += GetSize(c); + } + + if (!initval.is_fully_undef()) + post_q_w->attributes[ID::init] = initval; + + module->addMux(NEW_ID, sig_d, init_value, disable_sig, pre_d); + module->addMux(NEW_ID, post_q_w, init_value, disable_sig, sig_q); + + SigSpec post_q(post_q_w); + set_init_attribute(post_q); + return module->addFf(name, pre_d, post_q); + } + + set_init_attribute(sig_q); return module->addAdff(name, clock_sig, disable_sig, sig_d, sig_q, init_value, posedge); } - if (gclk) + if (gclk) { + set_init_attribute(sig_q); return module->addFf(name, sig_d, sig_q); + } + set_init_attribute(sig_q); return module->addDff(name, clock_sig, sig_d, sig_q, posedge); } @@ -1950,13 +1982,36 @@ Cell *VerificClocking::addDffsr(IdString name, RTLIL::SigSpec sig_set, RTLIL::Si Cell *VerificClocking::addAldff(IdString name, RTLIL::SigSpec sig_aload, RTLIL::SigSpec sig_adata, SigSpec sig_d, SigSpec sig_q) { - log_assert(gclk == false); log_assert(disable_sig == State::S0); // FIXME: Aldffe if (enable_sig != State::S1) sig_d = module->Mux(NEW_ID, sig_q, sig_d, enable_sig); + if (gclk) { + Wire *pre_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *post_q = module->addWire(NEW_ID, GetSize(sig_q)); + + Const initval(State::Sx, GetSize(sig_q)); + int offset = 0; + for (auto c : sig_q.chunks()) { + if (c.wire && c.wire->attributes.count(ID::init)) { + Const val = c.wire->attributes.at(ID::init); + for (int i = 0; i < GetSize(c); i++) + initval[offset+i] = val[c.offset+i]; + } + offset += GetSize(c); + } + + if (!initval.is_fully_undef()) + post_q->attributes[ID::init] = initval; + + module->addMux(NEW_ID, sig_d, sig_adata, sig_aload, pre_d); + module->addMux(NEW_ID, post_q, sig_adata, sig_aload, sig_q); + + return module->addFf(name, pre_d, post_q); + } + return module->addAldff(name, clock_sig, sig_aload, sig_d, sig_q, sig_adata, posedge); } @@ -2868,7 +2923,7 @@ struct VerificPass : public Pass { if (!(argidx+1 < GetSize(args))) cmd_error(args, argidx+1, "No top module specified.\n"); generator->setLogger([](std::string msg) { log("%s",msg.c_str()); } ); - + std::string module = args[++argidx]; VeriLibrary* veri_lib = veri_file::GetLibrary(work.c_str(), 1); VeriModule *veri_module = veri_lib ? veri_lib->GetModule(module.c_str(), 1) : nullptr; -- cgit v1.2.3 From 2ea757da5105fcd97c31e3b99069b19ca847e068 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Mon, 1 Nov 2021 10:41:51 +0100 Subject: Add "verific -cfg" command Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 77 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index eb9f37678..5a75b52af 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2498,6 +2498,13 @@ struct VerificPass : public Pass { log(" WARNING: Templates only available in commercial build.\n"); log("\n"); #endif + log("\n"); + log("\n"); + log(" verific -cfg [ []]\n"); + log("\n"); + log("Get/set Verific runtime flags.\n"); + log("\n"); + log("\n"); log("Use YosysHQ Tabby CAD Suite if you need Yosys+Verific.\n"); log("https://www.yosyshq.com/\n"); log("\n"); @@ -2526,7 +2533,10 @@ struct VerificPass : public Pass { Message::SetConsoleOutput(0); Message::RegisterCallBackMsg(msg_func); + RuntimeFlags::SetVar("db_preserve_user_instances", 1); RuntimeFlags::SetVar("db_preserve_user_nets", 1); + RuntimeFlags::SetVar("db_preserve_x", 1); + RuntimeFlags::SetVar("db_allow_external_nets", 1); RuntimeFlags::SetVar("db_infer_wide_operators", 1); RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); @@ -2542,10 +2552,12 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("vhdl_ignore_assertion_statements", 0); RuntimeFlags::SetVar("vhdl_preserve_assignments", 1); - //RuntimeFlags::SetVar("vhdl_preserve_comments",1); + //RuntimeFlags::SetVar("vhdl_preserve_comments", 1); + RuntimeFlags::SetVar("vhdl_preserve_drivers", 1); #endif RuntimeFlags::SetVar("veri_preserve_assignments", 1); - RuntimeFlags::SetVar("veri_preserve_comments",1); + RuntimeFlags::SetVar("veri_preserve_comments", 1); + RuntimeFlags::SetVar("veri_preserve_drivers", 1); // Workaround for VIPER #13851 RuntimeFlags::SetVar("veri_create_name_for_unnamed_gen_block", 1); @@ -2556,6 +2568,8 @@ struct VerificPass : public Pass { // https://github.com/YosysHQ/yosys/issues/1055 RuntimeFlags::SetVar("veri_elaborate_top_level_modules_having_interface_ports", 1) ; + RuntimeFlags::SetVar("verific_produce_verbose_syntax_error_message", 1); + #ifndef DB_PRESERVE_INITIAL_VALUE # warning Verific was built without DB_PRESERVE_INITIAL_VALUE. #endif @@ -3200,6 +3214,65 @@ struct VerificPass : public Pass { goto check_error; } + if (argidx < GetSize(args) && args[argidx] == "-cfg") + { + if (argidx+1 == GetSize(args)) { + MapIter mi; + const char *k, *s; + unsigned long v; + pool lines; + FOREACH_MAP_ITEM(RuntimeFlags::GetVarMap(), mi, &k, &v) { + lines.insert(stringf("%s %lu", k, v)); + } + FOREACH_MAP_ITEM(RuntimeFlags::GetStringVarMap(), mi, &k, &s) { + if (s == nullptr) + lines.insert(stringf("%s NULL", k)); + else + lines.insert(stringf("%s \"%s\"", k, s)); + } + lines.sort(); + for (auto &line : lines) + log("verific -cfg %s\n", line.c_str()); + goto check_error; + } + + if (argidx+2 == GetSize(args)) { + const char *k = args[argidx+1].c_str(); + if (RuntimeFlags::HasUnsignedVar(k)) { + log("verific -cfg %s %lu\n", k, RuntimeFlags::GetVar(k)); + goto check_error; + } + if (RuntimeFlags::HasStringVar(k)) { + const char *s = RuntimeFlags::GetStringVar(k); + if (s == nullptr) + log("verific -cfg %s NULL\n", k); + else + log("verific -cfg %s \"%s\"\n", k, s); + goto check_error; + } + log_cmd_error("Can't find Verific Runtime flag '%s'.\n", k); + } + + if (argidx+3 == GetSize(args)) { + const auto &k = args[argidx+1], &v = args[argidx+2]; + if (v == "NULL") { + RuntimeFlags::SetStringVar(k.c_str(), nullptr); + goto check_error; + } + if (v[0] == '"') { + std::string s = v.substr(1, GetSize(v)-2); + RuntimeFlags::SetStringVar(k.c_str(), v.c_str()); + goto check_error; + } + char *endptr; + unsigned long n = strtol(v.c_str(), &endptr, 0); + if (*endptr == 0) { + RuntimeFlags::SetVar(k.c_str(), n); + goto check_error; + } + } + } + cmd_error(args, argidx, "Missing or unsupported mode parameter.\n"); check_error: -- cgit v1.2.3 From f4f5acf396451b88fad99ef947ad733fbea651b6 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 20 Oct 2021 09:07:22 +0200 Subject: genrtlil: Fix displaying debug info in packages Signed-off-by: Kamil Rakoczy --- frontends/ast/genrtlil.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index a68bcd9ee..ed709aa33 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1126,8 +1126,9 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun // everything should have been handled above -> print error if not. default: + AstNode *current_scope_ast = current_ast_mod == nullptr ? current_ast : current_ast_mod; for (auto f : log_files) - current_ast_mod->dumpAst(f, "verilog-ast> "); + current_scope_ast->dumpAst(f, "verilog-ast> "); log_file_error(filename, location.first_line, "Don't know how to detect sign and width for %s node!\n", type2str(type).c_str()); } -- cgit v1.2.3 From 15a35f5584977605e685d2a92126a337a474ae89 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 10 Nov 2021 10:50:44 +0100 Subject: No need to alocate more memory than used --- frontends/verific/verific.cc | 1 - 1 file changed, 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 5a75b52af..47020f105 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1143,7 +1143,6 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se module->memories[memory->name] = memory; int number_of_bits = net->Size(); - number_of_bits = 1 << ceil_log2(number_of_bits); int bits_in_word = number_of_bits; FOREACH_PORTREF_OF_NET(net, si, pr) { if (pr->GetInst()->Type() == OPER_READ_PORT) { -- cgit v1.2.3 From fdb19a5b3a10572b1b84a26306ec5e83a4eff613 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 16 Nov 2021 10:59:54 +0100 Subject: Support parameters using struct as a wiretype (#3050) Signed-off-by: Kamil Rakoczy --- frontends/ast/simplify.cc | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 64d0fe475..777f46bd7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1613,6 +1613,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { // replace with wire representing the packed structure newNode = make_packed_struct(template_node, str); + newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); // add original input/output attribute to resolved wire newNode->is_input = this->is_input; newNode->is_output = this->is_output; @@ -1661,18 +1662,33 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (is_custom_type) { log_assert(children.size() == 2); log_assert(children[1]->type == AST_WIRETYPE); - if (!current_scope.count(children[1]->str)) - log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", children[1]->str.c_str()); - AstNode *resolved_type_node = current_scope.at(children[1]->str); + auto type_name = children[1]->str; + if (!current_scope.count(type_name)) { + log_file_error(filename, location.first_line, "Unknown identifier `%s' used as type name\n", type_name.c_str()); + } + AstNode *resolved_type_node = current_scope.at(type_name); if (resolved_type_node->type != AST_TYPEDEF) - log_file_error(filename, location.first_line, "`%s' does not name a type\n", children[1]->str.c_str()); + log_file_error(filename, location.first_line, "`%s' does not name a type\n", type_name.c_str()); log_assert(resolved_type_node->children.size() == 1); AstNode *template_node = resolved_type_node->children[0]; - delete children[1]; - children.pop_back(); // Ensure typedef itself is fully simplified - while(template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + while (template_node->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) {}; + + if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) { + // replace with wire representing the packed structure + newNode = make_packed_struct(template_node, str); + newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str); + newNode->type = type; + current_scope[str] = this; + // copy param value, it needs to be 1st value + delete children[1]; + children.pop_back(); + newNode->children.insert(newNode->children.begin(), children[0]->clone()); + goto apply_newNode; + } + delete children[1]; + children.pop_back(); if (template_node->type == AST_MEMORY) log_file_error(filename, location.first_line, "unpacked array type `%s' cannot be used for a parameter\n", children[1]->str.c_str()); -- cgit v1.2.3 From 3ebfa3fb84b707bf963973736fb940f32b74304c Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 3 Dec 2021 09:49:05 +0100 Subject: Make sure cell names are unique for wide operators --- frontends/verific/verific.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 47020f105..dccdcb482 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -896,7 +896,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr for (offset = 0; offset < GetSize(sig_acond); offset += width) { for (width = 1; offset+width < GetSize(sig_acond); width++) if (sig_acond[offset] != sig_acond[offset+width]) break; - cell = clocking.addAldff(inst_name, sig_acond[offset], sig_adata.extract(offset, width), + cell = clocking.addAldff(module->uniquify(inst_name), sig_acond[offset], sig_adata.extract(offset, width), sig_d.extract(offset, width), sig_q.extract(offset, width)); import_attributes(cell->attributes, inst); } @@ -922,7 +922,7 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr if (sig_acond[offset] != sig_acond[offset+width]) break; RTLIL::SigSpec sig_set = module->Mux(NEW_ID, RTLIL::SigSpec(0, width), sig_adata.extract(offset, width), sig_acond[offset]); RTLIL::SigSpec sig_clr = module->Mux(NEW_ID, RTLIL::SigSpec(0, width), module->Not(NEW_ID, sig_adata.extract(offset, width)), sig_acond[offset]); - cell = module->addDlatchsr(inst_name, net_map_at(inst->GetControl()), sig_set, sig_clr, + cell = module->addDlatchsr(module->uniquify(inst_name), net_map_at(inst->GetControl()), sig_set, sig_clr, sig_d.extract(offset, width), sig_q.extract(offset, width)); import_attributes(cell->attributes, inst); } -- cgit v1.2.3 From b06f547993818224ded59c555345140199f4595f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 8 Dec 2021 11:50:10 +0100 Subject: If direction NONE use that from first bit --- frontends/verific/verific.cc | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index dccdcb482..0548d9cb1 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1112,6 +1112,13 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se for (int i = portbus->LeftIndex();; i += portbus->IsUp() ? +1 : -1) { if (portbus->ElementAtIndex(i) && portbus->ElementAtIndex(i)->GetNet()) { + if (portbus->GetDir() == DIR_NONE && !wire->port_input && !wire->port_output) { + Port *p = portbus->ElementAtIndex(i); + if (p->GetDir() == DIR_INOUT || p->GetDir() == DIR_IN) + wire->port_input = true; + if (p->GetDir() == DIR_INOUT || p->GetDir() == DIR_OUT) + wire->port_output = true; + } net = portbus->ElementAtIndex(i)->GetNet(); RTLIL::SigBit bit(wire, i - wire->start_offset); if (net_map.count(net) == 0) -- cgit v1.2.3 From 19773d093fe6f9cf8b3f603f6594112550bac301 Mon Sep 17 00:00:00 2001 From: Claire Xen Date: Fri, 10 Dec 2021 14:27:18 +0100 Subject: Update verific.cc Ad-hoc fixes/improvements --- frontends/verific/verific.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 0548d9cb1..2f5e8cb9a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1105,16 +1105,19 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se wire->start_offset = min(portbus->LeftIndex(), portbus->RightIndex()); import_attributes(wire->attributes, portbus, nl); - if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN) + bool portbus_input = portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_IN; + if (portbus_input) wire->port_input = true; if (portbus->GetDir() == DIR_INOUT || portbus->GetDir() == DIR_OUT) wire->port_output = true; for (int i = portbus->LeftIndex();; i += portbus->IsUp() ? +1 : -1) { if (portbus->ElementAtIndex(i) && portbus->ElementAtIndex(i)->GetNet()) { - if (portbus->GetDir() == DIR_NONE && !wire->port_input && !wire->port_output) { + bool bit_input = portbus_input; + if (portbus->GetDir() == DIR_NONE) { Port *p = portbus->ElementAtIndex(i); - if (p->GetDir() == DIR_INOUT || p->GetDir() == DIR_IN) + bit_input = p->GetDir() == DIR_INOUT || p->GetDir() == DIR_IN; + if (bit_input) wire->port_input = true; if (p->GetDir() == DIR_INOUT || p->GetDir() == DIR_OUT) wire->port_output = true; @@ -1123,7 +1126,7 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::se RTLIL::SigBit bit(wire, i - wire->start_offset); if (net_map.count(net) == 0) net_map[net] = bit; - else if (wire->port_input) + else if (bit_input) module->connect(net_map_at(net), bit); else module->connect(bit, net_map_at(net)); -- cgit v1.2.3 From 2da214d72168400b9ea4d0d2f1a90417c1525658 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Fri, 10 Dec 2021 14:52:27 +0100 Subject: Fix verific import of enum values with x and/or z Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index dccdcb482..03640e9aa 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -198,7 +198,7 @@ void VerificImporter::import_attributes(dict &att p = nullptr; else for (auto q = p+2; *q != '\0'; q++) - if (*q != '0' && *q != '1') { + if (*q != '0' && *q != '1' && *q != 'x' && *q != 'z') { p = nullptr; break; } -- cgit v1.2.3 From 313340aed5e7d21a52d67c0a3c2bbc1623e87315 Mon Sep 17 00:00:00 2001 From: Claire Xenia Wolf Date: Mon, 13 Dec 2021 18:20:08 +0100 Subject: Add YOSYS to the implicitly defined verilog macros in verific Signed-off-by: Claire Xenia Wolf --- frontends/verific/verific.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 2c2858514..d5574f95a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2295,7 +2295,7 @@ struct VerificPass : public Pass { log("\n"); log("Additional -D[=] options may be added after the option indicating\n"); log("the language version (and before file names) to set additional verilog defines.\n"); - log("The macros SYNTHESIS and VERIFIC are defined implicitly.\n"); + log("The macros YOSYS, SYNTHESIS, and VERIFIC are defined implicitly.\n"); log("\n"); log("\n"); log(" verific -formal ..\n"); @@ -2713,6 +2713,7 @@ struct VerificPass : public Pass { else log_abort(); + veri_file::DefineMacro("YOSYS"); veri_file::DefineMacro("VERIFIC"); veri_file::DefineMacro(args[argidx] == "-formal" ? "FORMAL" : "SYNTHESIS"); -- cgit v1.2.3 From 4cd2f03e36d09f936d39f8499e26fb0a2bc897f9 Mon Sep 17 00:00:00 2001 From: Thomas Sailer Date: Wed, 25 Aug 2021 21:34:26 +0200 Subject: preprocessor: do not destroy double slash escaped identifiers The preprocessor currently destroys double slash containing escaped identifiers (for example \a//b ). This is due to next_token trying to convert single line comments (//) into /* */ comments. This then leads to an unintuitive error message like this: ERROR: syntax error, unexpected '*' This patch fixes the error by recognizing escaped identifiers and returning them as single token. It also adds a testcase. --- frontends/verilog/preproc.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'frontends') diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 17f567587..883531e78 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -142,6 +142,16 @@ static std::string next_token(bool pass_newline = false) return_char(ch); } } + else if (ch == '\\') + { + while ((ch = next_char()) != 0) { + if (ch < 33 || ch > 126) { + return_char(ch); + break; + } + token += ch; + } + } else if (ch == '/') { if ((ch = next_char()) != 0) { -- cgit v1.2.3 From 7608985d2c6237b869a4774c6b1659282e7473ad Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 15 Dec 2021 18:15:09 -0700 Subject: fix width detection of array querying function in case and case item expressions I also removed the unnecessary shadowing of `width_hint` and `sign_hint` in the corresponding case in `simplify()`. --- frontends/ast/genrtlil.cc | 5 +++++ frontends/ast/simplify.cc | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ed709aa33..1fe74bb72 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1087,6 +1087,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun } break; } + if (str == "\\$size" || str == "\\$bits" || str == "\\$high" || str == "\\$low" || str == "\\$left" || str == "\\$right") { + width_hint = 32; + sign_hint = true; + break; + } if (current_scope.count(str)) { // This width detection is needed for function calls which are diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 777f46bd7..cb47e641a 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1389,8 +1389,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (const_fold && type == AST_CASE) { - int width_hint; - bool sign_hint; detectSignWidth(width_hint, sign_hint); while (children[0]->simplify(const_fold, at_zero, in_lvalue, stage, width_hint, sign_hint, in_param)) { } if (children[0]->type == AST_CONSTANT && children[0]->bits_only_01()) { -- cgit v1.2.3 From 8c509a5659d540dc41f6cc19ee6989fc249f519d Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 30 Dec 2021 00:01:30 -0700 Subject: sv: fix size cast clipping expression width --- frontends/ast/genrtlil.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 1fe74bb72..2788a850f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -932,7 +932,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun if (children.at(0)->type != AST_CONSTANT) log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); children.at(1)->detectSignWidthWorker(width_hint, sign_hint); - width_hint = children.at(0)->bitsAsConst().as_int(); + this_width = children.at(0)->bitsAsConst().as_int(); + width_hint = max(width_hint, this_width); if (width_hint <= 0) log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); break; -- cgit v1.2.3 From 828e85068f8dd52a508e4cbb84deea0e621aa038 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Wed, 5 Jan 2022 23:33:08 -0700 Subject: sv: fix size cast internal expression extension --- frontends/ast/genrtlil.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 2788a850f..4c25287ad 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1531,13 +1531,20 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // changing the size of signal can be done directly using RTLIL::SigSpec case AST_CAST_SIZE: { RTLIL::SigSpec size = children[0]->genRTLIL(); - RTLIL::SigSpec sig = children[1]->genRTLIL(); if (!size.is_fully_const()) log_file_error(filename, location.first_line, "Static cast with non constant expression!\n"); int width = size.as_int(); if (width <= 0) log_file_error(filename, location.first_line, "Static cast with zero or negative size!\n"); - sig.extend_u0(width, sign_hint); + // determine the *signedness* of the expression + int sub_width_hint = -1; + bool sub_sign_hint = true; + children[1]->detectSignWidth(sub_width_hint, sub_sign_hint); + // generate the signal given the *cast's* size and the + // *expression's* signedness + RTLIL::SigSpec sig = children[1]->genWidthRTLIL(width, sub_sign_hint); + // context may effect this node's signedness, but not that of the + // casted expression is_signed = sign_hint; return sig; } -- cgit v1.2.3 From aa35f24290b0d7339860c8c8a6145703425fa154 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Thu, 6 Jan 2022 22:04:00 -0700 Subject: sv: auto add nosync to certain always_comb local vars If a local variable is always assigned before it is used, then adding nosync prevents latches from being needlessly generated. --- frontends/ast/simplify.cc | 127 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'frontends') diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index cb47e641a..18b1e1e11 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -673,6 +673,118 @@ void add_wire_for_ref(const RTLIL::Wire *ref, const std::string &str) current_scope[str] = wire; } +enum class IdentUsage { + NotReferenced, // target variable is neither read or written in the block + Assigned, // target variable is always assigned before use + SyncRequired, // target variable may be used before it has been assigned +}; + +// determines whether a local variable a block is always assigned before it is +// used, meaning the nosync attribute can automatically be added to that +// variable +static IdentUsage always_asgn_before_use(const AstNode *node, const std::string &target) +{ + // This variable has been referenced before it has necessarily been assigned + // a value in this procedure. + if (node->type == AST_IDENTIFIER && node->str == target) + return IdentUsage::SyncRequired; + + // For case statements (which are also used for if/else), we check each + // possible branch. If the variable is assigned in all branches, then it is + // assigned, and a sync isn't required. If it used before assignment in any + // branch, then a sync is required. + if (node->type == AST_CASE) { + bool all_defined = true; + bool any_used = false; + bool has_default = false; + for (const AstNode *child : node->children) { + if (child->type == AST_COND && child->children.at(0)->type == AST_DEFAULT) + has_default = true; + IdentUsage nested = always_asgn_before_use(child, target); + if (nested != IdentUsage::Assigned && child->type == AST_COND) + all_defined = false; + if (nested == IdentUsage::SyncRequired) + any_used = true; + } + if (any_used) + return IdentUsage::SyncRequired; + else if (all_defined && has_default) + return IdentUsage::Assigned; + else + return IdentUsage::NotReferenced; + } + + // Check if this is an assignment to the target variable. For simplicity, we + // don't analyze sub-ranges of the variable. + if (node->type == AST_ASSIGN_EQ) { + const AstNode *ident = node->children.at(0); + if (ident->type == AST_IDENTIFIER && ident->str == target) + return IdentUsage::Assigned; + } + + for (const AstNode *child : node->children) { + IdentUsage nested = always_asgn_before_use(child, target); + if (nested != IdentUsage::NotReferenced) + return nested; + } + return IdentUsage::NotReferenced; +} + +static const std::string auto_nosync_prefix = "\\AutoNosync"; + +// mark a local variable in an always_comb block for automatic nosync +// consideration +static void mark_auto_nosync(AstNode *block, const AstNode *wire) +{ + log_assert(block->type == AST_BLOCK); + log_assert(wire->type == AST_WIRE); + block->attributes[auto_nosync_prefix + wire->str] = AstNode::mkconst_int(1, + false); +} + +// check a procedural block for auto-nosync markings, remove them, and add +// nosync to local variables as necessary +static void check_auto_nosync(AstNode *node) +{ + std::vector attrs_to_drop; + for (const auto& elem : node->attributes) { + // skip attributes that don't begin with the prefix + if (elem.first.compare(0, auto_nosync_prefix.size(), + auto_nosync_prefix.c_str())) + continue; + + // delete and remove the attribute once we're done iterating + attrs_to_drop.push_back(elem.first); + + // find the wire based on the attribute + std::string wire_name = elem.first.substr(auto_nosync_prefix.size()); + auto it = current_scope.find(wire_name); + if (it == current_scope.end()) + continue; + + // analyze the usage of the local variable in this block + IdentUsage ident_usage = always_asgn_before_use(node, wire_name); + if (ident_usage != IdentUsage::Assigned) + continue; + + // mark the wire with `nosync` + AstNode *wire = it->second; + log_assert(wire->type == AST_WIRE); + wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); + } + + // remove the attributes we've "consumed" + for (const RTLIL::IdString &str : attrs_to_drop) { + auto it = node->attributes.find(str); + delete it->second; + node->attributes.erase(it); + } + + // check local variables in any nested blocks + for (AstNode *child : node->children) + check_auto_nosync(child); +} + // convert the AST into a simpler AST that has all parameters substituted by their // values, unrolled for-loops, expanded generate blocks, etc. when this function // is done with an AST it can be converted into RTLIL using genRTLIL(). @@ -980,6 +1092,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } } + + for (AstNode *child : children) + if (child->type == AST_ALWAYS && + child->attributes.count(ID::always_comb)) + check_auto_nosync(child); } // create name resolution entries for all objects with names @@ -2224,6 +2341,16 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { expand_genblock(str + "."); + // if this is an autonamed block is in an always_comb + if (current_always && current_always->attributes.count(ID::always_comb) + && str.at(0) == '$') + // track local variables in this block so we can consider adding + // nosync once the block has been fully elaborated + for (AstNode *child : children) + if (child->type == AST_WIRE && + !child->attributes.count(ID::nosync)) + mark_auto_nosync(this, child); + std::vector new_children; for (size_t i = 0; i < children.size(); i++) if (children[i]->type == AST_WIRE || children[i]->type == AST_MEMORY || children[i]->type == AST_PARAMETER || children[i]->type == AST_LOCALPARAM || children[i]->type == AST_TYPEDEF) { -- cgit v1.2.3 From 0b633b6c2e8c0dc1e2182761777bb5612f0eef23 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 2 Feb 2022 16:16:08 +0100 Subject: Use bmux for NTO1MUX --- frontends/verific/verific.cc | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index d5574f95a..bfd5e311a 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -798,28 +798,14 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr } if (inst->Type() == OPER_NTO1MUX) { - cell = module->addShr(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); + cell = module->addBmux(inst_name, IN2, IN1, net_map_at(inst->GetOutput())); import_attributes(cell->attributes, inst); return true; } if (inst->Type() == OPER_WIDE_NTO1MUX) { - SigSpec data = IN2, out = OUT; - - int wordsize_bits = ceil_log2(GetSize(out)); - int wordsize = 1 << wordsize_bits; - - SigSpec sel = {IN1, SigSpec(State::S0, wordsize_bits)}; - - SigSpec padded_data; - for (int i = 0; i < GetSize(data); i += GetSize(out)) { - SigSpec d = data.extract(i, GetSize(out)); - d.extend_u0(wordsize); - padded_data.append(d); - } - - cell = module->addShr(inst_name, padded_data, sel, out); + cell = module->addBmux(inst_name, IN2, IN1, OUT); import_attributes(cell->attributes, inst); return true; } -- cgit v1.2.3 From 2cef48bf2cb78aaa4b4dd1ea0bc064c8d12e7147 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 9 Feb 2022 09:19:25 +0100 Subject: Add ability to override verilog mode for verific -f command --- frontends/verific/verific.cc | 46 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) (limited to 'frontends') diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index bfd5e311a..17dbed067 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -2296,9 +2296,11 @@ struct VerificPass : public Pass { log("\n"); log("\n"); #endif - log(" verific {-f|-F} \n"); + log(" verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal] \n"); log("\n"); log("Load and execute the specified command file.\n"); + log("Override verilog parsing mode can be set.\n"); + log("The macros YOSYS, SYNTHESIS/FORMAL, and VERIFIC are defined implicitly.\n"); log("\n"); log("Command file parser supports following commands:\n"); log(" +define - defines macro\n"); @@ -2664,11 +2666,51 @@ struct VerificPass : public Pass { if (GetSize(args) > argidx && (args[argidx] == "-f" || args[argidx] == "-F")) { unsigned verilog_mode = veri_file::VERILOG_95; // default recommended by Verific + bool is_formal = false; + const char* filename = nullptr; Verific::veri_file::f_file_flags flags = (args[argidx] == "-f") ? veri_file::F_FILE_NONE : veri_file::F_FILE_CAPITAL; - Array *file_names = veri_file::ProcessFFile(args[++argidx].c_str(), flags, verilog_mode); + for (argidx++; argidx < GetSize(args); argidx++) { + if (args[argidx] == "-vlog95") { + verilog_mode = veri_file::VERILOG_95; + continue; + } else if (args[argidx] == "-vlog2k") { + verilog_mode = veri_file::VERILOG_2K; + continue; + } else if (args[argidx] == "-sv2005") { + verilog_mode = veri_file::SYSTEM_VERILOG_2005; + continue; + } else if (args[argidx] == "-sv2009") { + verilog_mode = veri_file::SYSTEM_VERILOG_2009; + continue; + } else if (args[argidx] == "-sv2012" || args[argidx] == "-sv" || args[argidx] == "-formal") { + verilog_mode = veri_file::SYSTEM_VERILOG; + if (args[argidx] == "-formal") is_formal = true; + continue; + } else if (args[argidx].compare(0, 1, "-") == 0) { + cmd_error(args, argidx, "unknown option"); + goto check_error; + } + + if (!filename) { + filename = args[argidx].c_str(); + continue; + } else { + log_cmd_error("Only one filename can be specified.\n"); + } + } + if (!filename) + log_cmd_error("Filname must be specified.\n"); + + unsigned analysis_mode = verilog_mode; // keep default as provided by user if not defined in file + Array *file_names = veri_file::ProcessFFile(filename, flags, analysis_mode); + if (analysis_mode != verilog_mode) + log_warning("Provided verilog mode differs from one specified in file.\n"); + + veri_file::DefineMacro("YOSYS"); veri_file::DefineMacro("VERIFIC"); + veri_file::DefineMacro(is_formal ? "FORMAL" : "SYNTHESIS"); if (!veri_file::AnalyzeMultipleFiles(file_names, verilog_mode, work.c_str(), veri_file::MFCU)) { verific_error_msg.clear(); -- cgit v1.2.3