From af0c8873bbc13eea10b3d705061b4cf68fe27c17 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 8 Sep 2014 13:28:23 +0200 Subject: Added $lcu cell type --- kernel/celltypes.h | 1 + kernel/consteval.h | 37 +++++++++++++++++++++ kernel/rtlil.cc | 14 ++++++++ kernel/satgen.h | 32 ++++++++++++++++++ manual/CHAPTER_CellLib.tex | 2 +- passes/tests/test_cell.cc | 27 ++++++++++++++- techlibs/common/simlib.v | 23 +++++++++++++ techlibs/common/techmap.v | 82 +++++----------------------------------------- 8 files changed, 142 insertions(+), 76 deletions(-) diff --git a/kernel/celltypes.h b/kernel/celltypes.h index b42cf4e9..85c21ef3 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -105,6 +105,7 @@ struct CellTypes for (auto type : std::vector({"$mux", "$pmux"})) setup_type(type, {"\\A", "\\B", "\\S"}, {"\\Y"}, true); + setup_type("$lcu", {"\\P", "\\G", "\\CI"}, {"\\CO"}, true); setup_type("$alu", {"\\A", "\\B", "\\CI", "\\BI"}, {"\\X", "\\Y", "\\CO"}, true); setup_type("$fa", {"\\A", "\\B", "\\C"}, {"\\X", "\\Y"}, true); diff --git a/kernel/consteval.h b/kernel/consteval.h index 7423f950..6e507bd5 100644 --- a/kernel/consteval.h +++ b/kernel/consteval.h @@ -86,6 +86,43 @@ struct ConstEval bool eval(RTLIL::Cell *cell, RTLIL::SigSpec &undef) { + if (cell->type == "$lcu") + { + RTLIL::SigSpec sig_p = cell->getPort("\\P"); + RTLIL::SigSpec sig_g = cell->getPort("\\G"); + RTLIL::SigSpec sig_ci = cell->getPort("\\CI"); + RTLIL::SigSpec sig_co = values_map(assign_map(cell->getPort("\\CO"))); + + if (sig_co.is_fully_const()) + return true; + + if (!eval(sig_p, undef, cell)) + return false; + + if (!eval(sig_g, undef, cell)) + return false; + + if (!eval(sig_ci, undef, cell)) + return false; + + if (sig_p.is_fully_def() && sig_g.is_fully_def() && sig_ci.is_fully_def()) + { + RTLIL::Const coval(RTLIL::Sx, SIZE(sig_co)); + bool carry = sig_ci.as_bool(); + + for (int i = 0; i < SIZE(coval); i++) { + carry = (sig_g[i] == RTLIL::S1) || (sig_p[i] == RTLIL::S1 && carry); + coval.bits[i] = carry ? RTLIL::S1 : RTLIL::S0; + } + + set(sig_co, coval); + } + else + set(sig_co, RTLIL::Const(RTLIL::Sx, SIZE(sig_co))); + + return true; + } + RTLIL::SigSpec sig_a, sig_b, sig_s, sig_y; log_assert(cell->hasPort("\\Y")); diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b5cede8b..ec4375f2 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -630,6 +630,15 @@ namespace { return; } + if (cell->type == "$lcu") { + port("\\P", param("\\WIDTH")); + port("\\G", param("\\WIDTH")); + port("\\CI", 1); + port("\\CO", param("\\WIDTH")); + check_expected(); + return; + } + if (cell->type == "$alu") { param_bool("\\A_SIGNED"); param_bool("\\B_SIGNED"); @@ -1808,6 +1817,11 @@ void RTLIL::Cell::fixup_parameters(bool set_a_signed, bool set_b_signed) return; } + if (type == "$lcu") { + parameters["\\WIDTH"] = SIZE(connections_["\\CO"]); + return; + } + bool signedness_ab = !type.in("$slice", "$concat", "$macc"); if (connections_.count("\\A")) { diff --git a/kernel/satgen.h b/kernel/satgen.h index 4aabe437..91f8ab40 100644 --- a/kernel/satgen.h +++ b/kernel/satgen.h @@ -1012,6 +1012,38 @@ struct SatGen return true; } + if (cell->type == "$lcu") + { + std::vector p = importDefSigSpec(cell->getPort("\\P"), timestep); + std::vector g = importDefSigSpec(cell->getPort("\\G"), timestep); + std::vector ci = importDefSigSpec(cell->getPort("\\CI"), timestep); + std::vector co = importDefSigSpec(cell->getPort("\\CO"), timestep); + + std::vector yy = model_undef ? ez->vec_var(co.size()) : co; + + for (int i = 0; i < SIZE(co); i++) + ez->SET(yy[i], ez->OR(g[i], ez->AND(p[i], i ? yy[i-1] : ci[0]))); + + if (model_undef) + { + std::vector undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep); + std::vector undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep); + std::vector undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep); + std::vector undef_co = importUndefSigSpec(cell->getPort("\\CO"), timestep); + + int undef_any_p = ez->expression(ezSAT::OpOr, undef_p); + int undef_any_g = ez->expression(ezSAT::OpOr, undef_g); + int undef_any_ci = ez->expression(ezSAT::OpOr, undef_ci); + int undef_co_bit = ez->OR(undef_any_p, undef_any_g, undef_any_ci); + + std::vector undef_co_bits(undef_co.size(), undef_co_bit); + ez->assume(ez->vec_eq(undef_co_bits, undef_co)); + + undefGating(co, yy, undef_co); + } + return true; + } + if (cell->type == "$alu") { std::vector a = importDefSigSpec(cell->getPort("\\A"), timestep); diff --git a/manual/CHAPTER_CellLib.tex b/manual/CHAPTER_CellLib.tex index 5045960c..64d3633e 100644 --- a/manual/CHAPTER_CellLib.tex +++ b/manual/CHAPTER_CellLib.tex @@ -425,7 +425,7 @@ Add information about {\tt \$slice} and {\tt \$concat} cells. \end{fixme} \begin{fixme} -Add information about {\tt \$alu} cells. +Add information about {\tt \$alu}, {\tt \$macc}, {\tt \$fa}, and {\tt \$lcu} cells. \end{fixme} \begin{fixme} diff --git a/passes/tests/test_cell.cc b/passes/tests/test_cell.cc index 72fb74d3..1fa90b54 100644 --- a/passes/tests/test_cell.cc +++ b/passes/tests/test_cell.cc @@ -69,6 +69,30 @@ static void create_gold_module(RTLIL::Design *design, RTLIL::IdString cell_type, cell->setPort("\\Y", wire); } + if (cell_type == "$lcu") + { + int width = 1 + xorshift32(8); + + wire = module->addWire("\\P"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\P", wire); + + wire = module->addWire("\\G"); + wire->width = width; + wire->port_input = true; + cell->setPort("\\G", wire); + + wire = module->addWire("\\CI"); + wire->port_input = true; + cell->setPort("\\CI", wire); + + wire = module->addWire("\\CO"); + wire->width = width; + wire->port_output = true; + cell->setPort("\\CO", wire); + } + if (cell_type == "$macc") { Macc macc; @@ -477,7 +501,7 @@ struct TestCellPass : public Pass { log("\n"); log(" test_cell [options] {cell-types}\n"); log("\n"); - log("Tests the internal implementation of the given cell type (for example '$mux')\n"); + log("Tests the internal implementation of the given cell type (for example '$add')\n"); log("by comparing SAT solver, EVAL and TECHMAP implementations of the cell types..\n"); log("\n"); log("Run with 'all' instead of a cell type to run the test on all supported\n"); @@ -632,6 +656,7 @@ struct TestCellPass : public Pass { cell_types["$lut"] = "*"; cell_types["$alu"] = "ABSY"; + cell_types["$lcu"] = "*"; cell_types["$macc"] = "*"; cell_types["$fa"] = "*"; diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index c170945e..1b67f325 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -459,6 +459,29 @@ endmodule // -------------------------------------------------------- +module \$lcu (P, G, CI, CO); + +parameter WIDTH = 1; + +input [WIDTH-1:0] P, G; +input CI; + +output reg [WIDTH-1:0] CO; + +integer i; +always @* begin + CO = 'bx; + if (^{P, G, CI} !== 1'bx) begin + CO[0] = G[0] || (P[0] && CI); + for (i = 1; i < WIDTH; i = i+1) + CO[i] = G[i] || (P[i] && CO[i-1]); + end +end + +endmodule + +// -------------------------------------------------------- + module \$alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 05074637..491511db 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -258,40 +258,7 @@ module \$fa (A, B, C, X, Y); assign Y = t1 ^ C, X = t2 | t3; endmodule -module \$__alu_ripple (A, B, CI, X, Y, CO); - parameter WIDTH = 1; - - input [WIDTH-1:0] A, B; - output [WIDTH-1:0] X, Y; - - input CI; - output [WIDTH-1:0] CO; - - wire [WIDTH:0] carry; - assign carry[0] = CI; - assign CO = carry[WIDTH:1]; - - genvar i; - generate - for (i = 0; i < WIDTH; i = i+1) - begin:V - // {x, y} = a + b + c - wire a, b, c, x, y; - wire t1, t2, t3; - - \$_AND_ gate1 ( .A(a), .B(b), .Y(t1) ); - \$_XOR_ gate2 ( .A(a), .B(b), .Y(t2) ); - \$_AND_ gate3 ( .A(t2), .B(c), .Y(t3) ); - \$_XOR_ gate4 ( .A(t2), .B(c), .Y(y) ); - \$_OR_ gate5 ( .A(t1), .B(t3), .Y(x) ); - - assign a = A[i], b = B[i], c = carry[i]; - assign carry[i+1] = x, X[i] = t2, Y[i] = y; - end - endgenerate -endmodule - -module \$__lcu (P, G, CI, CO); +module \$lcu (P, G, CI, CO); parameter WIDTH = 2; input [WIDTH-1:0] P, G; @@ -335,37 +302,6 @@ module \$__lcu (P, G, CI, CO); assign CO = g; endmodule -module \$__alu_lookahead (A, B, CI, X, Y, CO); - parameter WIDTH = 1; - - input [WIDTH-1:0] A, B; - output [WIDTH-1:0] X, Y; - - input CI; - output [WIDTH-1:0] CO; - - wire [WIDTH-1:0] P, G; - wire [WIDTH:0] carry; - - genvar i; - generate - for (i = 0; i < WIDTH; i = i+1) - begin:V - wire a, b, c, p, g, y; - - \$_AND_ gate1 ( .A(a), .B(b), .Y(g) ); - \$_XOR_ gate2 ( .A(a), .B(b), .Y(p) ); - \$_XOR_ gate3 ( .A(p), .B(c), .Y(y) ); - - assign a = A[i], b = B[i], c = carry[i]; - assign P[i] = p, G[i] = g, X[i] = p, Y[i] = y; - end - endgenerate - - \$__lcu #(.WIDTH(WIDTH)) lcu (.P(P), .G(G), .CI(CI), .CO(CO)); - assign carry = {CO, CI}; -endmodule - module \$alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; parameter B_SIGNED = 0; @@ -384,15 +320,13 @@ module \$alu (A, B, CI, BI, X, Y, CO); \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); -`ifdef ALU_RIPPLE - \$__alu_ripple #(.WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_buf), .B(BI ? ~B_buf : B_buf), .CI(CI), .X(X), .Y(Y), .CO(CO)); -`else - if (Y_WIDTH <= 4) begin - \$__alu_ripple #(.WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_buf), .B(BI ? ~B_buf : B_buf), .CI(CI), .X(X), .Y(Y), .CO(CO)); - end else begin - \$__alu_lookahead #(.WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A_buf), .B(BI ? ~B_buf : B_buf), .CI(CI), .X(X), .Y(Y), .CO(CO)); - end -`endif + wire [Y_WIDTH-1:0] AA = A_buf; + wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; + + \$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO)); + + assign X = AA ^ BB; + assign Y = X ^ {CO, CI}; endmodule -- cgit v1.2.3