Refactor +/cmp2lcu.v into recursive techmap
authorEddie Hung <eddie@fpgeh.com>
Tue, 21 Jan 2020 00:42:08 +0000 (16:42 -0800)
committerEddie Hung <eddie@fpgeh.com>
Fri, 3 Apr 2020 21:28:22 +0000 (14:28 -0700)
techlibs/common/cmp2lcu.v
tests/techmap/cmp2lcu.ys

index d427a4cd3d56efd0052f95757d327f2e430e3318..524bd443756eb623d803880a0ad74a80b6f68ff0 100644 (file)
@@ -29,52 +29,79 @@ generate
         // Transform $le into $ge by swapping A and B
         $ge #(.A_SIGNED(B_SIGNED), .B_SIGNED(A_SIGNED), .A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(B), .B(A), .Y(Y));
     end
-    else if (A_WIDTH != B_WIDTH) begin
+    else begin
         // Perform sign extension on A and B
         localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
         wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A};
         wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B};
-        if (_TECHMAP_CELLTYPE_ == "$gt")
-            $gt #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(WIDTH), .B_WIDTH(WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(AA), .B(BB), .Y(Y));
-        else if (_TECHMAP_CELLTYPE_ == "$ge")
-            $ge #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(WIDTH), .B_WIDTH(WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(AA), .B(BB), .Y(Y));
-        else
-            wire _TECHMAP_FAIL_ = 1;
-    end
-    else begin
-        localparam cmp_width = `LUT_WIDTH/2;
-        localparam lcu_width = (A_WIDTH+cmp_width-1)/cmp_width;
-        wire [lcu_width-1:0] P, G, CO;
-        genvar i, j;
-        for (i = 0; i < A_WIDTH; i=i+cmp_width) begin
-            wire [cmp_width-1:0] PP, GG;
-            for (j = cmp_width-1; j >= 0 && i+j < A_WIDTH; j = j-1) begin
-                // Bit-wise equality (xnor) of sign-extended A and B
-                assign PP[j] = A[i+j] ^~ B[i+j];
-                if (i+j == A_WIDTH-1 && A_SIGNED && B_SIGNED)
-                    assign GG[j] = ~A[i+j] & B[i+j];
-                else if (j == cmp_width-1)
-                    assign GG[j] = A[i+j] & ~B[i+j];
-                else
-                    // Priority "encoder" that checks A[i] == 1'b1 && B[i] == 1'b0
-                    //   from MSB down, deferring to less significant bits if the
-                    //   MSBs are equal
-                    assign GG[j] = &PP[cmp_width-1:j+1] & (A[i+j] & ~B[i+j]);
-            end
-            // Propagate only if all bit pairs are equal
-            //   (inconclusive evidence to say A >= B)
-            assign P[i/cmp_width] = &PP;
-            // Generate if any bit pairs call for it
-            assign G[i/cmp_width] = |GG;
-        end
         // For $ge operation, start with the assumption that A and B are
         //   equal (propagating this equality if A and B turn out to be so)
         if (_TECHMAP_CELLTYPE_ == "$ge")
-            wire CI = 1'b1;
+            localparam CI = 1'b1;
         else
-            wire CI = 1'b0;
-        $lcu #(.WIDTH(lcu_width)) lcu (.P(P), .G(G), .CI(CI), .CO(CO));
-        assign Y = CO[lcu_width-1];
+            localparam CI = 1'b0;
+        $__CMP2LCU #(.AB_WIDTH(WIDTH), .AB_SIGNED(A_SIGNED && B_SIGNED), .LCU_WIDTH(0), .BUDGET(`LUT_WIDTH), .CI(CI))
+            _TECHMAP_REPLACE_ (.A(AA), .B(BB), .P(), .G(), .PP(1'b1), .GG(1'b0), .Y(Y));
+    end
+endgenerate
+endmodule
+
+module $__CMP2LCU (A, B, P, G, PP, GG, Y);
+
+parameter AB_WIDTH = 0;
+parameter AB_SIGNED = 0;
+parameter LCU_WIDTH = 0;
+parameter BUDGET = 0;
+parameter CI = 0;
+
+input [AB_WIDTH-1:0] A;
+input [AB_WIDTH-1:0] B;
+input [LCU_WIDTH-1:0] P;
+input [LCU_WIDTH-1:0] G;
+input PP;
+input GG;
+output Y;
+
+parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0;
+parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0;
+
+generate
+    if (AB_WIDTH == 0) begin
+        if (BUDGET < `LUT_WIDTH)
+             $__CMP2LCU #(.AB_WIDTH(AB_WIDTH), .AB_SIGNED(AB_SIGNED), .LCU_WIDTH(LCU_WIDTH+1), .BUDGET(`LUT_WIDTH), .CI(CI))
+                _TECHMAP_REPLACE_ (.A(A), .B(B), .P({P, PP}), .G({G, GG}), .PP(1'b1), .GG(1'b0), .Y(Y));
+        else begin
+            wire [LCU_WIDTH-1:0] CO;
+            $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO));
+            assign Y = CO[LCU_WIDTH-1];
+        end
+    end
+    else begin
+        if (BUDGET < 2)
+             $__CMP2LCU #(.AB_WIDTH(AB_WIDTH), .AB_SIGNED(AB_SIGNED), .LCU_WIDTH(LCU_WIDTH+1), .BUDGET(`LUT_WIDTH), .CI(CI))
+                _TECHMAP_REPLACE_ (.A(A), .B(B), .P({P, PP}), .G({G, GG}), .PP(1'b1), .GG(1'b0), .Y(Y));
+        else begin
+            wire PPP, GGG;
+            // Bit-wise equality (xnor) of A and B
+            assign PPP = A[AB_WIDTH-1] ^~ B[AB_WIDTH-1];
+            if (AB_SIGNED)
+                assign GGG = ~A[AB_WIDTH-1] & B[AB_WIDTH-1];
+            else if (BUDGET == `LUT_WIDTH)
+                assign GGG = A[AB_WIDTH-1] & ~B[AB_WIDTH-1];
+            else
+                // Priority "encoder" that checks A[i] == 1'b1 && B[i] == 1'b0
+                //   from MSB down, deferring to less significant bits if the
+                //   MSBs are equal
+                assign GGG = PP & (A[AB_WIDTH-1] & ~B[AB_WIDTH-1]);
+            $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-2), .CI(CI))
+                _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P), .G(G), 
+                // Propagate only if all bit pairs are equal
+                //   (inconclusive evidence to say A >= B)
+                .PP(PP & PPP), 
+                // Generate if any bit pairs call for it
+                .GG(GG | GGG),
+                .Y(Y));
+        end
     end
 endgenerate
 endmodule
index e7a422e2f8c609e3de7b0382a8cd6ff4eff608b9..620996549f3df491e92aac0f1b5345c417c81dc2 100644 (file)
@@ -1,5 +1,5 @@
 read_verilog <<EOT
-module top(input [11:0] a, b, output gtu, gts, ltu, lts, geu, ges, leu, les);
+module top(input [12:0] a, b, output gtu, gts, ltu, lts, geu, ges, leu, les);
 assign gtu = a > b;
 assign gts = $signed(a) > $signed(b);
 assign ltu = a < b;