From 369bf81a7049c96f62af084bb5007fbf45e36ab4 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 27 Dec 2013 14:20:15 +0100 Subject: [PATCH] Added support for non-const === and !== (for miter circuits) --- backends/verilog/verilog_backend.cc | 14 ++++---- frontends/ast/genrtlil.cc | 4 +-- kernel/celltypes.h | 4 +++ kernel/rtlil.cc | 2 +- kernel/satgen.h | 20 +++++++++--- passes/extract/extract.cc | 2 ++ passes/opt/opt_const.cc | 12 ++++--- passes/proc/proc_arst.cc | 4 +-- techlibs/common/simlib.v | 36 +++++++++++++++++++++ techlibs/common/stdcells.v | 50 +++++++++++++++++++++++++++++ 10 files changed, 128 insertions(+), 20 deletions(-) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index ff41c2e3c..d8160c97b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -506,12 +506,14 @@ bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell) HANDLE_BINOP("$sshl", "<<<") HANDLE_BINOP("$sshr", ">>>") - HANDLE_BINOP("$lt", "<") - HANDLE_BINOP("$le", "<=") - HANDLE_BINOP("$eq", "==") - HANDLE_BINOP("$ne", "!=") - HANDLE_BINOP("$ge", ">=") - HANDLE_BINOP("$gt", ">") + HANDLE_BINOP("$lt", "<") + HANDLE_BINOP("$le", "<=") + HANDLE_BINOP("$eq", "==") + HANDLE_BINOP("$ne", "!=") + HANDLE_BINOP("$eqx", "===") + HANDLE_BINOP("$nex", "!==") + HANDLE_BINOP("$ge", ">=") + HANDLE_BINOP("$gt", ">") HANDLE_BINOP("$add", "+") HANDLE_BINOP("$sub", "-") diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 36ca1432b..1b6fc1d8b 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -1119,8 +1119,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) 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_EQX: type_name = "$eqx"; } + if (0) { case AST_NEX: type_name = "$nex"; } if (0) { case AST_GE: type_name = "$ge"; } if (0) { case AST_GT: type_name = "$gt"; } { diff --git a/kernel/celltypes.h b/kernel/celltypes.h index e59f74d66..29eb490f8 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -78,6 +78,8 @@ struct CellTypes cell_types.insert("$le"); cell_types.insert("$eq"); cell_types.insert("$ne"); + cell_types.insert("$eqx"); + cell_types.insert("$nex"); cell_types.insert("$ge"); cell_types.insert("$gt"); cell_types.insert("$add"); @@ -237,6 +239,8 @@ struct CellTypes HANDLE_CELL_TYPE(le) HANDLE_CELL_TYPE(eq) HANDLE_CELL_TYPE(ne) + HANDLE_CELL_TYPE(eqx) + HANDLE_CELL_TYPE(nex) HANDLE_CELL_TYPE(ge) HANDLE_CELL_TYPE(gt) HANDLE_CELL_TYPE(add) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9dfe196dc..47dc098a4 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -408,7 +408,7 @@ namespace { } if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || - cell->type == "$ge" || cell->type == "$gt") { + cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") { param("\\A_SIGNED"); param("\\B_SIGNED"); port("\\A", param("\\A_WIDTH")); diff --git a/kernel/satgen.h b/kernel/satgen.h index 35e15aa6c..c0807f550 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -451,7 +451,7 @@ struct SatGen return true; } - if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$ge" || cell->type == "$gt") + if (cell->type == "$lt" || cell->type == "$le" || cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex" || cell->type == "$ge" || cell->type == "$gt") { bool is_signed = cell->parameters["\\A_SIGNED"].as_bool() && cell->parameters["\\B_SIGNED"].as_bool(); std::vector a = importDefSigSpec(cell->connections.at("\\A"), timestep); @@ -465,9 +465,9 @@ struct SatGen ez->SET(is_signed ? ez->vec_lt_signed(a, b) : ez->vec_lt_unsigned(a, b), yy.at(0)); if (cell->type == "$le") ez->SET(is_signed ? ez->vec_le_signed(a, b) : ez->vec_le_unsigned(a, b), yy.at(0)); - if (cell->type == "$eq") + if (cell->type == "$eq" || cell->type == "$eqx") ez->SET(ez->vec_eq(a, b), yy.at(0)); - if (cell->type == "$ne") + if (cell->type == "$ne" || cell->type == "$nex") ez->SET(ez->vec_ne(a, b), yy.at(0)); if (cell->type == "$ge") ez->SET(is_signed ? ez->vec_ge_signed(a, b) : ez->vec_ge_unsigned(a, b), yy.at(0)); @@ -476,7 +476,19 @@ struct SatGen for (size_t i = 1; i < y.size(); i++) ez->SET(ez->FALSE, yy.at(i)); - if (model_undef && (cell->type == "$eq" || cell->type == "$ne")) + if (model_undef && (cell->type == "$eqx" || cell->type == "$nex")) + { + std::vector undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); + std::vector undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); + std::vector undef_y = importUndefSigSpec(cell->connections.at("\\Y"), timestep); + yy.at(0) = ez->AND(yy.at(0), ez->vec_eq(undef_a, undef_b)); + + for (size_t i = 0; i < y.size(); i++) + ez->SET(ez->FALSE, undef_y.at(i)); + + ez->assume(ez->vec_eq(y, yy)); + } + else if (model_undef && (cell->type == "$eq" || cell->type == "$ne")) { std::vector undef_a = importUndefSigSpec(cell->connections.at("\\A"), timestep); std::vector undef_b = importUndefSigSpec(cell->connections.at("\\B"), timestep); diff --git a/passes/extract/extract.cc b/passes/extract/extract.cc index 0c639aeda..aa21e573a 100644 --- a/passes/extract/extract.cc +++ b/passes/extract/extract.cc @@ -499,6 +499,8 @@ struct ExtractPass : public Pass { solver.addSwappablePorts("$xnor", "\\A", "\\B"); solver.addSwappablePorts("$eq", "\\A", "\\B"); solver.addSwappablePorts("$ne", "\\A", "\\B"); + solver.addSwappablePorts("$eqx", "\\A", "\\B"); + solver.addSwappablePorts("$nex", "\\A", "\\B"); solver.addSwappablePorts("$add", "\\A", "\\B"); solver.addSwappablePorts("$mul", "\\A", "\\B"); solver.addSwappablePorts("$logic_and", "\\A", "\\B"); diff --git a/passes/opt/opt_const.cc b/passes/opt/opt_const.cc index b7b361e95..30d85588c 100644 --- a/passes/opt/opt_const.cc +++ b/passes/opt/opt_const.cc @@ -144,7 +144,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons #endif } - if (cell->type == "$eq" || cell->type == "$ne") + if (cell->type == "$eq" || cell->type == "$ne" || cell->type == "$eqx" || cell->type == "$nex") { RTLIL::SigSpec a = cell->connections["\\A"]; RTLIL::SigSpec b = cell->connections["\\B"]; @@ -160,10 +160,12 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons assert(a.chunks.size() == b.chunks.size()); for (size_t i = 0; i < a.chunks.size(); i++) { - if (a.chunks[i].wire == NULL && a.chunks[i].data.bits[0] > RTLIL::State::S1) - continue; - if (b.chunks[i].wire == NULL && b.chunks[i].data.bits[0] > RTLIL::State::S1) - continue; + if (cell->type == "$eq" || cell->type == "$ne") { + if (a.chunks[i].wire == NULL && a.chunks[i].data.bits[0] > RTLIL::State::S1) + continue; + if (b.chunks[i].wire == NULL && b.chunks[i].data.bits[0] > RTLIL::State::S1) + continue; + } new_a.append(a.chunks[i]); new_b.append(b.chunks[i]); } diff --git a/passes/proc/proc_arst.cc b/passes/proc/proc_arst.cc index 65dc97bdd..571946573 100644 --- a/passes/proc/proc_arst.cc +++ b/passes/proc/proc_arst.cc @@ -47,7 +47,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp polarity = !polarity; return check_signal(mod, cell->connections["\\A"], ref, polarity); } - if (cell->type == "$eq" && cell->connections["\\Y"] == signal) { + if ((cell->type == "$eq" || cell->type == "$eqx") && cell->connections["\\Y"] == signal) { if (cell->connections["\\A"].is_fully_const()) { if (!cell->connections["\\A"].as_bool()) polarity = !polarity; @@ -59,7 +59,7 @@ static bool check_signal(RTLIL::Module *mod, RTLIL::SigSpec signal, RTLIL::SigSp return check_signal(mod, cell->connections["\\A"], ref, polarity); } } - if (cell->type == "$ne" && cell->connections["\\Y"] == signal) { + if ((cell->type == "$ne" || cell->type == "$nex") && cell->connections["\\Y"] == signal) { if (cell->connections["\\A"].is_fully_const()) { if (cell->connections["\\A"].as_bool()) polarity = !polarity; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index b4440ea8d..034244ca6 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -376,6 +376,42 @@ endmodule // -------------------------------------------------------- +module \$eqx (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +`INPUT_A +`INPUT_B +output [Y_WIDTH-1:0] Y; + +assign Y = A_BUF.val === B_BUF.val; + +endmodule + +// -------------------------------------------------------- + +module \$nex (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 0; +parameter B_WIDTH = 0; +parameter Y_WIDTH = 0; + +`INPUT_A +`INPUT_B +output [Y_WIDTH-1:0] Y; + +assign Y = A_BUF.val !== B_BUF.val; + +endmodule + +// -------------------------------------------------------- + module \$ge (A, B, Y); parameter A_SIGNED = 0; diff --git a/techlibs/common/stdcells.v b/techlibs/common/stdcells.v index ef4b96f71..c7efa240e 100644 --- a/techlibs/common/stdcells.v +++ b/techlibs/common/stdcells.v @@ -572,6 +572,56 @@ endmodule // -------------------------------------------------------- +module \$eqx (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +wire carry, carry_sign; +wire [WIDTH-1:0] A_buf, B_buf; +\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); +\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + +assign Y = ~|(A_buf ^ B_buf); + +endmodule + +// -------------------------------------------------------- + +module \$nex (A, B, Y); + +parameter A_SIGNED = 0; +parameter B_SIGNED = 0; +parameter A_WIDTH = 1; +parameter B_WIDTH = 1; +parameter Y_WIDTH = 1; + +parameter WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; + +input [A_WIDTH-1:0] A; +input [B_WIDTH-1:0] B; +output [Y_WIDTH-1:0] Y; + +wire carry, carry_sign; +wire [WIDTH-1:0] A_buf, B_buf; +\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf)); +\$pos #(.A_SIGNED(A_SIGNED && B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf)); + +assign Y = |(A_buf ^ B_buf); + +endmodule + +// -------------------------------------------------------- + module \$ge (A, B, Y); parameter A_SIGNED = 0; -- 2.30.2