aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--backends/edif/edif.cc122
-rw-r--r--backends/ilang/ilang_backend.cc12
-rw-r--r--backends/json/json.cc10
-rw-r--r--frontends/ast/ast.cc7
-rw-r--r--frontends/ast/ast.h4
-rw-r--r--frontends/ast/genrtlil.cc136
-rw-r--r--frontends/ast/simplify.cc82
-rw-r--r--frontends/ilang/ilang_parser.y11
-rw-r--r--kernel/hashlib.h24
-rw-r--r--kernel/rtlil.cc14
-rw-r--r--kernel/rtlil.h3
-rw-r--r--passes/cmds/bugpoint.cc18
-rw-r--r--passes/hierarchy/hierarchy.cc30
-rw-r--r--techlibs/intel_alm/common/alm_sim.v69
-rw-r--r--techlibs/intel_alm/common/dff_map.v28
-rw-r--r--techlibs/intel_alm/common/dff_sim.v44
-rw-r--r--techlibs/xilinx/xilinx_dffopt.cc6
-rw-r--r--tests/various/dynamic_part_select.ys106
-rw-r--r--tests/various/dynamic_part_select/forloop_select.v19
-rw-r--r--tests/various/dynamic_part_select/forloop_select_gate.v559
-rw-r--r--tests/various/dynamic_part_select/multiple_blocking.v19
-rw-r--r--tests/various/dynamic_part_select/multiple_blocking_gate.v83
-rw-r--r--tests/various/dynamic_part_select/nonblocking.v14
-rw-r--r--tests/various/dynamic_part_select/nonblocking_gate.v77
-rw-r--r--tests/various/dynamic_part_select/original.v12
-rw-r--r--tests/various/dynamic_part_select/original_gate.v74
-rw-r--r--tests/various/dynamic_part_select/reset_test.v23
-rw-r--r--tests/various/dynamic_part_select/reset_test_gate.v151
-rw-r--r--tests/various/dynamic_part_select/reversed.v13
-rw-r--r--tests/various/dynamic_part_select/reversed_gate.v74
-rw-r--r--tests/various/hierarchy_param.ys23
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 &reg, 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 &param : cell->parameters)
- if (mod->avail_parameters.count(param.first) == 0 && param.first[0] != '$' && strchr(param.first.c_str(), '.') == NULL)
+ for (auto &param : 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