diff options
Diffstat (limited to 'frontends')
-rw-r--r-- | frontends/ast/ast.cc | 1 | ||||
-rw-r--r-- | frontends/ast/ast.h | 1 | ||||
-rw-r--r-- | frontends/ast/genrtlil.cc | 32 | ||||
-rw-r--r-- | frontends/ast/simplify.cc | 60 | ||||
-rw-r--r-- | frontends/verilog/lexer.l | 2 | ||||
-rw-r--r-- | frontends/verilog/parser.y | 11 | ||||
-rw-r--r-- | frontends/verilog/preproc.cc | 2 |
7 files changed, 105 insertions, 4 deletions
diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 201584885..ecc58cf63 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -80,6 +80,7 @@ std::string AST::type2str(AstNodeType type) X(AST_CELLTYPE) X(AST_IDENTIFIER) X(AST_PREFIX) + X(AST_ASSERT) X(AST_FCALL) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 22853d0f9..6aaa90e86 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -58,6 +58,7 @@ namespace AST AST_CELLTYPE, AST_IDENTIFIER, AST_PREFIX, + AST_ASSERT, AST_FCALL, AST_TO_SIGNED, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index e44b2d361..83a5c7506 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 bc5dec7b9..c266800e9 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/frontends/verilog/lexer.l b/frontends/verilog/lexer.l index 9e606d90f..81167cf4e 100644 --- a/frontends/verilog/lexer.l +++ b/frontends/verilog/lexer.l @@ -113,6 +113,8 @@ namespace VERILOG_FRONTEND { "generate" { return TOK_GENERATE; } "endgenerate" { return TOK_ENDGENERATE; } +"assert"([ \t\r\n]+"property")? { return TOK_ASSERT; } + "input" { return TOK_INPUT; } "output" { return TOK_OUTPUT; } "inout" { return TOK_INOUT; } diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y index 874482d6e..b0c4db8ae 100644 --- a/frontends/verilog/parser.y +++ b/frontends/verilog/parser.y @@ -104,7 +104,7 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT %type <ast> wire_type range non_opt_range expr basic_expr concat_list rvalue lvalue lvalue_concat_list %type <string> opt_label tok_prim_wrapper hierarchical_id @@ -366,7 +366,7 @@ module_body: module_body_stmt: task_func_decl | param_decl | localparam_decl | defparam_decl | wire_decl | assign_stmt | cell_stmt | - always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr; + always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert; task_func_decl: TOK_TASK TOK_ID ';' { @@ -748,6 +748,11 @@ opt_label: $$ = NULL; }; +assert: + TOK_ASSERT '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSERT, $3)); + }; + simple_behavioral_stmt: lvalue '=' expr { AstNode *node = new AstNode(AST_ASSIGN_EQ, $1, $3); @@ -760,7 +765,7 @@ simple_behavioral_stmt: // this production creates the obligatory if-else shift/reduce conflict behavioral_stmt: - defattr | wire_decl | + defattr | assert | wire_decl | simple_behavioral_stmt ';' | hierarchical_id attr { AstNode *node = new AstNode(AST_TCALL); diff --git a/frontends/verilog/preproc.cc b/frontends/verilog/preproc.cc index 5cfa0f24b..db53e8c68 100644 --- a/frontends/verilog/preproc.cc +++ b/frontends/verilog/preproc.cc @@ -386,7 +386,7 @@ std::string frontend_verilog_preproc(FILE *f, std::string filename, const std::m std::string name = tok.substr(1); // printf("expand: >>%s<< -> >>%s<<\n", name.c_str(), defines_map[name].c_str()); std::string skipped_spaces = skip_spaces(); - tok = next_token(true); + tok = next_token(false); if (tok == "(" && defines_with_args.count(name) > 0) { int level = 1; std::vector<std::string> args; |