Added $lcu cell type
authorClifford Wolf <clifford@clifford.at>
Mon, 8 Sep 2014 11:28:23 +0000 (13:28 +0200)
committerClifford Wolf <clifford@clifford.at>
Mon, 8 Sep 2014 11:31:04 +0000 (13:31 +0200)
kernel/celltypes.h
kernel/consteval.h
kernel/rtlil.cc
kernel/satgen.h
manual/CHAPTER_CellLib.tex
passes/tests/test_cell.cc
techlibs/common/simlib.v
techlibs/common/techmap.v

index b42cf4e9a4bc8809804d0026255a2e3f7e867939..85c21ef3c470cebc810f1280056a3309b0e9d909 100644 (file)
@@ -105,6 +105,7 @@ struct CellTypes
                for (auto type : std::vector<RTLIL::IdString>({"$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);
 
index 7423f950f92577ea8bfa86de8e615062b3858801..6e507bd515df3a0212bddd22b22139deff47281e 100644 (file)
@@ -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"));
index b5cede8b2314aad1926dc4f46882c3d88af78645..ec4375f2fb7c0e78c363f27a86d5168f0df411d1 100644 (file)
@@ -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")) {
index 4aabe4378a417302012978f351af1fd59fcbb12e..91f8ab40d27e21e3a58ce02b506adb6c933f3dda 100644 (file)
@@ -1012,6 +1012,38 @@ struct SatGen
                        return true;
                }
 
+               if (cell->type == "$lcu")
+               {
+                       std::vector<int> p = importDefSigSpec(cell->getPort("\\P"), timestep);
+                       std::vector<int> g = importDefSigSpec(cell->getPort("\\G"), timestep);
+                       std::vector<int> ci = importDefSigSpec(cell->getPort("\\CI"), timestep);
+                       std::vector<int> co = importDefSigSpec(cell->getPort("\\CO"), timestep);
+
+                       std::vector<int> 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<int> undef_p = importUndefSigSpec(cell->getPort("\\P"), timestep);
+                               std::vector<int> undef_g = importUndefSigSpec(cell->getPort("\\G"), timestep);
+                               std::vector<int> undef_ci = importUndefSigSpec(cell->getPort("\\CI"), timestep);
+                               std::vector<int> 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<int> 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<int> a = importDefSigSpec(cell->getPort("\\A"), timestep);
index 5045960cb4fc9d5fa75b7debfe32dee0b253ec60..64d3633e941fe2f4c92a0ba3d7a53f6a50c9cab0 100644 (file)
@@ -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}
index 72fb74d3a7f71523aac86d8722b39c0a758951f0..1fa90b540075d956810720f3da734504ed1b8598 100644 (file)
@@ -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"] = "*";
 
index c170945ea770110e4acb28a48afa95616c6b128b..1b67f3257abe56f9bddf6d629efeac9b39a86fb6 100644 (file)
@@ -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;
index 05074637643f3f9719c5099fc1385e08128ca29f..491511dbc94582acebbad11916c036254cc8f02f 100644 (file)
@@ -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