From 1e67099b77904802880ad7c53d2cac33c6df456f Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 19 Jan 2014 14:03:40 +0100 Subject: Added $assert cell --- frontends/ast/genrtlil.cc | 32 +++++++++++++++++++++++++ frontends/ast/simplify.cc | 60 ++++++++++++++++++++++++++++++++++++++++++++++ kernel/celltypes.h | 1 + kernel/rtlil.cc | 7 ++++++ manual/CHAPTER_CellLib.tex | 4 ++++ passes/opt/opt_clean.cc | 2 +- techlibs/common/simlib.v | 15 ++++++++++++ 7 files changed, 120 insertions(+), 1 deletion(-) 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 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; -- cgit v1.2.3