From ecc30255ba70910777a4586f5bd6abc818073293 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 27 Dec 2013 13:50:08 +0100 Subject: [PATCH] Added proper === and !== support in constant expressions --- frontends/ast/ast.cc | 4 ++++ frontends/ast/ast.h | 2 ++ frontends/ast/genrtlil.cc | 16 ++++++++++------ frontends/ast/simplify.cc | 16 ++++++++++------ frontends/verilog/lexer.l | 4 ++-- frontends/verilog/parser.y | 10 +++++++++- kernel/calc.cc | 29 +++++++++++++++++++++++++++++ kernel/rtlil.h | 2 ++ tests/simple/undef_eqx_nex.v | 11 +++++++++++ 9 files changed, 79 insertions(+), 15 deletions(-) create mode 100644 tests/simple/undef_eqx_nex.v diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 0e65f1cb7..201584885 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -103,6 +103,8 @@ std::string AST::type2str(AstNodeType type) X(AST_LE) X(AST_EQ) X(AST_NE) + X(AST_EQX) + X(AST_NEX) X(AST_GE) X(AST_GT) X(AST_ADD) @@ -539,6 +541,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) if (0) { case AST_LE: txt = "<="; } if (0) { case AST_EQ: txt = "=="; } if (0) { case AST_NE: txt = "!="; } + if (0) { case AST_EQX: txt = "==="; } + if (0) { case AST_NEX: txt = "!=="; } if (0) { case AST_GE: txt = ">="; } if (0) { case AST_GT: txt = ">"; } if (0) { case AST_ADD: txt = "+"; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index f8e279274..22853d0f9 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -82,6 +82,8 @@ namespace AST AST_LE, AST_EQ, AST_NE, + AST_EQX, + AST_NEX, AST_GE, AST_GT, AST_ADD, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 269752df5..36ca1432b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -728,6 +728,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint) case AST_LE: case AST_EQ: case AST_NE: + case AST_EQX: + case AST_NEX: case AST_GE: case AST_GT: width_hint = std::max(width_hint, 1); @@ -1113,12 +1115,14 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) } // generate cells for binary operations: $lt, $le, $eq, $ne, $ge, $gt - if (0) { case AST_LT: type_name = "$lt"; } - if (0) { case AST_LE: type_name = "$le"; } - if (0) { case AST_EQ: type_name = "$eq"; } - if (0) { case AST_NE: type_name = "$ne"; } - if (0) { case AST_GE: type_name = "$ge"; } - if (0) { case AST_GT: type_name = "$gt"; } + if (0) { case AST_LT: type_name = "$lt"; } + if (0) { case AST_LE: type_name = "$le"; } + if (0) { case AST_EQ: type_name = "$eq"; } + if (0) { case AST_NE: type_name = "$ne"; } + if (0) { case AST_EQX: type_name = "$eq"; } + if (0) { case AST_NEX: type_name = "$ne"; } + if (0) { case AST_GE: type_name = "$ge"; } + if (0) { case AST_GT: type_name = "$gt"; } { int width = std::max(width_hint, 1); width_hint = -1, sign_hint = true; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index f6df0c170..982d1ae35 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -299,6 +299,8 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_LE: case AST_EQ: case AST_NE: + case AST_EQX: + case AST_NEX: case AST_GE: case AST_GT: width_hint = -1; @@ -1258,12 +1260,14 @@ skip_dynamic_range_lvalue_expansion:; newNode = mkconst_bits(y.bits, sign_hint); } break; - if (0) { case AST_LT: const_func = RTLIL::const_lt; } - if (0) { case AST_LE: const_func = RTLIL::const_le; } - if (0) { case AST_EQ: const_func = RTLIL::const_eq; } - if (0) { case AST_NE: const_func = RTLIL::const_ne; } - if (0) { case AST_GE: const_func = RTLIL::const_ge; } - if (0) { case AST_GT: const_func = RTLIL::const_gt; } + if (0) { case AST_LT: const_func = RTLIL::const_lt; } + if (0) { case AST_LE: const_func = RTLIL::const_le; } + if (0) { case AST_EQ: const_func = RTLIL::const_eq; } + if (0) { case AST_NE: const_func = RTLIL::const_ne; } + if (0) { case AST_EQX: const_func = RTLIL::const_eqx; } + if (0) { case AST_NEX: const_func = RTLIL::const_nex; } + if (0) { case AST_GE: const_func = RTLIL::const_ge; } + if (0) { case AST_GT: const_func = RTLIL::const_gt; } if (children[0]->type == AST_CONSTANT && children[1]->type == AST_CONSTANT) { int cmp_width = std::max(children[0]->bits.size(), children[1]->bits.size()); bool cmp_signed = children[0]->is_signed && children[1]->is_signed; diff --git a/frontends/verilog/lexer.l b/frontends/verilog/lexer.l index a0deb755b..9e606d90f 100644 --- a/frontends/verilog/lexer.l +++ b/frontends/verilog/lexer.l @@ -232,8 +232,8 @@ supply1 { return TOK_SUPPLY1; } "<=" { return OP_LE; } ">=" { return OP_GE; } -"===" { return OP_EQ; } -"!==" { return OP_NE; } +"===" { return OP_EQX; } +"!==" { return OP_NEX; } "~&" { return OP_NAND; } "~|" { return OP_NOR; } diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y index f47d1785c..874482d6e 100644 --- a/frontends/verilog/parser.y +++ b/frontends/verilog/parser.y @@ -117,7 +117,7 @@ static void free_attr(std::map *al) %left '|' OP_NOR %left '^' OP_XNOR %left '&' OP_NAND -%left OP_EQ OP_NE +%left OP_EQ OP_NE OP_EQX OP_NEX %left '<' OP_LE OP_GE '>' %left OP_SHL OP_SHR OP_SSHL OP_SSHR %left '+' '-' @@ -1161,6 +1161,14 @@ basic_expr: $$ = new AstNode(AST_NE, $1, $4); append_attr($$, $3); } | + basic_expr OP_EQX attr basic_expr { + $$ = new AstNode(AST_EQX, $1, $4); + append_attr($$, $3); + } | + basic_expr OP_NEX attr basic_expr { + $$ = new AstNode(AST_NEX, $1, $4); + append_attr($$, $3); + } | basic_expr OP_GE attr basic_expr { $$ = new AstNode(AST_GE, $1, $4); append_attr($$, $3); diff --git a/kernel/calc.cc b/kernel/calc.cc index 61025104d..fc978c11a 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -386,6 +386,35 @@ RTLIL::Const RTLIL::const_ne(const RTLIL::Const &arg1, const RTLIL::Const &arg2, return result; } +RTLIL::Const RTLIL::const_eqx(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + RTLIL::Const arg1_ext = arg1; + RTLIL::Const arg2_ext = arg2; + RTLIL::Const result(RTLIL::State::S0, result_len); + + int width = std::max(arg1_ext.bits.size(), arg2_ext.bits.size()); + extend_u0(arg1_ext, width, signed1 && signed2); + extend_u0(arg2_ext, width, signed1 && signed2); + + for (size_t i = 0; i < arg1_ext.bits.size(); i++) { + if (arg1_ext.bits.at(i) != arg2_ext.bits.at(i)) + return result; + } + + result.bits.front() = RTLIL::State::S1; + return result; +} + +RTLIL::Const RTLIL::const_nex(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) +{ + RTLIL::Const result = RTLIL::const_eqx(arg1, arg2, signed1, signed2, result_len); + if (result.bits.front() == RTLIL::State::S0) + result.bits.front() = RTLIL::State::S1; + else if (result.bits.front() == RTLIL::State::S1) + result.bits.front() = RTLIL::State::S0; + return result; +} + RTLIL::Const RTLIL::const_ge(const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len) { int undef_bit_pos = -1; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index fbdab53eb..91dd9d44c 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -174,6 +174,8 @@ namespace RTLIL RTLIL::Const const_le (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_eq (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_ne (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_eqx (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); + RTLIL::Const const_nex (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_ge (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); RTLIL::Const const_gt (const RTLIL::Const &arg1, const RTLIL::Const &arg2, bool signed1, bool signed2, int result_len); diff --git a/tests/simple/undef_eqx_nex.v b/tests/simple/undef_eqx_nex.v new file mode 100644 index 000000000..63912a2fa --- /dev/null +++ b/tests/simple/undef_eqx_nex.v @@ -0,0 +1,11 @@ +module test(y); +output [7:0] y; +assign y[0] = 0/0; +assign y[1] = 0/1; +assign y[2] = 0/0 == 32'bx; +assign y[3] = 0/0 != 32'bx; +assign y[4] = 0/0 === 32'bx; +assign y[5] = 0/0 !== 32'bx; +assign y[6] = 0/1 === 32'bx; +assign y[7] = 0/1 !== 32'bx; +endmodule -- 2.30.2