summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--frontends/ast/genrtlil.cc32
-rw-r--r--frontends/ast/simplify.cc60
-rw-r--r--kernel/celltypes.h1
-rw-r--r--kernel/rtlil.cc7
-rw-r--r--manual/CHAPTER_CellLib.tex4
-rw-r--r--passes/opt/opt_clean.cc2
-rw-r--r--techlibs/common/simlib.v15
7 files changed, 120 insertions, 1 deletions
diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc
index e44b2d36..83a5c750 100644
--- a/frontends/ast/genrtlil.cc
+++ b/frontends/ast/genrtlil.cc
@@ -1276,6 +1276,38 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint)
}
break;
+ // generate $assert cells
+ case AST_ASSERT:
+ {
+ log_assert(children.size() == 2);
+
+ RTLIL::SigSpec check = children[0]->genRTLIL();
+ log_assert(check.width == 1);
+
+ RTLIL::SigSpec en = children[1]->genRTLIL();
+ log_assert(en.width == 1);
+
+ std::stringstream sstr;
+ sstr << "$assert$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+
+ RTLIL::Cell *cell = new RTLIL::Cell;
+ cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum);
+ cell->name = sstr.str();
+ cell->type = "$assert";
+ current_module->cells[cell->name] = cell;
+
+ for (auto &attr : attributes) {
+ if (attr.second->type != AST_CONSTANT)
+ log_error("Attribute `%s' with non-constant value at %s:%d!\n",
+ attr.first.c_str(), filename.c_str(), linenum);
+ cell->attributes[attr.first] = attr.second->asAttrConst();
+ }
+
+ cell->connections["\\A"] = check;
+ cell->connections["\\EN"] = en;
+ }
+ break;
+
// add entries to current_module->connections for assignments (outside of always blocks)
case AST_ASSIGN:
{
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index bc5dec7b..c266800e 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -966,6 +966,66 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
}
skip_dynamic_range_lvalue_expansion:;
+ if (stage > 1 && type == AST_ASSERT && current_block != NULL)
+ {
+ std::stringstream sstr;
+ sstr << "$assert$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
+ std::string id_check = sstr.str() + "_CHECK", id_en = sstr.str() + "_EN";
+
+ AstNode *wire_check = new AstNode(AST_WIRE);
+ wire_check->str = id_check;
+ current_ast_mod->children.push_back(wire_check);
+ current_scope[wire_check->str] = wire_check;
+ while (wire_check->simplify(true, false, false, 1, -1, false)) { }
+
+ AstNode *wire_en = new AstNode(AST_WIRE);
+ wire_en->str = id_en;
+ current_ast_mod->children.push_back(wire_en);
+ current_scope[wire_en->str] = wire_en;
+ while (wire_en->simplify(true, false, false, 1, -1, false)) { }
+
+ std::vector<RTLIL::State> x_bit;
+ x_bit.push_back(RTLIL::State::Sx);
+
+ AstNode *assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_bits(x_bit, false));
+ assign_check->children[0]->str = id_check;
+
+ AstNode *assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(0, false, 1));
+ assign_en->children[0]->str = id_en;
+
+ AstNode *default_signals = new AstNode(AST_BLOCK);
+ default_signals->children.push_back(assign_check);
+ default_signals->children.push_back(assign_en);
+ current_top_block->children.insert(current_top_block->children.begin(), default_signals);
+
+ assign_check = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), new AstNode(AST_REDUCE_BOOL, children[0]->clone()));
+ assign_check->children[0]->str = id_check;
+
+ assign_en = new AstNode(AST_ASSIGN_LE, new AstNode(AST_IDENTIFIER), mkconst_int(1, false, 1));
+ assign_en->children[0]->str = id_en;
+
+ newNode = new AstNode(AST_BLOCK);
+ newNode->children.push_back(assign_check);
+ newNode->children.push_back(assign_en);
+
+ AstNode *assertnode = new AstNode(AST_ASSERT);
+ assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ assertnode->children.push_back(new AstNode(AST_IDENTIFIER));
+ assertnode->children[0]->str = id_check;
+ assertnode->children[1]->str = id_en;
+ assertnode->attributes.swap(attributes);
+ current_ast_mod->children.push_back(assertnode);
+
+ goto apply_newNode;
+ }
+
+ if (stage > 1 && type == AST_ASSERT && children.size() == 1)
+ {
+ children[0] = new AstNode(AST_REDUCE_BOOL, children[0]->clone());
+ children.push_back(mkconst_int(1, false, 1));
+ did_something = true;
+ }
+
// found right-hand side identifier for memory -> replace with memory read port
if (stage > 1 && type == AST_IDENTIFIER && id2ast != NULL && id2ast->type == AST_MEMORY && !in_lvalue &&
children[0]->type == AST_RANGE && children[0]->children.size() == 1) {
diff --git a/kernel/celltypes.h b/kernel/celltypes.h
index 2f311c82..9e63e9d1 100644
--- a/kernel/celltypes.h
+++ b/kernel/celltypes.h
@@ -96,6 +96,7 @@ struct CellTypes
cell_types.insert("$pmux");
cell_types.insert("$safe_pmux");
cell_types.insert("$lut");
+ cell_types.insert("$assert");
}
void setup_internals_mem()
diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc
index 66152573..7638d468 100644
--- a/kernel/rtlil.cc
+++ b/kernel/rtlil.cc
@@ -595,6 +595,13 @@ namespace {
return;
}
+ if (cell->type == "$assert") {
+ port("\\A", 1);
+ port("\\EN", 1);
+ check_expected();
+ return;
+ }
+
if (cell->type == "$_INV_") { check_gate("AY"); return; }
if (cell->type == "$_AND_") { check_gate("ABY"); return; }
if (cell->type == "$_OR_") { check_gate("ABY"); return; }
diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex
index b84e1b30..b848a2b6 100644
--- a/manual/CHAPTER_CellLib.tex
+++ b/manual/CHAPTER_CellLib.tex
@@ -418,3 +418,7 @@ from the gate level logic network can be mapped to physical flip-flop cells from
pass. The combinatorial logic cells can be mapped to physical cells from a Liberty file via ABC \citeweblink{ABC}
using the {\tt abc} pass.
+\begin{fixme}
+Add information about {\tt \$assert} cells.
+\end{fixme}
+
diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc
index 2921c92d..051d8dc6 100644
--- a/passes/opt/opt_clean.cc
+++ b/passes/opt/opt_clean.cc
@@ -47,7 +47,7 @@ static void rmunused_module_cells(RTLIL::Module *module, bool verbose)
wire2driver.insert(sig, cell);
}
}
- if (cell->type == "$memwr" || cell->get_bool_attribute("\\keep"))
+ if (cell->type == "$memwr" || cell->type == "$assert" || cell->get_bool_attribute("\\keep"))
queue.insert(cell);
unused.insert(cell);
}
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 0e041e12..8f354a63 100644
--- a/techlibs/common/simlib.v
+++ b/techlibs/common/simlib.v
@@ -733,6 +733,21 @@ endmodule
// --------------------------------------------------------
+module \$assert (A, EN);
+
+input A, EN;
+
+always @* begin
+ if (A !== 1'b1 && EN === 1'b1) begin
+ $display("Assertation failed!");
+ $finish;
+ end
+end
+
+endmodule
+
+// --------------------------------------------------------
+
module \$sr (SET, CLR, Q);
parameter WIDTH = 0;