diff options
31 files changed, 1799 insertions, 68 deletions
diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index cc20f17fc..7e24468c0 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -113,6 +113,9 @@ struct EdifBackend : public Backend { log(" -attrprop\n"); log(" create EDIF properties for cell attributes\n"); log("\n"); + log(" -keep\n"); + log(" create extra KEEP nets by allowing a cell to drive multiple nets.\n"); + log("\n"); log(" -pvector {par|bra|ang}\n"); log(" sets the delimiting character for module port rename clauses to\n"); log(" parentheses, square brackets, or angle brackets.\n"); @@ -130,7 +133,7 @@ struct EdifBackend : public Backend { bool port_rename = false; bool attr_properties = false; std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports; - bool nogndvcc = false, gndvccy = false; + bool nogndvcc = false, gndvccy = false, keepmode = false; CellTypes ct(design); EdifNames edif_names; @@ -153,6 +156,10 @@ struct EdifBackend : public Backend { attr_properties = true; continue; } + if (args[argidx] == "-keep") { + keepmode = true; + continue; + } if (args[argidx] == "-pvector" && argidx+1 < args.size()) { std::string parray; port_rename = true; @@ -337,6 +344,71 @@ struct EdifBackend : public Backend { *f << stringf(" (view VIEW_NETLIST\n"); *f << stringf(" (viewType NETLIST)\n"); *f << stringf(" (interface\n"); + + for (auto cell : module->cells()) { + for (auto &conn : cell->connections()) + if (cell->output(conn.first)) + sigmap.add(conn.second); + } + + for (auto wire : module->wires()) + for (auto b1 : SigSpec(wire)) + { + auto b2 = sigmap(b1); + + if (b1 == b2 || !b2.wire) + continue; + + log_assert(b1.wire != nullptr); + + Wire *w1 = b1.wire; + Wire *w2 = b2.wire; + + { + int c1 = w1->get_bool_attribute(ID::keep); + int c2 = w2->get_bool_attribute(ID::keep); + + if (c1 > c2) goto promote; + if (c1 < c2) goto nopromote; + } + + { + int c1 = w1->name[0] == '\\'; + int c2 = w2->name[0] == '\\'; + + if (c1 > c2) goto promote; + if (c1 < c2) goto nopromote; + } + + { + auto count_nontrivial_attr = [](Wire *w) { + int count = w->attributes.size(); + count -= w->attributes.count(ID::src); + count -= w->attributes.count(ID::unused_bits); + return count; + }; + + int c1 = count_nontrivial_attr(w1); + int c2 = count_nontrivial_attr(w2); + + if (c1 > c2) goto promote; + if (c1 < c2) goto nopromote; + } + + { + int c1 = w1->port_id ? INT_MAX - w1->port_id : 0; + int c2 = w2->port_id ? INT_MAX - w2->port_id : 0; + + if (c1 > c2) goto promote; + if (c1 < c2) goto nopromote; + } + + nopromote: + if (0) + promote: + sigmap.add(b1); + } + for (auto wire : module->wires()) { if (wire->port_id == 0) continue; @@ -369,12 +441,15 @@ struct EdifBackend : public Backend { } } } + *f << stringf(" )\n"); *f << stringf(" (contents\n"); + if (!nogndvcc) { *f << stringf(" (instance GND (viewRef VIEW_NETLIST (cellRef GND (libraryRef LIB))))\n"); *f << stringf(" (instance VCC (viewRef VIEW_NETLIST (cellRef VCC (libraryRef LIB))))\n"); } + for (auto cell : module->cells()) { *f << stringf(" (instance %s\n", EDIF_DEF(cell->name)); *f << stringf(" (viewRef VIEW_NETLIST (cellRef %s%s))", EDIF_REF(cell->type), @@ -412,6 +487,7 @@ struct EdifBackend : public Backend { } } } + for (auto &it : net_join_db) { RTLIL::SigBit sig = it.first; if (sig.wire == NULL && sig != RTLIL::State::S0 && sig != RTLIL::State::S1) { @@ -440,7 +516,7 @@ struct EdifBackend : public Backend { } *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); for (auto &ref : it.second) - *f << stringf(" %s\n", ref.first.c_str()); + *f << stringf(" %s\n", ref.first.c_str()); if (sig.wire == NULL) { if (nogndvcc) log_error("Design contains constant nodes (map with \"hilomap\" first).\n"); @@ -455,30 +531,48 @@ struct EdifBackend : public Backend { add_prop(p.first, p.second); *f << stringf("\n )\n"); } - for (auto wire : module->wires()) { + + for (auto wire : module->wires()) + { if (!wire->get_bool_attribute(ID::keep)) continue; - for(int i = 0; i < wire->width; i++) { + + for(int i = 0; i < wire->width; i++) + { SigBit raw_sig = RTLIL::SigSpec(wire, i); SigBit mapped_sig = sigmap(raw_sig); + if (raw_sig == mapped_sig || net_join_db.count(mapped_sig) == 0) continue; + std::string netname = log_signal(raw_sig); for (size_t i = 0; i < netname.size(); i++) if (netname[i] == ' ' || netname[i] == '\\') netname.erase(netname.begin() + i--); - *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); - auto &refs = net_join_db.at(mapped_sig); - for (auto &ref : refs) - if (ref.second) - *f << stringf(" %s\n", ref.first.c_str()); - *f << stringf(" )"); - if (attr_properties && raw_sig.wire != NULL) - for (auto &p : raw_sig.wire->attributes) - add_prop(p.first, p.second); - *f << stringf("\n )\n"); + + if (keepmode) + { + *f << stringf(" (net %s (joined\n", EDIF_DEF(netname)); + + auto &refs = net_join_db.at(mapped_sig); + for (auto &ref : refs) + if (ref.second) + *f << stringf(" %s\n", ref.first.c_str()); + *f << stringf(" )"); + + if (attr_properties && raw_sig.wire != NULL) + for (auto &p : raw_sig.wire->attributes) + add_prop(p.first, p.second); + + *f << stringf("\n )\n"); + } + else + { + log_warning("Ignoring conflicting 'keep' property on net %s. Use -keep to generate the extra net nevertheless.\n", EDIF_DEF(netname)); + } } } + *f << stringf(" )\n"); *f << stringf(" )\n"); *f << stringf(" )\n"); diff --git a/backends/ilang/ilang_backend.cc b/backends/ilang/ilang_backend.cc index 5445fad90..6e3882d2d 100644 --- a/backends/ilang/ilang_backend.cc +++ b/backends/ilang/ilang_backend.cc @@ -290,8 +290,16 @@ void ILANG_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Modu if (!module->avail_parameters.empty()) { if (only_selected) f << stringf("\n"); - for (auto &p : module->avail_parameters) - f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str()); + for (const auto &p : module->avail_parameters) { + const auto &it = module->parameter_default_values.find(p); + if (it == module->parameter_default_values.end()) { + f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str()); + } else { + f << stringf("%s" " parameter %s ", indent.c_str(), p.c_str()); + dump_const(f, it->second); + f << stringf("\n"); + } + } } } diff --git a/backends/json/json.cc b/backends/json/json.cc index 1da23bb7d..1a8b757ef 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -141,6 +141,12 @@ struct JsonWriter write_parameters(module->attributes, /*for_module=*/true); f << stringf("\n },\n"); + if (module->parameter_default_values.size()) { + f << stringf(" \"parameter_default_values\": {"); + write_parameters(module->parameter_default_values, /*for_module=*/true); + f << stringf("\n },\n"); + } + f << stringf(" \"ports\": {"); bool first = true; for (auto n : module->ports) { @@ -310,6 +316,10 @@ struct JsonBackend : public Backend { log(" <attribute_name>: <attribute_value>,\n"); log(" ...\n"); log(" },\n"); + log(" \"parameter_default_values\": {\n"); + log(" <parameter_name>: <parameter_value>,\n"); + log(" ...\n"); + log(" },\n"); log(" \"ports\": {\n"); log(" <port_name>: <port_details>,\n"); log(" ...\n"); diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index de741a506..733556621 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -218,6 +218,7 @@ AstNode::AstNode(AstNodeType type, AstNode *child1, AstNode *child2, AstNode *ch realvalue = 0; id2ast = NULL; basic_prep = false; + lookahead = false; if (child1) children.push_back(child1); @@ -310,6 +311,10 @@ void AstNode::dumpAst(FILE *f, std::string indent) const fprintf(f, " reg"); if (is_signed) fprintf(f, " signed"); + if (basic_prep) + fprintf(f, " basic_prep"); + if (lookahead) + fprintf(f, " lookahead"); if (port_id > 0) fprintf(f, " port=%d", port_id); if (range_valid || range_left != -1 || range_right != 0) @@ -1069,8 +1074,6 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast if (child->type == AST_WIRE && (child->is_input || child->is_output)) { new_children.push_back(child); } else if (child->type == AST_PARAMETER) { - child->delete_children(); - child->children.push_back(AstNode::mkconst_int(0, false, 0)); new_children.push_back(child); } else if (child->type == AST_CELL && child->children.size() > 0 && child->children[0]->type == AST_CELLTYPE && (child->children[0]->str == "$specify2" || child->children[0]->str == "$specify3" || child->children[0]->str == "$specrule")) { diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3dd40238f..3f6329112 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -202,6 +202,9 @@ namespace AST // this is used by simplify to detect if basic analysis has been performed already on the node bool basic_prep; + // this is used for ID references in RHS expressions that should use the "new" value for non-blocking assignments + bool lookahead; + // this is the original sourcecode location that resulted in this AST node // it is automatically set by the constructor using AST::current_filename and // the AST::get_line_num() callback function. @@ -352,6 +355,7 @@ 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; + struct LookaheadRewriter; struct ProcessGenerator; } diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index ab368fdb0..d35335747 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -157,6 +157,126 @@ static RTLIL::SigSpec mux2rtlil(AstNode *that, const RTLIL::SigSpec &cond, const return wire; } +// helper class for rewriting simple lookahead references in AST always blocks +struct AST_INTERNAL::LookaheadRewriter +{ + dict<IdString, pair<AstNode*, AstNode*>> lookaheadids; + + void collect_lookaheadids(AstNode *node) + { + if (node->lookahead) { + log_assert(node->type == AST_IDENTIFIER); + if (!lookaheadids.count(node->str)) { + AstNode *wire = new AstNode(AST_WIRE); + for (auto c : node->id2ast->children) + wire->children.push_back(c->clone()); + wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->is_logic = true; + while (wire->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire); + lookaheadids[node->str] = make_pair(node->id2ast, wire); + wire->genRTLIL(); + } + } + + for (auto child : node->children) + collect_lookaheadids(child); + } + + bool has_lookaheadids(AstNode *node) + { + if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) != 0) + return true; + + for (auto child : node->children) + if (has_lookaheadids(child)) + return true; + + return false; + } + + bool has_nonlookaheadids(AstNode *node) + { + if (node->type == AST_IDENTIFIER && lookaheadids.count(node->str) == 0) + return true; + + for (auto child : node->children) + if (has_nonlookaheadids(child)) + return true; + + return false; + } + + void rewrite_lookaheadids(AstNode *node, bool lhs = false) + { + if (node->type == AST_ASSIGN_LE) + { + if (has_lookaheadids(node->children[0])) + { + if (has_nonlookaheadids(node->children[0])) + log_error("incompatible mix of lookahead and non-lookahead IDs in LHS expression.\n"); + + rewrite_lookaheadids(node->children[0], true); + node->type = AST_ASSIGN_EQ; + } + + rewrite_lookaheadids(node->children[1], lhs); + return; + } + + if (node->type == AST_IDENTIFIER && (node->lookahead || lhs)) { + AstNode *newwire = lookaheadids.at(node->str).second; + node->str = newwire->str; + node->id2ast = newwire; + lhs = false; + } + + for (auto child : node->children) + rewrite_lookaheadids(child, lhs); + } + + LookaheadRewriter(AstNode *top) + { + // top->dumpAst(NULL, "REWRITE-BEFORE> "); + // top->dumpVlog(NULL, "REWRITE-BEFORE> "); + + AstNode *block = nullptr; + + for (auto c : top->children) + if (c->type == AST_BLOCK) { + log_assert(block == nullptr); + block = c; + } + log_assert(block != nullptr); + + collect_lookaheadids(block); + rewrite_lookaheadids(block); + + for (auto it : lookaheadids) + { + AstNode *ref_orig = new AstNode(AST_IDENTIFIER); + ref_orig->str = it.second.first->str; + ref_orig->id2ast = it.second.first; + ref_orig->was_checked = true; + + AstNode *ref_temp = new AstNode(AST_IDENTIFIER); + ref_temp->str = it.second.second->str; + ref_temp->id2ast = it.second.second; + ref_temp->was_checked = true; + + AstNode *init_assign = new AstNode(AST_ASSIGN_EQ, ref_temp->clone(), ref_orig->clone()); + AstNode *final_assign = new AstNode(AST_ASSIGN_LE, ref_orig, ref_temp); + + block->children.insert(block->children.begin(), init_assign); + block->children.push_back(final_assign); + } + + // top->dumpAst(NULL, "REWRITE-AFTER> "); + // top->dumpVlog(NULL, "REWRITE-AFTER> "); + } +}; + // helper class for converting AST always nodes to RTLIL processes struct AST_INTERNAL::ProcessGenerator { @@ -191,6 +311,9 @@ struct AST_INTERNAL::ProcessGenerator ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg) { + // rewrite lookahead references + LookaheadRewriter la_rewriter(always); + // generate process and simple root case proc = new RTLIL::Process; proc->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", always->filename.c_str(), always->location.first_line, always->location.first_column, always->location.last_line, always->location.last_column); @@ -338,7 +461,7 @@ struct AST_INTERNAL::ProcessGenerator return chunks; } - // recursively traverse the AST an collect all assigned signals + // recursively traverse the AST and collect all assigned signals void collect_lvalues(RTLIL::SigSpec ®, AstNode *ast, bool type_eq, bool type_le, bool run_sort_and_unify = true) { switch (ast->type) @@ -892,7 +1015,10 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // remember the parameter, needed for example in techmap case AST_PARAMETER: - current_module->avail_parameters.insert(str); + current_module->avail_parameters(str); + if (GetSize(children) >= 1 && children[0]->type == AST_CONSTANT) { + current_module->parameter_default_values[str] = children[0]->asParaConst(); + } /* fall through */ case AST_LOCALPARAM: if (flag_pwires) @@ -1010,7 +1136,9 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) int add_undef_bits_msb = 0; int add_undef_bits_lsb = 0; - if (id2ast && id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) { + log_assert(id2ast != nullptr); + + if (id2ast->type == AST_AUTOWIRE && current_module->wires_.count(str) == 0) { RTLIL::Wire *wire = current_module->addWire(str); wire->attributes[ID::src] = stringf("%s:%d.%d-%d.%d", filename.c_str(), location.first_line, location.first_column, location.last_line, location.last_column); wire->name = str; @@ -1025,7 +1153,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) chunk = RTLIL::Const(id2ast->children[0]->bits); goto use_const_chunk; } - else if (id2ast && (id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { + else if ((id2ast->type == AST_WIRE || id2ast->type == AST_AUTOWIRE || id2ast->type == AST_MEMORY) && current_module->wires_.count(str) != 0) { RTLIL::Wire *current_wire = current_module->wire(str); if (current_wire->get_bool_attribute(ID::is_interface)) is_interface = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 467afdd87..837c14ad7 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1754,8 +1754,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } // replace dynamic ranges in left-hand side expressions (e.g. "foo[bar] <= 1'b1;") with - // a big case block that selects the correct single-bit assignment. - if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) { + // either a big case block that selects the correct single-bit assignment, or mask and + // shift operations. + if (type == AST_ASSIGN_EQ || type == AST_ASSIGN_LE) + { if (children[0]->type != AST_IDENTIFIER || children[0]->children.size() == 0) goto skip_dynamic_range_lvalue_expansion; if (children[0]->children[0]->range_valid || did_something) @@ -1764,10 +1766,13 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, goto skip_dynamic_range_lvalue_expansion; if (!children[0]->id2ast->range_valid) goto skip_dynamic_range_lvalue_expansion; + int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1; int result_width = 1; + AstNode *shift_expr = NULL; AstNode *range = children[0]->children[0]; + if (range->children.size() == 1) { shift_expr = range->children[0]->clone(); } else { @@ -1780,19 +1785,72 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, 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; } - did_something = true; - newNode = new AstNode(AST_CASE, shift_expr); - for (int i = 0; i < source_width; i++) { - int start_bit = children[0]->id2ast->range_right + i; - AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); + + if (0) + { + // big case block + + did_something = true; + newNode = new AstNode(AST_CASE, shift_expr); + for (int i = 0; i < source_width; i++) { + int start_bit = children[0]->id2ast->range_right + i; + AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); + AstNode *lvalue = children[0]->clone(); + lvalue->delete_children(); + int end_bit = std::min(start_bit+result_width,source_width) - 1; + lvalue->children.push_back(new AstNode(AST_RANGE, + mkconst_int(end_bit, true), mkconst_int(start_bit, true))); + cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); + newNode->children.push_back(cond); + } + } + else + { + // mask and shift operations, disabled for now + + AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); + wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); + wire_mask->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_mask->is_logic = true; + while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire_mask); + + AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); + wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); + wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_data->is_logic = true; + while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } + current_ast_mod->children.push_back(wire_data); + + did_something = true; + newNode = new AstNode(AST_BLOCK); + AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); - int end_bit = std::min(start_bit+result_width,source_width) - 1; - lvalue->children.push_back(new AstNode(AST_RANGE, - mkconst_int(end_bit, true), mkconst_int(start_bit, true))); - cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); - newNode->children.push_back(cond); + + AstNode *ref_mask = new AstNode(AST_IDENTIFIER); + ref_mask->str = wire_mask->str; + ref_mask->id2ast = wire_mask; + ref_mask->was_checked = true; + + AstNode *ref_data = new AstNode(AST_IDENTIFIER); + ref_data->str = wire_data->str; + ref_data->id2ast = wire_data; + ref_data->was_checked = true; + + AstNode *old_data = lvalue->clone(); + if (type == AST_ASSIGN_LE) + old_data->lookahead = true; + + AstNode *shamt = shift_expr; + + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), + new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); + newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), + new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); + newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); } + goto apply_newNode; } skip_dynamic_range_lvalue_expansion:; diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 0522fa72a..8e21fb176 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -143,11 +143,18 @@ module_body: /* empty */; module_stmt: - param_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; + param_stmt | param_defval_stmt | attr_stmt | wire_stmt | memory_stmt | cell_stmt | proc_stmt | conn_stmt; param_stmt: TOK_PARAMETER TOK_ID EOL { - current_module->avail_parameters.insert($2); + current_module->avail_parameters($2); + free($2); + }; + +param_defval_stmt: + TOK_PARAMETER TOK_ID constant EOL { + current_module->avail_parameters($2); + current_module->parameter_default_values[$2] = *$3; free($2); }; diff --git a/kernel/hashlib.h b/kernel/hashlib.h index 996bda38e..97fadea0e 100644 --- a/kernel/hashlib.h +++ b/kernel/hashlib.h @@ -569,7 +569,7 @@ public: return entries[i].udata.second; } - T at(const K &key, const T &defval) const + const T& at(const K &key, const T &defval) const { int hash = do_hash(key); int i = do_lookup(key, hash); @@ -961,7 +961,21 @@ class idict pool<K, OPS> database; public: - typedef typename pool<K, OPS>::const_iterator const_iterator; + class const_iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class idict; + protected: + const idict &container; + int index; + const_iterator(const idict &container, int index) : container(container), index(index) { } + public: + const_iterator() { } + const_iterator operator++() { index++; return *this; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const K &operator*() const { return container[index]; } + const K *operator->() const { return &container[index]; } + }; int operator()(const K &key) { @@ -1019,9 +1033,9 @@ public: bool empty() const { return database.empty(); } void clear() { database.clear(); } - const_iterator begin() const { return database.begin(); } - const_iterator element(int n) const { return database.element(n); } - const_iterator end() const { return database.end(); } + const_iterator begin() const { return const_iterator(*this, offset); } + const_iterator element(int n) const { return const_iterator(*this, n); } + const_iterator end() const { return const_iterator(*this, offset + size()); } }; template<typename K, typename OPS> diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 8af941c85..2aefe30b1 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1389,7 +1389,7 @@ void RTLIL::Module::sort() { wires_.sort(sort_by_id_str()); cells_.sort(sort_by_id_str()); - avail_parameters.sort(sort_by_id_str()); + parameter_default_values.sort(sort_by_id_str()); memories.sort(sort_by_id_str()); processes.sort(sort_by_id_str()); for (auto &it : cells_) @@ -1508,6 +1508,7 @@ void RTLIL::Module::cloneInto(RTLIL::Module *new_mod) const log_assert(new_mod->refcount_cells_ == 0); new_mod->avail_parameters = avail_parameters; + new_mod->parameter_default_values = parameter_default_values; for (auto &conn : connections_) new_mod->connect(conn); @@ -2618,7 +2619,16 @@ void RTLIL::Cell::setParam(RTLIL::IdString paramname, RTLIL::Const value) const RTLIL::Const &RTLIL::Cell::getParam(RTLIL::IdString paramname) const { - return parameters.at(paramname); + static const RTLIL::Const empty; + const auto &it = parameters.find(paramname); + if (it != parameters.end()) + return it->second; + if (module && module->design) { + RTLIL::Module *m = module->design->module(type); + if (m) + return m->parameter_default_values.at(paramname, empty); + } + return empty; } void RTLIL::Cell::sort() diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f3b1c9ae7..11c45bbec 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1091,7 +1091,8 @@ public: std::vector<RTLIL::SigSig> connections_; RTLIL::IdString name; - pool<RTLIL::IdString> avail_parameters; + idict<RTLIL::IdString> avail_parameters; + dict<RTLIL::IdString, RTLIL::Const> parameter_default_values; dict<RTLIL::IdString, RTLIL::Memory*> memories; dict<RTLIL::IdString, RTLIL::Process*> processes; diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index ad6a07fa0..a75927393 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -133,6 +133,7 @@ struct BugpointPass : public Pass { int index = 0; if (modules) { + Module *removed_module = nullptr; for (auto module : design_copy->modules()) { if (module->get_blackbox_attribute()) @@ -141,10 +142,14 @@ struct BugpointPass : public Pass { if (index++ == seed) { log("Trying to remove module %s.\n", module->name.c_str()); - design_copy->remove(module); - return design_copy; + removed_module = module; + break; } } + if (removed_module) { + design_copy->remove(removed_module); + return design_copy; + } } if (ports) { @@ -178,15 +183,20 @@ struct BugpointPass : public Pass { if (mod->get_blackbox_attribute()) continue; + Cell *removed_cell = nullptr; for (auto cell : mod->cells()) { if (index++ == seed) { log("Trying to remove cell %s.%s.\n", mod->name.c_str(), cell->name.c_str()); - mod->remove(cell); - return design_copy; + removed_cell = cell; + break; } } + if (removed_cell) { + mod->remove(removed_cell); + return design_copy; + } } } if (connections) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 3880b19fe..95d74d1eb 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -334,10 +334,16 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a port named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(conn.first)); } - for (auto ¶m : cell->parameters) - if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL) + for (auto ¶m : cell->parameters) { + if (param.first[0] == '$' && '0' <= param.first[1] && param.first[1] <= '9') { + int id = atoi(param.first.c_str()+1); + if (id <= 0 || id > GetSize(mod->avail_parameters)) + log_error("Module `%s' referenced in module `%s' in cell `%s' has only %d parameters, requested parameter %d.\n", + log_id(cell->type), log_id(module), log_id(cell), GetSize(mod->avail_parameters), id); + } else if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL) log_error("Module `%s' referenced in module `%s' in cell `%s' does not have a parameter named '%s'.\n", log_id(cell->type), log_id(module), log_id(cell), log_id(param.first)); + } } } @@ -939,7 +945,8 @@ struct HierarchyPass : public Pass { for (auto mod : design->modules()) for (auto cell : mod->cells()) { - if (design->module(cell->type) == nullptr) + RTLIL::Module *cell_mod = design->module(cell->type); + if (cell_mod == nullptr) continue; for (auto &conn : cell->connections()) if (conn.first[0] == '$' && '0' <= conn.first[1] && conn.first[1] <= '9') { @@ -947,6 +954,23 @@ struct HierarchyPass : public Pass { pos_work.push_back(std::pair<RTLIL::Module*,RTLIL::Cell*>(mod, cell)); break; } + + pool<std::pair<IdString, IdString>> params_rename; + for (const auto &p : cell->parameters) { + if (p.first[0] == '$' && '0' <= p.first[1] && p.first[1] <= '9') { + int id = atoi(p.first.c_str()+1); + if (id <= 0 || id > GetSize(cell_mod->avail_parameters)) { + log(" Failed to map positional parameter %d of cell %s.%s (%s).\n", + id, RTLIL::id2cstr(mod->name), RTLIL::id2cstr(cell->name), RTLIL::id2cstr(cell->type)); + } else { + params_rename.insert(std::make_pair(p.first, cell_mod->avail_parameters[id - 1])); + } + } + } + for (const auto &p : params_rename) { + cell->setParam(p.second, cell->getParam(p.first)); + cell->unsetParam(p.first); + } } for (auto module : pos_mods) diff --git a/techlibs/intel_alm/common/alm_sim.v b/techlibs/intel_alm/common/alm_sim.v index 69768d9f7..979c51132 100644 --- a/techlibs/intel_alm/common/alm_sim.v +++ b/techlibs/intel_alm/common/alm_sim.v @@ -1,3 +1,72 @@ +// The core logic primitive of the Cyclone V/10GX is the Adaptive Logic Module +// (ALM). Each ALM is made up of an 8-input, 2-output look-up table, covered +// in this file, connected to combinational outputs, a carry chain, and four +// D flip-flops (which are covered as MISTRAL_FF in dff_sim.v). +// +// The ALM is vertically symmetric, so I find it helps to think in terms of +// half-ALMs, as that's predominantly the unit that synth_intel_alm uses. +// +// ALMs are quite flexible, having multiple modes. +// +// Normal (combinational) mode +// --------------------------- +// The ALM can implement: +// - a single 6-input function (with the other inputs usable for flip-flop access) +// - two 5-input functions that share two inputs +// - a 5-input and a 4-input function that share one input +// - a 5-input and a 3-or-less-input function that share no inputs +// - two 4-or-less-input functions that share no inputs +// +// Normal-mode functions are represented as MISTRAL_ALUTN cells with N inputs. +// It would be possible to represent a normal mode function as a single cell - +// the vendor cyclone{v,10gx}_lcell_comb cell does exactly that - but I felt +// it was more user-friendly to print out the specific function sizes +// separately. +// +// With the exception of MISTRAL_ALUT6, you can think of two normal-mode cells +// fitting inside a single ALM. +// +// Extended (7-input) mode +// ----------------------- +// The ALM can also fit a 7-input function made of two 5-input functions that +// share four inputs, multiplexed by another input. +// +// Because this can't accept arbitrary 7-input functions, Yosys can't handle +// it, so it doesn't have a cell, but I would likely call it MISTRAL_ALUT7(E?) +// if it did, and it would take up a full ALM. +// +// It might be possible to add an extraction pass to examine all ALUT5 cells +// that feed into ALUT3 cells to see if they can be combined into an extended +// ALM, but I don't think it will be worth it. +// +// Arithmetic mode +// --------------- +// In arithmetic mode, each half-ALM uses its carry chain to perform fast addition +// of two four-input functions that share three inputs. Oddly, the result of +// one of the functions is inverted before being added (you can see this as +// the dot on a full-adder input of Figure 1-8 in the Handbook). +// +// The cell for an arithmetic-mode half-ALM is MISTRAL_ALM_ARITH. One idea +// I've had (or rather was suggested by mwk) is that functions that feed into +// arithmetic-mode cells could be packed directly into the arithmetic-mode +// cell as a function, which reduces the number of ALMs needed. +// +// Shared arithmetic mode +// ---------------------- +// Shared arithmetic mode looks a lot like arithmetic mode, but here the +// output of every other four-input function goes to the input of the adder +// the next bit along. What this means is that adding three bits together can +// be done in an ALM, because functions can be used to implement addition that +// then feeds into the carry chain. This means that three bits can be added per +// ALM, as opposed to two in the arithmetic mode. +// +// Shared arithmetic mode doesn't currently have a cell, but I intend to add +// it as MISTRAL_ALM_SHARED, and have it occupy a full ALM. Because it adds +// three bits per cell, it makes addition shorter and use less ALMs, but +// I don't know enough to tell whether it's more efficient to use shared +// arithmetic mode to shorten the carry chain, or plain arithmetic mode with +// the functions packed in. + `default_nettype none (* abc9_lut=2, lib_whitebox *) diff --git a/techlibs/intel_alm/common/dff_map.v b/techlibs/intel_alm/common/dff_map.v index f7f2fe3c3..962be670c 100644 --- a/techlibs/intel_alm/common/dff_map.v +++ b/techlibs/intel_alm/common/dff_map.v @@ -6,7 +6,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_P_ with INIT=1"); +end else $error("Cannot implement a flip-flop that initialises to one"); endmodule module \$_DFF_N_ (input D, C, output Q); @@ -14,7 +14,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_N_ with INIT=1"); +end else $error("Cannot implement a flip-flop that initialises to one"); endmodule // D flip-flops with reset @@ -23,7 +23,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_PP0_ with INIT=1"); +end else $error("Cannot implement a flip-flop with reset that initialises to one"); endmodule module \$_DFF_PN0_ (input D, C, R, output Q); @@ -31,7 +31,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_PN0_ with INIT=1"); +end else $error("Cannot implement a flip-flop with reset that initialises to one"); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); @@ -39,7 +39,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_NP0_ with INIT=1"); +end else $error("Cannot implement a flip-flop with reset that initialises to one"); endmodule module \$_DFF_NN0_ (input D, C, R, output Q); @@ -47,7 +47,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFF_NN0_ with INIT=1"); +end else $error("Cannot implement a flip-flop with reset that initialises to one"); endmodule // D flip-flops with set @@ -58,7 +58,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin wire Q_tmp; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); assign Q = ~Q_tmp; -end else $error("Unsupported flop: $_DFF_PP1_ with INIT=0"); +end else $error("Cannot implement a flip-flop with set that initialises to zero"); endmodule module \$_DFF_PN1_ (input D, C, R, output Q); @@ -67,7 +67,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; wire Q_tmp; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); -end else $error("Unsupported flop: $_DFF_PN1_ with INIT=0"); +end else $error("Cannot implement a flip-flop with set that initialises to zero"); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); @@ -77,7 +77,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin wire Q_tmp; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(~R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); assign Q = ~Q_tmp; -end else $error("Unsupported flop: $_DFF_NP1_ with INIT=0"); +end else $error("Cannot implement a flip-flop with set that initialises to zero"); endmodule module \$_DFF_NN1_ (input D, C, R, output Q); @@ -87,7 +87,7 @@ if (_TECHMAP_WIREINIT_Q_ !== 1'b0) begin wire Q_tmp; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(~D), .CLK(~C), .ACLR(R), .ENA(1'b1), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q_tmp)); assign Q = ~Q_tmp; -end else $error("Unsupported flop: $_DFF_NN1_ with INIT=0"); +end else $error("Cannot implement a flip-flop with set that initialises to zero"); endmodule // D flip-flops with clock enable @@ -96,7 +96,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFFE_PP_ with INIT=1"); +end else $error("Cannot implement a flip-flop with enable that initialises to one"); endmodule module \$_DFFE_PN_ (input D, C, E, output Q); @@ -104,7 +104,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFFE_PN_ with INIT=1"); +end else $error("Cannot implement a flip-flop with enable that initialises to one"); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); @@ -112,7 +112,7 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFFE_NP_ with INIT=1"); +end else $error("Cannot implement a flip-flop with enable that initialises to one"); endmodule module \$_DFFE_NN_ (input D, C, E, output Q); @@ -120,5 +120,5 @@ parameter _TECHMAP_WIREINIT_Q_ = 1'b0; if (_TECHMAP_WIREINIT_Q_ !== 1'b1) begin wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; MISTRAL_FF _TECHMAP_REPLACE_(.DATAIN(D), .CLK(~C), .ACLR(1'b1), .ENA(~E), .SCLR(1'b0), .SLOAD(1'b0), .SDATA(1'b0), .Q(Q)); -end else $error("Unsupported flop: $_DFFE_NN_ with INIT=1"); +end else $error("Cannot implement a flip-flop with enable that initialises to one"); endmodule diff --git a/techlibs/intel_alm/common/dff_sim.v b/techlibs/intel_alm/common/dff_sim.v index 07865905f..32444dd46 100644 --- a/techlibs/intel_alm/common/dff_sim.v +++ b/techlibs/intel_alm/common/dff_sim.v @@ -1,3 +1,47 @@ +// The four D flip-flops (DFFs) in a Cyclone V/10GX Adaptive Logic Module (ALM) +// act as one-bit memory cells that can be placed very flexibly (wherever there's +// an ALM); each flop is represented by a MISTRAL_FF cell. +// +// The flops in these chips are rather flexible in some ways, but in practice +// quite crippled by FPGA standards. +// +// What the flops can do +// --------------------- +// The core flop acts as a single-bit memory that initialises to zero at chip +// reset. It takes in data on the rising edge of CLK if ENA is high, +// and outputs it to Q. The ENA (clock enable) pin can therefore be used to +// capture the input only if a condition is true. +// +// The data itself is zero if SCLR (synchronous clear) is high, else it comes +// from SDATA (synchronous data) if SLOAD (synchronous load) is high, or DATAIN +// if SLOAD is low. +// +// If ACLR (asynchronous clear) is low then Q is forced to zero, regardless of +// the synchronous inputs or CLK edge. This is most often used for an FPGA-wide +// power-on reset. +// +// An asynchronous set that sets Q to one can be emulated by inverting the input +// and output of the flop, resulting in ACLR forcing Q to zero, which then gets +// inverted to produce one. Likewise, logic can operate on the falling edge of +// CLK if CLK is inverted before being passed as an input. +// +// What the flops *can't* do +// ------------------------- +// The trickiest part of the above capabilities is the lack of configurable +// initialisation state. For example, it isn't possible to implement a flop with +// asynchronous clear that initialises to one, because the hardware initialises +// to zero. Likewise, you can't emulate a flop with asynchronous set that +// initialises to zero, because the inverters mean the flop initialises to one. +// +// If the input design requires one of these cells (which appears to be rare +// in practice) then synth_intel_alm will fail to synthesize the design where +// other Yosys synthesis scripts might succeed. +// +// This stands in notable contrast to e.g. Xilinx flip-flops, which have +// configurable initialisation state and native synchronous/asynchronous +// set/clear (although not at the same time), which means they can generally +// implement a much wider variety of logic. + // DATAIN: synchronous data input // CLK: clock input (positive edge) // ACLR: asynchronous clear (negative-true) diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc index ac9b57fe1..c608db883 100644 --- a/techlibs/xilinx/xilinx_dffopt.cc +++ b/techlibs/xilinx/xilinx_dffopt.cc @@ -209,7 +209,7 @@ lut_sigin_done: continue; LutData lut_d = it_D->second.first; Cell *cell_d = it_D->second.second; - if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) { + if (cell->getParam(ID(IS_D_INVERTED)).as_bool()) { // Flip all bits in the LUT. for (int i = 0; i < GetSize(lut_d.first); i++) lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1; @@ -249,7 +249,7 @@ lut_sigin_done: if (has_s) { SigBit sig_S = sigmap(cell->getPort(ID::S)); LutData lut_s = LutData(Const(2, 2), {sig_S}); - bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool(); + bool inv_s = cell->getParam(ID(IS_S_INVERTED)).as_bool(); auto it_S = bit_to_lut.find(sig_S); if (it_S != bit_to_lut.end()) lut_s = it_S->second.first; @@ -271,7 +271,7 @@ lut_sigin_done: if (has_r) { SigBit sig_R = sigmap(cell->getPort(ID::R)); LutData lut_r = LutData(Const(2, 2), {sig_R}); - bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool(); + bool inv_r = cell->getParam(ID(IS_R_INVERTED)).as_bool(); auto it_R = bit_to_lut.find(sig_R); if (it_R != bit_to_lut.end()) lut_r = it_R->second.first; diff --git a/tests/various/dynamic_part_select.ys b/tests/various/dynamic_part_select.ys new file mode 100644 index 000000000..abc1daad6 --- /dev/null +++ b/tests/various/dynamic_part_select.ys @@ -0,0 +1,106 @@ +### Original testcase ### +read_verilog ./dynamic_part_select/original.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/original_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv + +### Multiple blocking assingments ### +design -reset +read_verilog ./dynamic_part_select/multiple_blocking.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/multiple_blocking_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv + +### Non-blocking to the same output register ### +design -reset +read_verilog ./dynamic_part_select/nonblocking.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/nonblocking_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv + +### For-loop select, one dynamic input +design -reset +read_verilog ./dynamic_part_select/forloop_select.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/forloop_select_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv + +#### Double loop (part-select, reset) ### +design -reset +read_verilog ./dynamic_part_select/reset_test.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/reset_test_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv + +### Reversed part-select case ### +design -reset +read_verilog ./dynamic_part_select/reversed.v +proc +rename -top gold +design -stash gold + +read_verilog ./dynamic_part_select/reversed_gate.v +proc +rename -top gate +design -stash gate + +design -copy-from gold -as gold gold +design -copy-from gate -as gate gate + +miter -equiv -make_assert -make_outcmp -flatten gold gate equiv +sat -prove-asserts -seq 10 -show-public -verify -set-init-zero equiv diff --git a/tests/various/dynamic_part_select/forloop_select.v b/tests/various/dynamic_part_select/forloop_select.v new file mode 100644 index 000000000..8260f3186 --- /dev/null +++ b/tests/various/dynamic_part_select/forloop_select.v @@ -0,0 +1,19 @@ +module forloop_select #(parameter WIDTH=16, SELW=4, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input en, + output reg [WIDTH-1:0] dout); + + reg [SELW:0] sel; + localparam SLICE = WIDTH/(SELW**2); + + always @(posedge clk) + begin + if (en) begin + for (sel = 0; sel <= 4'hf; sel=sel+1'b1) + dout[(ctrl*sel)+:SLICE] <= din; + end + end +endmodule + diff --git a/tests/various/dynamic_part_select/forloop_select_gate.v b/tests/various/dynamic_part_select/forloop_select_gate.v new file mode 100644 index 000000000..71ae88537 --- /dev/null +++ b/tests/various/dynamic_part_select/forloop_select_gate.v @@ -0,0 +1,559 @@ +module forloop_select_gate (clk, ctrl, din, en, dout); + input clk; + input [3:0] ctrl; + input [15:0] din; + input en; + output reg [15:0] dout; + reg [4:0] sel; + always @(posedge clk) + case (|(en)) + 1'b 1: + begin + case (({(ctrl)*(0)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00001)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00010)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00011)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00100)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00101)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00110)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 00111)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01000)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01001)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01010)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01011)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01100)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01101)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01110)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + case (({(ctrl)*(5'b 01111)})+(0)) + 0: + dout[0:0] <= din; + 1: + dout[1:1] <= din; + 2: + dout[2:2] <= din; + 3: + dout[3:3] <= din; + 4: + dout[4:4] <= din; + 5: + dout[5:5] <= din; + 6: + dout[6:6] <= din; + 7: + dout[7:7] <= din; + 8: + dout[8:8] <= din; + 9: + dout[9:9] <= din; + 10: + dout[10:10] <= din; + 11: + dout[11:11] <= din; + 12: + dout[12:12] <= din; + 13: + dout[13:13] <= din; + 14: + dout[14:14] <= din; + 15: + dout[15:15] <= din; + endcase + sel = 5'b 10000; + end + endcase + endmodule diff --git a/tests/various/dynamic_part_select/multiple_blocking.v b/tests/various/dynamic_part_select/multiple_blocking.v new file mode 100644 index 000000000..2858f7741 --- /dev/null +++ b/tests/various/dynamic_part_select/multiple_blocking.v @@ -0,0 +1,19 @@ +module multiple_blocking #(parameter WIDTH=32, SELW=1, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input [SELW-1:0] sel, + output reg [WIDTH-1:0] dout); + + localparam SLICE = WIDTH/(SELW**2); + reg [CTRLW:0] a; + reg [SELW-1:0] b; + reg [DINW:0] c; + always @(posedge clk) begin + a = ctrl + 1; + b = sel - 1; + c = ~din; + dout = dout + 1; + dout[a*b+:SLICE] = c; + end +endmodule diff --git a/tests/various/dynamic_part_select/multiple_blocking_gate.v b/tests/various/dynamic_part_select/multiple_blocking_gate.v new file mode 100644 index 000000000..073b559dc --- /dev/null +++ b/tests/various/dynamic_part_select/multiple_blocking_gate.v @@ -0,0 +1,83 @@ +module multiple_blocking_gate (clk, ctrl, din, sel, dout); + input clk; + input [4:0] ctrl; + input [1:0] din; + input [0:0] sel; + output reg [31:0] dout; + reg [5:0] a; + reg [0:0] b; + reg [2:0] c; + always @(posedge clk) + begin + a = (ctrl)+(1); + b = (sel)-(1); + c = ~(din); + dout = (dout)+(1); + case (({(a)*(b)})+(0)) + 0: + dout[31:0] = c; + 1: + dout[31:1] = c; + 2: + dout[31:2] = c; + 3: + dout[31:3] = c; + 4: + dout[31:4] = c; + 5: + dout[31:5] = c; + 6: + dout[31:6] = c; + 7: + dout[31:7] = c; + 8: + dout[31:8] = c; + 9: + dout[31:9] = c; + 10: + dout[31:10] = c; + 11: + dout[31:11] = c; + 12: + dout[31:12] = c; + 13: + dout[31:13] = c; + 14: + dout[31:14] = c; + 15: + dout[31:15] = c; + 16: + dout[31:16] = c; + 17: + dout[31:17] = c; + 18: + dout[31:18] = c; + 19: + dout[31:19] = c; + 20: + dout[31:20] = c; + 21: + dout[31:21] = c; + 22: + dout[31:22] = c; + 23: + dout[31:23] = c; + 24: + dout[31:24] = c; + 25: + dout[31:25] = c; + 26: + dout[31:26] = c; + 27: + dout[31:27] = c; + 28: + dout[31:28] = c; + 29: + dout[31:29] = c; + 30: + dout[31:30] = c; + 31: + dout[31:31] = c; + endcase + end +endmodule diff --git a/tests/various/dynamic_part_select/nonblocking.v b/tests/various/dynamic_part_select/nonblocking.v new file mode 100644 index 000000000..0949b31a9 --- /dev/null +++ b/tests/various/dynamic_part_select/nonblocking.v @@ -0,0 +1,14 @@ +module nonblocking #(parameter WIDTH=32, SELW=1, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input [SELW-1:0] sel, + output reg [WIDTH-1:0] dout); + + localparam SLICE = WIDTH/(SELW**2); + always @(posedge clk) begin + dout <= dout + 1; + dout[ctrl*sel+:SLICE] <= din ; + end + +endmodule diff --git a/tests/various/dynamic_part_select/nonblocking_gate.v b/tests/various/dynamic_part_select/nonblocking_gate.v new file mode 100644 index 000000000..ed1ee2776 --- /dev/null +++ b/tests/various/dynamic_part_select/nonblocking_gate.v @@ -0,0 +1,77 @@ +module nonblocking_gate (clk, ctrl, din, sel, dout); + input clk; + input [4:0] ctrl; + input [1:0] din; + input [0:0] sel; + output reg [31:0] dout; + always @(posedge clk) + begin + dout <= (dout)+(1); + case (({(ctrl)*(sel)})+(0)) + 0: + dout[31:0] <= din; + 1: + dout[31:1] <= din; + 2: + dout[31:2] <= din; + 3: + dout[31:3] <= din; + 4: + dout[31:4] <= din; + 5: + dout[31:5] <= din; + 6: + dout[31:6] <= din; + 7: + dout[31:7] <= din; + 8: + dout[31:8] <= din; + 9: + dout[31:9] <= din; + 10: + dout[31:10] <= din; + 11: + dout[31:11] <= din; + 12: + dout[31:12] <= din; + 13: + dout[31:13] <= din; + 14: + dout[31:14] <= din; + 15: + dout[31:15] <= din; + 16: + dout[31:16] <= din; + 17: + dout[31:17] <= din; + 18: + dout[31:18] <= din; + 19: + dout[31:19] <= din; + 20: + dout[31:20] <= din; + 21: + dout[31:21] <= din; + 22: + dout[31:22] <= din; + 23: + dout[31:23] <= din; + 24: + dout[31:24] <= din; + 25: + dout[31:25] <= din; + 26: + dout[31:26] <= din; + 27: + dout[31:27] <= din; + 28: + dout[31:28] <= din; + 29: + dout[31:29] <= din; + 30: + dout[31:30] <= din; + 31: + dout[31:31] <= din; + endcase + end +endmodule diff --git a/tests/various/dynamic_part_select/original.v b/tests/various/dynamic_part_select/original.v new file mode 100644 index 000000000..f7dfed1a1 --- /dev/null +++ b/tests/various/dynamic_part_select/original.v @@ -0,0 +1,12 @@ +module original #(parameter WIDTH=32, SELW=1, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input [SELW-1:0] sel, + output reg [WIDTH-1:0] dout); + localparam SLICE = WIDTH/(SELW**2); + always @(posedge clk) + begin + dout[ctrl*sel+:SLICE] <= din ; + end +endmodule diff --git a/tests/various/dynamic_part_select/original_gate.v b/tests/various/dynamic_part_select/original_gate.v new file mode 100644 index 000000000..22093bf63 --- /dev/null +++ b/tests/various/dynamic_part_select/original_gate.v @@ -0,0 +1,74 @@ +module original_gate (clk, ctrl, din, sel, dout); + input clk; + input [4:0] ctrl; + input [1:0] din; + input [0:0] sel; + output reg [31:0] dout; + always @(posedge clk) + case (({(ctrl)*(sel)})+(0)) + 0: + dout[31:0] <= din; + 1: + dout[31:1] <= din; + 2: + dout[31:2] <= din; + 3: + dout[31:3] <= din; + 4: + dout[31:4] <= din; + 5: + dout[31:5] <= din; + 6: + dout[31:6] <= din; + 7: + dout[31:7] <= din; + 8: + dout[31:8] <= din; + 9: + dout[31:9] <= din; + 10: + dout[31:10] <= din; + 11: + dout[31:11] <= din; + 12: + dout[31:12] <= din; + 13: + dout[31:13] <= din; + 14: + dout[31:14] <= din; + 15: + dout[31:15] <= din; + 16: + dout[31:16] <= din; + 17: + dout[31:17] <= din; + 18: + dout[31:18] <= din; + 19: + dout[31:19] <= din; + 20: + dout[31:20] <= din; + 21: + dout[31:21] <= din; + 22: + dout[31:22] <= din; + 23: + dout[31:23] <= din; + 24: + dout[31:24] <= din; + 25: + dout[31:25] <= din; + 26: + dout[31:26] <= din; + 27: + dout[31:27] <= din; + 28: + dout[31:28] <= din; + 29: + dout[31:29] <= din; + 30: + dout[31:30] <= din; + 31: + dout[31:31] <= din; + endcase +endmodule diff --git a/tests/various/dynamic_part_select/reset_test.v b/tests/various/dynamic_part_select/reset_test.v new file mode 100644 index 000000000..29355aafb --- /dev/null +++ b/tests/various/dynamic_part_select/reset_test.v @@ -0,0 +1,23 @@ +module reset_test #(parameter WIDTH=32, SELW=1, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input [SELW-1:0] sel, + output reg [WIDTH-1:0] dout); + + reg [SELW:0] i; + wire [SELW-1:0] rval = {reset, {SELW-1{1'b0}}}; + localparam SLICE = WIDTH/(SELW**2); + // Doing exotic reset. masking 2 LSB bits to 0, 6 MSB bits to 1 for + // whatever reason. + always @(posedge clk) begin + if (reset) begin: reset_mask + for (i = 0; i < {SELW{1'b1}}; i=i+1) begin + dout[i*rval+:SLICE] <= 32'hDEAD; + end + end + //else begin + dout[ctrl*sel+:SLICE] <= din; + //end + end +endmodule diff --git a/tests/various/dynamic_part_select/reset_test_gate.v b/tests/various/dynamic_part_select/reset_test_gate.v new file mode 100644 index 000000000..96dff4135 --- /dev/null +++ b/tests/various/dynamic_part_select/reset_test_gate.v @@ -0,0 +1,151 @@ +module reset_test_gate (clk, ctrl, din, sel, dout); + input clk; + input [4:0] ctrl; + input [1:0] din; + input [0:0] sel; + output reg [31:0] dout; + reg [1:0] i; + wire [0:0] rval; + assign rval = {reset, 1'b0 }; + always @(posedge clk) + begin + case (|(reset)) + 1'b 1: + begin + case (({(0)*(rval)})+(0)) + 0: + dout[31:0] <= 57005; + 1: + dout[31:1] <= 57005; + 2: + dout[31:2] <= 57005; + 3: + dout[31:3] <= 57005; + 4: + dout[31:4] <= 57005; + 5: + dout[31:5] <= 57005; + 6: + dout[31:6] <= 57005; + 7: + dout[31:7] <= 57005; + 8: + dout[31:8] <= 57005; + 9: + dout[31:9] <= 57005; + 10: + dout[31:10] <= 57005; + 11: + dout[31:11] <= 57005; + 12: + dout[31:12] <= 57005; + 13: + dout[31:13] <= 57005; + 14: + dout[31:14] <= 57005; + 15: + dout[31:15] <= 57005; + 16: + dout[31:16] <= 57005; + 17: + dout[31:17] <= 57005; + 18: + dout[31:18] <= 57005; + 19: + dout[31:19] <= 57005; + 20: + dout[31:20] <= 57005; + 21: + dout[31:21] <= 57005; + 22: + dout[31:22] <= 57005; + 23: + dout[31:23] <= 57005; + 24: + dout[31:24] <= 57005; + 25: + dout[31:25] <= 57005; + 26: + dout[31:26] <= 57005; + 27: + dout[31:27] <= 57005; + 28: + dout[31:28] <= 57005; + 29: + dout[31:29] <= 57005; + 30: + dout[31:30] <= 57005; + 31: + dout[31:31] <= 57005; + endcase + i = 1; + end + endcase + case (({(ctrl)*(sel)})+(0)) + 0: + dout[31:0] <= din; + 1: + dout[31:1] <= din; + 2: + dout[31:2] <= din; + 3: + dout[31:3] <= din; + 4: + dout[31:4] <= din; + 5: + dout[31:5] <= din; + 6: + dout[31:6] <= din; + 7: + dout[31:7] <= din; + 8: + dout[31:8] <= din; + 9: + dout[31:9] <= din; + 10: + dout[31:10] <= din; + 11: + dout[31:11] <= din; + 12: + dout[31:12] <= din; + 13: + dout[31:13] <= din; + 14: + dout[31:14] <= din; + 15: + dout[31:15] <= din; + 16: + dout[31:16] <= din; + 17: + dout[31:17] <= din; + 18: + dout[31:18] <= din; + 19: + dout[31:19] <= din; + 20: + dout[31:20] <= din; + 21: + dout[31:21] <= din; + 22: + dout[31:22] <= din; + 23: + dout[31:23] <= din; + 24: + dout[31:24] <= din; + 25: + dout[31:25] <= din; + 26: + dout[31:26] <= din; + 27: + dout[31:27] <= din; + 28: + dout[31:28] <= din; + 29: + dout[31:29] <= din; + 30: + dout[31:30] <= din; + 31: + dout[31:31] <= din; + endcase + end +endmodule diff --git a/tests/various/dynamic_part_select/reversed.v b/tests/various/dynamic_part_select/reversed.v new file mode 100644 index 000000000..8b114ac77 --- /dev/null +++ b/tests/various/dynamic_part_select/reversed.v @@ -0,0 +1,13 @@ +module reversed #(parameter WIDTH=32, SELW=4, CTRLW=$clog2(WIDTH), DINW=2**SELW) + (input clk, + input [CTRLW-1:0] ctrl, + input [DINW-1:0] din, + input [SELW-1:0] sel, + output reg [WIDTH-1:0] dout); + + localparam SLICE = WIDTH/(SELW**2); + always @(posedge clk) begin + dout[(WIDTH-ctrl*sel)-:SLICE] <= din; + end +endmodule + diff --git a/tests/various/dynamic_part_select/reversed_gate.v b/tests/various/dynamic_part_select/reversed_gate.v new file mode 100644 index 000000000..9349d45ee --- /dev/null +++ b/tests/various/dynamic_part_select/reversed_gate.v @@ -0,0 +1,74 @@ +module reversed_gate (clk, ctrl, din, sel, dout); + input clk; + input [4:0] ctrl; + input [15:0] din; + input [3:0] sel; + output reg [31:0] dout; + always @(posedge clk) + case ((({(32)-((ctrl)*(sel))})+(1))-(2)) + 0: + dout[1:0] <= din; + 1: + dout[2:1] <= din; + 2: + dout[3:2] <= din; + 3: + dout[4:3] <= din; + 4: + dout[5:4] <= din; + 5: + dout[6:5] <= din; + 6: + dout[7:6] <= din; + 7: + dout[8:7] <= din; + 8: + dout[9:8] <= din; + 9: + dout[10:9] <= din; + 10: + dout[11:10] <= din; + 11: + dout[12:11] <= din; + 12: + dout[13:12] <= din; + 13: + dout[14:13] <= din; + 14: + dout[15:14] <= din; + 15: + dout[16:15] <= din; + 16: + dout[17:16] <= din; + 17: + dout[18:17] <= din; + 18: + dout[19:18] <= din; + 19: + dout[20:19] <= din; + 20: + dout[21:20] <= din; + 21: + dout[22:21] <= din; + 22: + dout[23:22] <= din; + 23: + dout[24:23] <= din; + 24: + dout[25:24] <= din; + 25: + dout[26:25] <= din; + 26: + dout[27:26] <= din; + 27: + dout[28:27] <= din; + 28: + dout[29:28] <= din; + 29: + dout[30:29] <= din; + 30: + dout[31:30] <= din; + 31: + dout[31:31] <= din; + endcase +endmodule diff --git a/tests/various/hierarchy_param.ys b/tests/various/hierarchy_param.ys new file mode 100644 index 000000000..d703bb713 --- /dev/null +++ b/tests/various/hierarchy_param.ys @@ -0,0 +1,23 @@ +read_verilog <<EOT + +module bb (...); +parameter A = "abc"; +parameter B = 1; +parameter C = 2; +input a; +output b; +endmodule + +module top (...); +input a; +output b; +bb #("def", 3) my_bb (a, b); +endmodule + +EOT + +hierarchy -top top +dump + +select -assert-count 1 t:bb r:A=def %i +select -assert-count 1 t:bb r:B=3 %i |