Added $assert cell
authorClifford Wolf <clifford@clifford.at>
Sun, 19 Jan 2014 13:03:40 +0000 (14:03 +0100)
committerClifford Wolf <clifford@clifford.at>
Sun, 19 Jan 2014 13:03:40 +0000 (14:03 +0100)
frontends/ast/genrtlil.cc
frontends/ast/simplify.cc
kernel/celltypes.h
kernel/rtlil.cc
manual/CHAPTER_CellLib.tex
passes/opt/opt_clean.cc
techlibs/common/simlib.v

index e44b2d361e1079853cacd1d8ffb18bd38e330369..83a5c7506e806ede363c29f49af4f5b2a245ba05 100644 (file)
@@ -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:
                {
index bc5dec7b982c5ee57ab6a2a2ea63c030f47dad79..c266800e934eabb7b060afb31291b78d159b6221 100644 (file)
@@ -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) {
index 2f311c82697eee4c6e569a7bbd586515fd48726b..9e63e9d1bfe848169e7b8a9e86068f51ef9c16ac 100644 (file)
@@ -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()
index 661525735ead1ae3e567ca8d2b6d5f417c319ec8..7638d4689f8bdf49c0790c2ba27c52501900abe0 100644 (file)
@@ -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; }
index b84e1b30e26c45f34624849029e074cf8d3ddb13..b848a2b60a46cc0539cff3ea7cb6683c31ae77d8 100644 (file)
@@ -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}
+
index 2921c92d86b6d423fb38f56b6fb3dd0d763f47f2..051d8dc684d07270409581af6d30686ab5584feb 100644 (file)
@@ -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);
        }
index 0e041e12eeab5802b1cbf136d47eb5ae843088ce..8f354a63d19edb0d8b018756dd7ccbaac234f053 100644 (file)
@@ -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;