From c29f0c5048fce87258eb4a4b204b6584efe0170c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 09:31:24 -0800 Subject: [PATCH 001/149] Add techmap rule for $__SHREG_DFF_P_ to SRL16/32 --- techlibs/xilinx/cells_map.v | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0771be0b9..bd115e305 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -84,3 +84,74 @@ module \$lut (A, Y); endgenerate endmodule `endif + +module \$__SHREG_DFF_P_ (input C, input D, output Q); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + generate + if (DEPTH == 1) begin + if (INIT == 0) + (* init=0 *) \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else if (INIT == 1) + (* init=1 *) \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + else + \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + end else + if (DEPTH <= 16) begin + SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A0(DEPTH[0]), .A1(DEPTH[1]), .A2(DEPTH[2]), .A3(DEPTH[3]), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); + end else + if (DEPTH == 17) begin + wire T0; + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + end else + if (DEPTH <= 32) begin + SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); + end else + if (DEPTH == 33 || DEPTH == 49) begin + wire T0; + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + end else + if (DEPTH <= 64) begin + wire T0, T1, T2; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32])) fpga_srl_1 (.C(C), .D(T1), .Q(T2)); + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(DEPTH[5])); + end else + if (DEPTH == 65 || DEPTH == 81) begin + wire T0; + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + end else + if (DEPTH <= 96) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64])) fpga_srl_2 (.C(C), .D(T3), .Q(T4)); + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(DEPTH[5])); + MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(DEPTH[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(DEPTH[6])); + end else + if (DEPTH == 97 || DEPTH == 113) begin + wire T0; + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + end else + if (DEPTH <= 128) begin + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(|0)) fpga_srl_2 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96])) fpga_srl_3 (.C(C), .D(T5), .Q(T6)); + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(DEPTH[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(DEPTH[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(DEPTH[6])); + end else + begin + wire T0, T1; + \$__SHREG_DFF_P_ #(.DEPTH(128), .INIT(INIT[128-1:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + end + endgenerate +endmodule From c9ab18889a63f74534c6fe9184ccb32e3661ab90 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 09:32:29 -0800 Subject: [PATCH 002/149] synth_xilinx to now have shregmap call after dff2dffe --- techlibs/xilinx/synth_xilinx.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 6c11d885d..afd868743 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -103,6 +103,7 @@ struct SynthXilinxPass : public Pass log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); + log(" shregmap -init\n"); log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); @@ -222,6 +223,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); + Pass::call(design, "shregmap -init"); Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); Pass::call(design, "opt -fast"); From 68f38f2ee0e82ac7250e8c4b257e33fd62d21544 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 10:21:05 -0800 Subject: [PATCH 003/149] synth_xilinx to use shregmap with -params too --- techlibs/xilinx/cells_map.v | 39 +++++++++++++++------------------ techlibs/xilinx/synth_xilinx.cc | 2 +- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index bd115e305..3b0a69898 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -85,73 +85,70 @@ module \$lut (A, Y); endmodule `endif -module \$__SHREG_DFF_P_ (input C, input D, output Q); - parameter DEPTH = 0; +module \$__SHREG_ (input C, input D, output Q); + parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 0; + parameter ENPOL = 2; generate if (DEPTH == 1) begin - if (INIT == 0) - (* init=0 *) \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); - else if (INIT == 1) - (* init=1 *) \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); - else - \$_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q)); + FDRE #(.INIT(INIT), .IS_C_INVERTED(CLKPOL), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); end else if (DEPTH <= 16) begin SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A0(DEPTH[0]), .A1(DEPTH[1]), .A2(DEPTH[2]), .A3(DEPTH[3]), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 17) begin wire T0; - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); end else if (DEPTH <= 32) begin SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 33 || DEPTH == 49) begin wire T0; - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); end else if (DEPTH <= 64) begin wire T0, T1, T2; SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32])) fpga_srl_1 (.C(C), .D(T1), .Q(T2)); + \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .Q(T2)); MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(DEPTH[5])); end else if (DEPTH == 65 || DEPTH == 81) begin wire T0; - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); end else if (DEPTH <= 96) begin wire T0, T1, T2, T3, T4, T5, T6; SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64])) fpga_srl_2 (.C(C), .D(T3), .Q(T4)); + \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .Q(T4)); MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(DEPTH[5])); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(DEPTH[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(DEPTH[6])); end else if (DEPTH == 97 || DEPTH == 113) begin wire T0; - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_DFF_P_ #(.DEPTH(1), .INIT(INIT[DEPTH-1])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); end else if (DEPTH <= 128) begin wire T0, T1, T2, T3, T4, T5, T6, T7, T8; SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(|0)) fpga_srl_2 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96])) fpga_srl_3 (.C(C), .D(T5), .Q(T6)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .Q(T6)); MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(DEPTH[5])); MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(DEPTH[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(DEPTH[6])); end else begin wire T0, T1; - \$__SHREG_DFF_P_ #(.DEPTH(128), .INIT(INIT[128-1:0])) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_DFF_P_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128])) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); + \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); end endgenerate endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index afd868743..4e4139154 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -223,7 +223,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); - Pass::call(design, "shregmap -init"); + Pass::call(design, "shregmap -init -params"); Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); Pass::call(design, "opt -fast"); From fe4d6898de378260c659dca08398fa434d71f7f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 11:17:13 -0800 Subject: [PATCH 004/149] synth_xilinx to call shregmap with enable support --- techlibs/xilinx/cells_map.v | 51 ++++++++++++++++++--------------- techlibs/xilinx/synth_xilinx.cc | 2 +- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 3b0a69898..168cbfa04 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -85,70 +85,75 @@ module \$lut (A, Y); endmodule `endif -module \$__SHREG_ (input C, input D, output Q); +module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; parameter CLKPOL = 0; parameter ENPOL = 2; + wire CE; generate + if (ENPOL != 0) + assign CE = E; + else + assign CE = ~E; if (DEPTH == 1) begin - FDRE #(.INIT(INIT), .IS_C_INVERTED(CLKPOL), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); + FDRE #(.INIT(INIT), .IS_C_INVERTED(~CLKPOL[0]), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else if (DEPTH <= 16) begin - SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A0(DEPTH[0]), .A1(DEPTH[1]), .A2(DEPTH[2]), .A3(DEPTH[3]), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); + SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(DEPTH[0]), .A1(DEPTH[1]), .A2(DEPTH[2]), .A3(DEPTH[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 17) begin wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 32) begin - SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(|0)) _TECHMAP_REPLACE_ (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(Q)); + SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 33 || DEPTH == 49) begin wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 64) begin wire T0, T1, T2; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .Q(T2)); + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(DEPTH[5])); end else if (DEPTH == 65 || DEPTH == 81) begin wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 96) begin wire T0, T1, T2, T3, T4, T5, T6; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .Q(T4)); + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .E(E), .Q(T4)); MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(DEPTH[5])); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(DEPTH[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(DEPTH[6])); end else if (DEPTH == 97 || DEPTH == 113) begin wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 128) begin wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(|0)) fpga_srl_0 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(|0)) fpga_srl_1 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(|0)) fpga_srl_2 (.A(DEPTH[4:0]), .CE(1'b1), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .Q(T6)); + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(DEPTH[5])); MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(DEPTH[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(DEPTH[6])); end else begin wire T0, T1; - \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .Q(T0)); - \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .Q(Q)); + \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end endgenerate endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 4e4139154..280c6b729 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -223,7 +223,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); - Pass::call(design, "shregmap -init -params"); + Pass::call(design, "shregmap -init -params -enpol any_or_none"); Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); Pass::call(design, "opt -fast"); From 8aab7fe7e64b1c213d924126e30994ab7b6d4625 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 13:56:00 -0800 Subject: [PATCH 005/149] Fix SRL16/32 techmap off-by-one --- techlibs/xilinx/cells_map.v | 42 +++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 168cbfa04..d2cc96969 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -88,19 +88,22 @@ endmodule module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; - parameter CLKPOL = 0; + parameter CLKPOL = 1; parameter ENPOL = 2; wire CE; generate - if (ENPOL != 0) + if (ENPOL == 0) + assign CE = ~E; + else if (ENPOL == 1) assign CE = E; else - assign CE = ~E; + assign CE = 1'b1; if (DEPTH == 1) begin FDRE #(.INIT(INIT), .IS_C_INVERTED(~CLKPOL[0]), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else if (DEPTH <= 16) begin - SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(DEPTH[0]), .A1(DEPTH[1]), .A2(DEPTH[2]), .A3(DEPTH[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); + localparam [3:0] A = DEPTH - 1; + SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 17) begin wire T0; @@ -108,7 +111,7 @@ module \$__SHREG_ (input C, input D, input E, output Q); \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 32) begin - SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH), .CE(CE), .CLK(C), .D(D), .Q(Q)); + SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH-1), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH == 33 || DEPTH == 49) begin wire T0; @@ -117,9 +120,10 @@ module \$__SHREG_ (input C, input D, input E, output Q); end else if (DEPTH <= 64) begin wire T0, T1, T2; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + localparam [5:0] A = DEPTH-1; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); - MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(DEPTH[5])); + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(A[5])); end else if (DEPTH == 65 || DEPTH == 81) begin wire T0; @@ -127,13 +131,14 @@ module \$__SHREG_ (input C, input D, input E, output Q); \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 96) begin + localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .E(E), .Q(T4)); - MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(DEPTH[5])); - MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(DEPTH[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(DEPTH[6])); + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(A[5])); + MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(A[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(A[6])); end else if (DEPTH == 97 || DEPTH == 113) begin wire T0; @@ -141,14 +146,15 @@ module \$__SHREG_ (input C, input D, input E, output Q); \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else if (DEPTH <= 128) begin + localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(DEPTH[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); - MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(DEPTH[5])); - MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(DEPTH[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(DEPTH[6])); + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); end else begin wire T0, T1; From 73ddab6960a02aef0c5f9ccee8cee2e666778c06 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 13:56:22 -0800 Subject: [PATCH 006/149] Add SRL16 and SRL32 sim models --- techlibs/xilinx/cells_sim.v | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index eba17ac9c..68f678385 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -186,3 +186,42 @@ module RAM128X1D ( wire clk = WCLK ^ IS_WCLK_INVERTED; always @(posedge clk) if (WE) mem[A] <= D; endmodule + +module SRL16E ( + output Q, + input A0, A1, A2, A3, CE, CLK, D +); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [15:0] r = INIT; + assign Q = r[{A3,A2,A1,A0}]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[14:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[14:0], D }; + endgenerate +endmodule + +module SRLC32E ( + output Q, + output Q31, + input [4:0] A, + input CE, CLK, D +); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [31:0] r = INIT; + assign Q31 = r[31]; + assign Q = r[A]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[30:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[30:0], D }; + endgenerate +endmodule From 1da090966263318c46dd1d91d2f1f4d11238c2c1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 28 Feb 2019 13:56:45 -0800 Subject: [PATCH 007/149] Remove SRL16/32 from cells_xtra --- techlibs/xilinx/cells_xtra.sh | 4 ++-- techlibs/xilinx/cells_xtra.v | 16 ---------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 0480410f5..8cc90d1f2 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -134,8 +134,8 @@ function xtract_cell_decl() xtract_cell_decl ROM256X1 xtract_cell_decl ROM32X1 xtract_cell_decl ROM64X1 - xtract_cell_decl SRL16E - xtract_cell_decl SRLC32E + #xtract_cell_decl SRL16E + #xtract_cell_decl SRLC32E xtract_cell_decl STARTUPE2 xtract_cell_decl USR_ACCESSE2 xtract_cell_decl XADC diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 8d8b91ddc..21db6a6bd 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -3824,22 +3824,6 @@ module ROM64X1 (...); input A0, A1, A2, A3, A4, A5; endmodule -module SRL16E (...); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output Q; - input A0, A1, A2, A3, CE, CLK, D; -endmodule - -module SRLC32E (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output Q; - output Q31; - input [4:0] A; - input CE, CLK, D; -endmodule - module STARTUPE2 (...); parameter PROG_USR = "FALSE"; parameter real SIM_CCLK_FREQ = 0.0; From 24f129ddfb6496226801861a15e4e9518217dd76 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Mar 2019 16:17:54 -0700 Subject: [PATCH 008/149] Refactor $__SHREG__ in cells_map.v --- techlibs/xilinx/cells_map.v | 56 ++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index d2cc96969..92358620e 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -105,32 +105,17 @@ module \$__SHREG_ (input C, input D, input E, output Q); localparam [3:0] A = DEPTH - 1; SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (DEPTH == 17) begin - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end else - if (DEPTH <= 32) begin + if (DEPTH > 17 && DEPTH <= 32) begin SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH-1), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (DEPTH == 33 || DEPTH == 49) begin - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end else - if (DEPTH <= 64) begin + if (DEPTH > 33 && DEPTH <= 64) begin wire T0, T1, T2; localparam [5:0] A = DEPTH-1; SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(A[5])); end else - if (DEPTH == 65 || DEPTH == 81) begin - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end else - if (DEPTH <= 96) begin + if (DEPTH > 65 && DEPTH <= 96) begin localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6; SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); @@ -140,23 +125,30 @@ module \$__SHREG_ (input C, input D, input E, output Q); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(A[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(A[6])); end else - if (DEPTH == 97 || DEPTH == 113) begin - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end else if (DEPTH <= 128) begin - localparam [6:0] A = DEPTH-1; - wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); - MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); - MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); + if (DEPTH > 97) begin + localparam [6:0] A = DEPTH-1; + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); + end + // Handle case where depth is just 1 over a convenient value, + // in which case use the flop + else begin + wire T0; + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); + end end else begin + // UG474 (v1.8, p34) states that: + // "There are no direct connections between slices to form longer shift + // registers, nor is the MC31 output at LUT B/C/D available." wire T0, T1; \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); From edca2f116373df7819ec68906ce74f15456168c2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 13 Mar 2019 17:13:52 -0700 Subject: [PATCH 009/149] Move shregmap until after first techmap --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 280c6b729..ce597ea4a 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -103,9 +103,9 @@ struct SynthXilinxPass : public Pass log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); - log(" shregmap -init\n"); log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); + log(" shregmap -init -params -enpol any_or_none\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); @@ -223,9 +223,9 @@ struct SynthXilinxPass : public Pass Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); - Pass::call(design, "shregmap -init -params -enpol any_or_none"); Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + Pass::call(design, "shregmap -init -params -enpol any_or_none"); Pass::call(design, "opt -fast"); } From 79b4a275ce85d231186105b6e73a596ff3326e1f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 Mar 2019 08:09:48 -0700 Subject: [PATCH 010/149] Fix cells_map for SRL --- techlibs/xilinx/cells_map.v | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 92358620e..0ace369d1 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -125,31 +125,29 @@ module \$__SHREG_ (input C, input D, input E, output Q); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(A[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(A[6])); end else - if (DEPTH <= 128) begin - if (DEPTH > 97) begin - localparam [6:0] A = DEPTH-1; - wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); - MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); - MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); - end - // Handle case where depth is just 1 over a convenient value, + if (DEPTH > 97 && DEPTH <= 128) begin + localparam [6:0] A = DEPTH-1; + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); + end + else if (DEPTH <= 129) begin + // Handle cases where depth is just 1 over a convenient value, // in which case use the flop - else begin - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end + wire T0; + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else begin // UG474 (v1.8, p34) states that: // "There are no direct connections between slices to form longer shift // registers, nor is the MC31 output at LUT B/C/D available." - wire T0, T1; + wire T0; \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end From 26ecbc1aee1dca1c186ab2b51835d74f67bc3e75 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 Mar 2019 08:10:02 -0700 Subject: [PATCH 011/149] Add shregmap -init_msb_first and use in synth_xilinx --- passes/techmap/shregmap.cc | 16 ++++++++++++++-- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index f20863ba0..6cd9082dc 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -34,7 +34,7 @@ struct ShregmapOptions { int minlen, maxlen; int keep_before, keep_after; - bool zinit, init, params, ffe; + bool zinit, init, params, ffe, init_msb_first; dict> ffcells; ShregmapTech *tech; @@ -48,6 +48,7 @@ struct ShregmapOptions init = false; params = false; ffe = false; + init_msb_first = false; tech = nullptr; } }; @@ -307,6 +308,8 @@ struct ShregmapWorker initval.push_back(State::S0); remove_init.insert(bit); } + if (opts.init_msb_first) + std::reverse(initval.begin(), initval.end()); first_cell->setParam("\\INIT", initval); } @@ -442,9 +445,13 @@ struct ShregmapPass : public Pass { log("\n"); log(" -init\n"); log(" map initialized registers to the shift reg, add an INIT parameter to\n"); - log(" generated cells with the initialization value. (first bit to shift out\n"); + log(" generated cells with the initialization value. (First bit to shift out\n"); log(" in LSB position)\n"); log("\n"); + log(" -init_msb_first\n"); + log(" same as -init, but INIT parameter to have first bit to shift out\n"); + log(" in MSB position.\n"); + log("\n"); log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); log("\n"); @@ -515,6 +522,11 @@ struct ShregmapPass : public Pass { opts.init = true; continue; } + if (args[argidx] == "-init_msb_first") { + opts.init = true; + opts.init_msb_first = true; + continue; + } if (args[argidx] == "-params") { opts.params = true; continue; diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index ce597ea4a..71b468e38 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -105,7 +105,7 @@ struct SynthXilinxPass : public Pass log(" dff2dffe\n"); log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" shregmap -init -params -enpol any_or_none\n"); + log(" shregmap -init_msb_first -params -enpol any_or_none\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); @@ -225,7 +225,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); - Pass::call(design, "shregmap -init -params -enpol any_or_none"); + Pass::call(design, "shregmap -init_msb_first -params -enpol any_or_none"); Pass::call(design, "opt -fast"); } From 8af9979aab5f1434ee7d0e56a85324d78e2fd9f9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 Mar 2019 09:01:48 -0700 Subject: [PATCH 012/149] Revert "Add shregmap -init_msb_first and use in synth_xilinx" This reverts commit 26ecbc1aee1dca1c186ab2b51835d74f67bc3e75. --- passes/techmap/shregmap.cc | 16 ++-------------- techlibs/xilinx/synth_xilinx.cc | 5 ++--- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 6cd9082dc..f20863ba0 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -34,7 +34,7 @@ struct ShregmapOptions { int minlen, maxlen; int keep_before, keep_after; - bool zinit, init, params, ffe, init_msb_first; + bool zinit, init, params, ffe; dict> ffcells; ShregmapTech *tech; @@ -48,7 +48,6 @@ struct ShregmapOptions init = false; params = false; ffe = false; - init_msb_first = false; tech = nullptr; } }; @@ -308,8 +307,6 @@ struct ShregmapWorker initval.push_back(State::S0); remove_init.insert(bit); } - if (opts.init_msb_first) - std::reverse(initval.begin(), initval.end()); first_cell->setParam("\\INIT", initval); } @@ -445,13 +442,9 @@ struct ShregmapPass : public Pass { log("\n"); log(" -init\n"); log(" map initialized registers to the shift reg, add an INIT parameter to\n"); - log(" generated cells with the initialization value. (First bit to shift out\n"); + log(" generated cells with the initialization value. (first bit to shift out\n"); log(" in LSB position)\n"); log("\n"); - log(" -init_msb_first\n"); - log(" same as -init, but INIT parameter to have first bit to shift out\n"); - log(" in MSB position.\n"); - log("\n"); log(" -tech greenpak4\n"); log(" map to greenpak4 shift registers.\n"); log("\n"); @@ -522,11 +515,6 @@ struct ShregmapPass : public Pass { opts.init = true; continue; } - if (args[argidx] == "-init_msb_first") { - opts.init = true; - opts.init_msb_first = true; - continue; - } if (args[argidx] == "-params") { opts.params = true; continue; diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 169f3b7ce..1978ccf21 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -111,7 +111,7 @@ struct SynthXilinxPass : public Pass log(" dff2dffe\n"); log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" shregmap -init_msb_first -params -enpol any_or_none\n"); + log(" shregmap -init -params -enpol any_or_none\n"); log(" techmap -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); @@ -262,9 +262,8 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); } - Pass::call(design, "shregmap -init_msb_first -params -enpol any_or_none"); + Pass::call(design, "shregmap -initt -params -enpol any_or_none"); Pass::call(design, "techmap -map +/xilinx/ff_map.v"); - Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); } From af5706c2a38c010e6c7343aeb1c5d6e26a6b7799 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 Mar 2019 09:06:56 -0700 Subject: [PATCH 013/149] Misspell --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1978ccf21..f2c3833a4 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -262,7 +262,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); } - Pass::call(design, "shregmap -initt -params -enpol any_or_none"); + Pass::call(design, "shregmap -init -params -enpol any_or_none"); Pass::call(design, "techmap -map +/xilinx/ff_map.v"); Pass::call(design, "opt -fast"); } From e7ef7fa443c0b7c7ec9e4bbb15893053aed8c3ce Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 14 Mar 2019 09:38:42 -0700 Subject: [PATCH 014/149] Reverse bits in INIT parameter for Xilinx, since MSB is shifted first --- techlibs/xilinx/cells_map.v | 48 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0c5c5a26f..69f8b85f4 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -23,6 +23,19 @@ module \$__SHREG_ (input C, input D, input E, output Q); parameter CLKPOL = 1; parameter ENPOL = 2; wire CE; + + // shregmap's INIT parameter shifts out LSB first; + // however Xilinx expects MSB first + function [DEPTH-1:0] brev; + input [DEPTH-1:0] din; + integer i; + begin + for (i = 0; i < DEPTH; i=i+1) + brev[i] = din[DEPTH-1-i]; + end + endfunction + localparam [DEPTH-1:0] INIT_R = brev(INIT); + generate if (ENPOL == 0) assign CE = ~E; @@ -31,28 +44,31 @@ module \$__SHREG_ (input C, input D, input E, output Q); else assign CE = 1'b1; if (DEPTH == 1) begin - FDRE #(.INIT(INIT), .IS_C_INVERTED(~CLKPOL[0]), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + if (CLKPOL) + FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + else + FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else if (DEPTH <= 16) begin localparam [3:0] A = DEPTH - 1; - SRL16E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); + SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH > 17 && DEPTH <= 32) begin - SRLC32E #(.INIT(INIT), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH-1), .CE(CE), .CLK(C), .D(D), .Q(Q)); + SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH-1), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH > 33 && DEPTH <= 64) begin wire T0, T1, T2; localparam [5:0] A = DEPTH-1; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-1:32]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(A[5])); end else if (DEPTH > 65 && DEPTH <= 96) begin localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-1:64]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .E(E), .Q(T4)); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .E(E), .Q(T4)); MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(A[5])); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(A[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(A[6])); @@ -60,10 +76,10 @@ module \$__SHREG_ (input C, input D, input E, output Q); if (DEPTH > 97 && DEPTH <= 128) begin localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-1:96]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); @@ -72,16 +88,16 @@ module \$__SHREG_ (input C, input D, input E, output Q); // Handle cases where depth is just 1 over a convenient value, // in which case use the flop wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-2:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[DEPTH-1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end else begin // UG474 (v1.8, p34) states that: // "There are no direct connections between slices to form longer shift // registers, nor is the MC31 output at LUT B/C/D available." wire T0; - \$__SHREG_ #(.DEPTH(128), .INIT(INIT[128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-1:128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); + \$__SHREG_ #(.DEPTH(128), .INIT(INIT[DEPTH-1:DEPTH-128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); end endgenerate endmodule From 06f8f2654abdef8684bfe4f373ac42cb8c62ee2a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 15 Mar 2019 19:13:40 -0700 Subject: [PATCH 015/149] Working --- passes/techmap/shregmap.cc | 655 +++++++++++++++++++------------- techlibs/xilinx/cells_map.v | 109 ++++-- techlibs/xilinx/synth_xilinx.cc | 16 +- 3 files changed, 470 insertions(+), 310 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index f20863ba0..4b8f8a828 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -26,7 +26,9 @@ PRIVATE_NAMESPACE_BEGIN struct ShregmapTech { virtual ~ShregmapTech() { } - virtual bool analyze(vector &taps) = 0; + virtual void init(const Module * /*module*/, const SigMap &/*sigmap*/) {} + virtual void non_chain_user(const SigBit &/*bit*/, const Cell* /*cell*/, IdString /*port*/) {} + virtual bool analyze(vector &taps, const vector &qbits) = 0; virtual bool fixup(Cell *cell, dict &taps) = 0; }; @@ -54,7 +56,7 @@ struct ShregmapOptions struct ShregmapTechGreenpak4 : ShregmapTech { - bool analyze(vector &taps) + bool analyze(vector &taps, const vector &/*qbits*/) { if (GetSize(taps) > 2 && taps[0] == 0 && taps[2] < 17) { taps.clear(); @@ -91,302 +93,423 @@ struct ShregmapTechGreenpak4 : ShregmapTech } }; +struct ShregmapTechXilinx7 : ShregmapTech +{ + dict sigbit_to_shiftx; + const ShregmapOptions &opts; + + ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} + + virtual void init(const Module* module, const SigMap &sigmap) override + { + for (auto i : module->cells_) { + auto cell = i.second; + if (cell->type != "$shiftx") continue; + if (cell->getParam("\\Y_WIDTH") != 1) continue; + for (auto bit : sigmap(cell->getPort("\\A"))) + sigbit_to_shiftx[bit] = cell; + } + } + + virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override + { + auto it = sigbit_to_shiftx.find(bit); + if (it == sigbit_to_shiftx.end()) + return; + if (cell->type == "$shiftx" && port == "\\A") + return; + it->second = nullptr; + } + + virtual bool analyze(vector &taps, const vector &qbits) override + { + if (GetSize(taps) == 1) + return taps[0] >= opts.minlen-1; + + if (taps.back() < opts.minlen-1) + return false; + + Cell *shiftx = nullptr; + int offset = 0; + for (int i = 0; i < GetSize(taps); ++i) { + // Check taps are sequential + if (i != taps[i]) + return false; + // Check taps are not connected to a shift register, + // or sequential to the same shift register + auto it = sigbit_to_shiftx.find(qbits[i]); + if (i == 0) { + if (it != sigbit_to_shiftx.end()) { + shiftx = it->second; + // NULL indicates there are non-shiftx users + if (shiftx == nullptr) + return false; + offset = qbits[i].offset; + } + } + else { + if (it == sigbit_to_shiftx.end()) { + if (shiftx != nullptr) + return false; + } + else { + if (shiftx != it->second) + return false; + if (qbits[i].offset != offset + i) + return false; + } + } + } + + return true; + } + + virtual bool fixup(Cell *cell, dict &taps) override + { + const auto &tap = *taps.begin(); + auto bit = tap.second; + auto it = sigbit_to_shiftx.find(bit); + if (it == sigbit_to_shiftx.end()) + return true; + + Cell* shiftx = it->second; + + auto module = cell->module; + + auto cell_q = cell->getPort("\\Q").as_bit(); + + auto shiftx_a = shiftx->getPort("\\A").bits(); + int offset = 0; + for (auto bit : shiftx_a) { + if (bit == cell_q) + break; + ++offset; + } + offset -= taps.size() - 1; + log_assert(offset >= 0); + for (size_t i = offset; i < offset + taps.size(); ++i) + shiftx_a[i] = cell_q; + // FIXME: Hack to ensure that $shiftx gets optimised away + // Without this, Yosys will refuse to optimise away a $shiftx + // where \\A 's width is not perfectly \\B_WIDTH ** 2 + auto shiftx_bwidth = shiftx->getParam("\\B_WIDTH").as_int(); + shiftx_a.resize(1 << shiftx_bwidth, shiftx_a.back()); + shiftx->setPort("\\A", shiftx_a); + shiftx->setParam("\\A_WIDTH", shiftx_a.size()); + + auto length = module->addWire(NEW_ID, ceil(log2(taps.size()))); + module->addSub(NEW_ID, shiftx->getPort("\\B"), RTLIL::Const(offset, ceil(log2(offset))), length); + cell->setPort("\\L", length); + + + return true; + } +}; + + struct ShregmapWorker { - Module *module; - SigMap sigmap; + Module *module; + SigMap sigmap; - const ShregmapOptions &opts; - int dff_count, shreg_count; + const ShregmapOptions &opts; + int dff_count, shreg_count; - pool remove_cells; - pool remove_init; + pool remove_cells; + pool remove_init; - dict sigbit_init; - dict sigbit_chain_next; - dict sigbit_chain_prev; - pool sigbit_with_non_chain_users; - pool chain_start_cells; + dict sigbit_init; + dict sigbit_chain_next; + dict sigbit_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; - void make_sigbit_chain_next_prev() + void make_sigbit_chain_next_prev() + { + for (auto wire : module->wires()) { - for (auto wire : module->wires()) - { - if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) - sigbit_with_non_chain_users.insert(bit); - } + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) + sigbit_with_non_chain_users.insert(bit); + } - if (wire->attributes.count("\\init")) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (initval[i] == State::S0 && !opts.zinit) - sigbit_init[initsig[i]] = false; - else if (initval[i] == State::S1) - sigbit_init[initsig[i]] = true; - } - } - - for (auto cell : module->cells()) - { - if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) - { - IdString d_port = opts.ffcells.at(cell->type).first; - IdString q_port = opts.ffcells.at(cell->type).second; - - SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); - SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); - - if (opts.init || sigbit_init.count(q_bit) == 0) - { - if (sigbit_chain_next.count(d_bit)) { - sigbit_with_non_chain_users.insert(d_bit); - } else - sigbit_chain_next[d_bit] = cell; - - sigbit_chain_prev[q_bit] = cell; - continue; - } - } - - for (auto conn : cell->connections()) - if (cell->input(conn.first)) - for (auto bit : sigmap(conn.second)) - sigbit_with_non_chain_users.insert(bit); - } + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (initval[i] == State::S0 && !opts.zinit) + sigbit_init[initsig[i]] = false; + else if (initval[i] == State::S1) + sigbit_init[initsig[i]] = true; + } } - void find_chain_start_cells() + for (auto cell : module->cells()) { - for (auto it : sigbit_chain_next) + if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) + { + IdString d_port = opts.ffcells.at(cell->type).first; + IdString q_port = opts.ffcells.at(cell->type).second; + + SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); + SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + + if (opts.init || sigbit_init.count(q_bit) == 0) { - if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) - goto start_cell; + if (sigbit_chain_next.count(d_bit)) { + sigbit_with_non_chain_users.insert(d_bit); + } else + sigbit_chain_next[d_bit] = cell; - if (sigbit_chain_prev.count(it.first) != 0) - { - Cell *c1 = sigbit_chain_prev.at(it.first); - Cell *c2 = it.second; - - if (c1->type != c2->type) - goto start_cell; - - if (c1->parameters != c2->parameters) - goto start_cell; - - IdString d_port = opts.ffcells.at(c1->type).first; - IdString q_port = opts.ffcells.at(c1->type).second; - - auto c1_conn = c1->connections(); - auto c2_conn = c1->connections(); - - c1_conn.erase(d_port); - c1_conn.erase(q_port); - - c2_conn.erase(d_port); - c2_conn.erase(q_port); - - if (c1_conn != c2_conn) - goto start_cell; - - continue; - } - - start_cell: - chain_start_cells.insert(it.second); + sigbit_chain_prev[q_bit] = cell; + continue; } + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) { + sigbit_with_non_chain_users.insert(bit); + if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first); + } + } + } + + void find_chain_start_cells() + { + for (auto it : sigbit_chain_next) + { + if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) + goto start_cell; + + if (sigbit_chain_prev.count(it.first) != 0) + { + Cell *c1 = sigbit_chain_prev.at(it.first); + Cell *c2 = it.second; + + if (c1->type != c2->type) + goto start_cell; + + if (c1->parameters != c2->parameters) + goto start_cell; + + IdString d_port = opts.ffcells.at(c1->type).first; + IdString q_port = opts.ffcells.at(c1->type).second; + + auto c1_conn = c1->connections(); + auto c2_conn = c1->connections(); + + c1_conn.erase(d_port); + c1_conn.erase(q_port); + + c2_conn.erase(d_port); + c2_conn.erase(q_port); + + if (c1_conn != c2_conn) + goto start_cell; + + continue; + } + +start_cell: + chain_start_cells.insert(it.second); + } + } + + vector create_chain(Cell *start_cell) + { + vector chain; + + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); + + IdString q_port = opts.ffcells.at(c->type).second; + SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); + + if (sigbit_chain_next.count(q_bit) == 0) + break; + + c = sigbit_chain_next.at(q_bit); + if (chain_start_cells.count(c) != 0) + break; } - vector create_chain(Cell *start_cell) - { - vector chain; + return chain; + } - Cell *c = start_cell; - while (c != nullptr) + void process_chain(vector &chain) + { + if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after) + return; + + int cursor = opts.keep_before; + while (cursor < GetSize(chain) - opts.keep_after) + { + int depth = GetSize(chain) - opts.keep_after - cursor; + + if (opts.maxlen > 0) + depth = std::min(opts.maxlen, depth); + + Cell *first_cell = chain[cursor]; + IdString q_port = opts.ffcells.at(first_cell->type).second; + dict taps_dict; + + if (opts.tech) + { + vector qbits; + vector taps; + + for (int i = 0; i < depth; i++) { - chain.push_back(c); + Cell *cell = chain[cursor+i]; + auto qbit = sigmap(cell->getPort(q_port)); + qbits.push_back(qbit); - IdString q_port = opts.ffcells.at(c->type).second; - SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); - - if (sigbit_chain_next.count(q_bit) == 0) - break; - - c = sigbit_chain_next.at(q_bit); - if (chain_start_cells.count(c) != 0) - break; + if (sigbit_with_non_chain_users.count(qbit)) + taps.push_back(i); } - return chain; - } - - void process_chain(vector &chain) - { - if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after) - return; - - int cursor = opts.keep_before; - while (cursor < GetSize(chain) - opts.keep_after) + while (depth > 0) { - int depth = GetSize(chain) - opts.keep_after - cursor; + if (taps.empty() || taps.back() < depth-1) + taps.push_back(depth-1); - if (opts.maxlen > 0) - depth = std::min(opts.maxlen, depth); + if (opts.tech->analyze(taps, qbits)) + break; - Cell *first_cell = chain[cursor]; - IdString q_port = opts.ffcells.at(first_cell->type).second; - dict taps_dict; - - if (opts.tech) - { - vector qbits; - vector taps; - - for (int i = 0; i < depth; i++) - { - Cell *cell = chain[cursor+i]; - auto qbit = sigmap(cell->getPort(q_port)); - qbits.push_back(qbit); - - if (sigbit_with_non_chain_users.count(qbit)) - taps.push_back(i); - } - - while (depth > 0) - { - if (taps.empty() || taps.back() < depth-1) - taps.push_back(depth-1); - - if (opts.tech->analyze(taps)) - break; - - taps.pop_back(); - depth--; - } - - depth = 0; - for (auto tap : taps) { - taps_dict[tap] = qbits.at(tap); - log_assert(depth < tap+1); - depth = tap+1; - } - } - - if (depth < 2) { - cursor++; - continue; - } - - Cell *last_cell = chain[cursor+depth-1]; - - log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", - log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); - - dff_count += depth; - shreg_count += 1; - - string shreg_cell_type_str = "$__SHREG"; - if (opts.params) { - shreg_cell_type_str += "_"; - } else { - if (first_cell->type[1] != '_') - shreg_cell_type_str += "_"; - shreg_cell_type_str += first_cell->type.substr(1); - } - - if (opts.init) { - vector initval; - for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - if (sigbit_init.count(bit) == 0) - initval.push_back(State::Sx); - else if (sigbit_init.at(bit)) - initval.push_back(State::S1); - else - initval.push_back(State::S0); - remove_init.insert(bit); - } - first_cell->setParam("\\INIT", initval); - } - - if (opts.zinit) - for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - remove_init.insert(bit); - } - - if (opts.params) - { - int param_clkpol = -1; - int param_enpol = 2; - - if (first_cell->type == "$_DFF_N_") param_clkpol = 0; - if (first_cell->type == "$_DFF_P_") param_clkpol = 1; - - if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; - if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; - if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; - if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; - - log_assert(param_clkpol >= 0); - first_cell->setParam("\\CLKPOL", param_clkpol); - if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); - } - - first_cell->type = shreg_cell_type_str; - first_cell->setPort(q_port, last_cell->getPort(q_port)); - first_cell->setParam("\\DEPTH", depth); - - if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) - remove_cells.insert(first_cell); - - for (int i = 1; i < depth; i++) - remove_cells.insert(chain[cursor+i]); - cursor += depth; + taps.pop_back(); + depth--; } - } - void cleanup() + depth = 0; + for (auto tap : taps) { + taps_dict[tap] = qbits.at(tap); + log_assert(depth < tap+1); + depth = tap+1; + } + } + + if (depth < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+depth-1]; + + log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); + + dff_count += depth; + shreg_count += 1; + + string shreg_cell_type_str = "$__SHREG"; + if (opts.params) { + shreg_cell_type_str += "_"; + } else { + if (first_cell->type[1] != '_') + shreg_cell_type_str += "_"; + shreg_cell_type_str += first_cell->type.substr(1); + } + + if (opts.init) { + vector initval; + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + if (sigbit_init.count(bit) == 0) + initval.push_back(State::Sx); + else if (sigbit_init.at(bit)) + initval.push_back(State::S1); + else + initval.push_back(State::S0); + remove_init.insert(bit); + } + first_cell->setParam("\\INIT", initval); + } + + if (opts.zinit) + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + remove_init.insert(bit); + } + + if (opts.params) + { + int param_clkpol = -1; + int param_enpol = 2; + + if (first_cell->type == "$_DFF_N_") param_clkpol = 0; + if (first_cell->type == "$_DFF_P_") param_clkpol = 1; + + if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; + if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; + if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; + if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; + + log_assert(param_clkpol >= 0); + first_cell->setParam("\\CLKPOL", param_clkpol); + if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); + } + + first_cell->type = shreg_cell_type_str; + first_cell->setPort(q_port, last_cell->getPort(q_port)); + if (!first_cell->hasPort("\\L")) + first_cell->setPort("\\L", depth-1); + first_cell->setParam("\\DEPTH", depth); + + if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) + remove_cells.insert(first_cell); + + for (int i = 1; i < depth; i++) + remove_cells.insert(chain[cursor+i]); + cursor += depth; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + for (auto wire : module->wires()) { - for (auto cell : remove_cells) - module->remove(cell); + if (wire->attributes.count("\\init") == 0) + continue; - for (auto wire : module->wires()) - { - if (wire->attributes.count("\\init") == 0) - continue; + SigSpec initsig = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); - SigSpec initsig = sigmap(wire); - Const &initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (remove_init.count(initsig[i])) + initval[i] = State::Sx; - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (remove_init.count(initsig[i])) - initval[i] = State::Sx; - - if (SigSpec(initval).is_fully_undef()) - wire->attributes.erase("\\init"); - } - - remove_cells.clear(); - sigbit_chain_next.clear(); - sigbit_chain_prev.clear(); - chain_start_cells.clear(); + if (SigSpec(initval).is_fully_undef()) + wire->attributes.erase("\\init"); } - ShregmapWorker(Module *module, const ShregmapOptions &opts) : - module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) - { - make_sigbit_chain_next_prev(); - find_chain_start_cells(); + remove_cells.clear(); + sigbit_chain_next.clear(); + sigbit_chain_prev.clear(); + chain_start_cells.clear(); + } - for (auto c : chain_start_cells) { - vector chain = create_chain(c); - process_chain(chain); - } + ShregmapWorker(Module *module, const ShregmapOptions &opts) : + module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) + { + if (opts.tech) + opts.tech->init(module, sigmap); - cleanup(); + make_sigbit_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); } + + cleanup(); + } }; struct ShregmapPass : public Pass { @@ -501,6 +624,12 @@ struct ShregmapPass : public Pass { clkpol = "pos"; opts.zinit = true; opts.tech = new ShregmapTechGreenpak4; + } + else if (tech == "xilinx") { + opts.init = true; + opts.params = true; + enpol = "any_or_none"; + opts.tech = new ShregmapTechXilinx7(opts); } else { argidx--; break; diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 69f8b85f4..e7fb269e9 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -17,7 +17,7 @@ * */ -module \$__SHREG_ (input C, input D, input E, output Q); +module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; parameter CLKPOL = 1; @@ -36,6 +36,9 @@ module \$__SHREG_ (input C, input D, input E, output Q); endfunction localparam [DEPTH-1:0] INIT_R = brev(INIT); + parameter _TECHMAP_CONSTMSK_L_ = 0; + parameter _TECHMAP_CONSTVAL_L_ = 0; + generate if (ENPOL == 0) assign CE = ~E; @@ -44,60 +47,86 @@ module \$__SHREG_ (input C, input D, input E, output Q); else assign CE = 1'b1; if (DEPTH == 1) begin - if (CLKPOL) - FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); - else - FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + wire _TECHMAP_FAIL_ = ~&_TECHMAP_CONSTMSK_L_ || _TECHMAP_CONSTVAL_L_ != 0; + if (CLKPOL) + FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + else + FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else if (DEPTH <= 16) begin - localparam [3:0] A = DEPTH - 1; - SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); + SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH > 17 && DEPTH <= 32) begin - SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(DEPTH-1), .CE(CE), .CLK(C), .D(D), .Q(Q)); + SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else if (DEPTH > 33 && DEPTH <= 64) begin wire T0, T1, T2; - localparam [5:0] A = DEPTH-1; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .E(E), .Q(T2)); - MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(A[5])); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T2; + else + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); end else if (DEPTH > 65 && DEPTH <= 96) begin - localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .E(E), .Q(T4)); - MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(A[5])); - MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(A[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(A[6])); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T4; + else begin + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); + end end else if (DEPTH > 97 && DEPTH <= 128) begin - localparam [6:0] A = DEPTH-1; wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(A[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(A[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .E(E), .Q(T6)); - MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(A[5])); - MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(A[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(A[6])); + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else begin + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); + end end - else if (DEPTH <= 129) begin + else if (DEPTH < 129 || (DEPTH <= 129 && &_TECHMAP_CONSTMSK_L_)) begin // Handle cases where depth is just 1 over a convenient value, - // in which case use the flop - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); - end else - begin - // UG474 (v1.8, p34) states that: - // "There are no direct connections between slices to form longer shift - // registers, nor is the MC31 output at LUT B/C/D available." - wire T0; - \$__SHREG_ #(.DEPTH(128), .INIT(INIT[DEPTH-1:DEPTH-128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .E(E), .Q(Q)); + if (&_TECHMAP_CONSTMSK_L_) begin + // For constant length, use the flop + wire T0; + \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(DEPTH-1-1), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(0), .E(E), .Q(Q)); + end + else begin + // For variable length, bump up to the next length + // because we can't access Q31 + \$__SHREG_ #(.DEPTH(DEPTH+1), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + end + else begin + if (&_TECHMAP_CONSTMSK_L_) begin + // UG474 (v1.8, p34) states that: + // "There are no direct connections between slices to form longer shift + // registers, nor is the MC31 output at LUT B/C/D available." + wire T0; + \$__SHREG_ #(.DEPTH(128), .INIT(INIT[DEPTH-1:DEPTH-128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(127), .E(E), .Q(T0)); + \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-1-128), .E(E), .Q(Q)); + end + else begin + // No way to create variable length shift registers >128 bits as Q31 + // cannot be output to the fabric... + wire [DEPTH-1:-1] c; + genvar i; + for (i = 0; i < DEPTH; i=i+1) + \$__SHREG_ #(.DEPTH(1), .INIT(INIT_R[i]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(c[i-1]), .L(0), .E(E), .Q(c[i])); + assign { c[-1], Q } = { D, c[L] }; + end end endgenerate endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index f2c3833a4..443ac4eed 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -110,9 +110,8 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" shregmap -init -params -enpol any_or_none\n"); - log(" techmap -map +/xilinx/ff_map.v\n"); + log(" shregmap -tech xilinx\n"); + log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); @@ -256,14 +255,17 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); + Pass::call(design, "simplemap t:$dff*"); + Pass::call(design, "shregmap -tech xilinx"); + Pass::call(design, "techmap -map +/xilinx/cells_map.v t:$__SHREG_"); + Pass::call(design, "opt -fast"); + if (vpr) { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); } else { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v"); } - Pass::call(design, "shregmap -init -params -enpol any_or_none"); - Pass::call(design, "techmap -map +/xilinx/ff_map.v"); Pass::call(design, "opt -fast"); } From 29a8d4745eb4ecd2947694d02f51c9333bf3ac21 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 15 Mar 2019 23:01:40 -0700 Subject: [PATCH 016/149] Cleanup synth_xilinx --- techlibs/xilinx/cells_map.v | 2 +- techlibs/xilinx/synth_xilinx.cc | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index e7fb269e9..a35b0742b 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -95,7 +95,7 @@ module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); end end - else if (DEPTH < 129 || (DEPTH <= 129 && &_TECHMAP_CONSTMSK_L_)) begin + else if (DEPTH <= 128 || (DEPTH == 129 && &_TECHMAP_CONSTMSK_L_)) begin // Handle cases where depth is just 1 over a convenient value, if (&_TECHMAP_CONSTMSK_L_) begin // For constant length, use the flop diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 443ac4eed..763732fe5 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -110,6 +110,7 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); + log(" simplemap t:$dff*\n"); log(" shregmap -tech xilinx\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v +/xilinx/ff_map.v\n"); log(" opt -fast\n"); @@ -257,8 +258,6 @@ struct SynthXilinxPass : public Pass Pass::call(design, "simplemap t:$dff*"); Pass::call(design, "shregmap -tech xilinx"); - Pass::call(design, "techmap -map +/xilinx/cells_map.v t:$__SHREG_"); - Pass::call(design, "opt -fast"); if (vpr) { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); From fadeadb8c87670b1cfe8f92ac9c5ac3beadcb312 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 16 Mar 2019 08:51:13 -0700 Subject: [PATCH 017/149] Only accept <128 for variable length, only if $shiftx exclusive --- passes/techmap/shregmap.cc | 25 +++++++++++++++++-------- techlibs/xilinx/cells_map.v | 6 +----- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 4b8f8a828..f893461a0 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -161,6 +161,16 @@ struct ShregmapTechXilinx7 : ShregmapTech } } + // Cannot implement variable-length shift registers + // greater than 128 since Q31 cannot be output onto + // fabric + if (shiftx && GetSize(taps) > 128) + return false; + + // Only map if $shiftx exclusively covers the shift register + if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + return false; + return true; } @@ -173,34 +183,33 @@ struct ShregmapTechXilinx7 : ShregmapTech return true; Cell* shiftx = it->second; - - auto module = cell->module; + auto shiftx_a = shiftx->getPort("\\A").bits(); auto cell_q = cell->getPort("\\Q").as_bit(); - auto shiftx_a = shiftx->getPort("\\A").bits(); int offset = 0; +#ifndef NDEBUG for (auto bit : shiftx_a) { if (bit == cell_q) break; ++offset; } offset -= taps.size() - 1; - log_assert(offset >= 0); + log_assert(offset == 0); +#endif for (size_t i = offset; i < offset + taps.size(); ++i) shiftx_a[i] = cell_q; + // FIXME: Hack to ensure that $shiftx gets optimised away // Without this, Yosys will refuse to optimise away a $shiftx // where \\A 's width is not perfectly \\B_WIDTH ** 2 + // See YosysHQ/yosys#878 auto shiftx_bwidth = shiftx->getParam("\\B_WIDTH").as_int(); shiftx_a.resize(1 << shiftx_bwidth, shiftx_a.back()); shiftx->setPort("\\A", shiftx_a); shiftx->setParam("\\A_WIDTH", shiftx_a.size()); - auto length = module->addWire(NEW_ID, ceil(log2(taps.size()))); - module->addSub(NEW_ID, shiftx->getPort("\\B"), RTLIL::Const(offset, ceil(log2(offset))), length); - cell->setPort("\\L", length); - + cell->setPort("\\L", shiftx->getPort("\\B")); return true; } diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index a35b0742b..1d538e262 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -121,11 +121,7 @@ module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); else begin // No way to create variable length shift registers >128 bits as Q31 // cannot be output to the fabric... - wire [DEPTH-1:-1] c; - genvar i; - for (i = 0; i < DEPTH; i=i+1) - \$__SHREG_ #(.DEPTH(1), .INIT(INIT_R[i]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl (.C(C), .D(c[i-1]), .L(0), .E(E), .Q(c[i])); - assign { c[-1], Q } = { D, c[L] }; + wire _TECHMAP_FAIL_ = 1; end end endgenerate From d6d9ef0fee3a187b884cbfd0b9a97da935666189 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 16 Mar 2019 12:49:46 -0700 Subject: [PATCH 018/149] Cleanup --- passes/techmap/shregmap.cc | 60 ++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index f893461a0..179a331fd 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -95,7 +95,7 @@ struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechXilinx7 : ShregmapTech { - dict sigbit_to_shiftx; + dict> sigbit_to_shiftx_offset; const ShregmapOptions &opts; ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} @@ -106,19 +106,21 @@ struct ShregmapTechXilinx7 : ShregmapTech auto cell = i.second; if (cell->type != "$shiftx") continue; if (cell->getParam("\\Y_WIDTH") != 1) continue; + int j = 0; for (auto bit : sigmap(cell->getPort("\\A"))) - sigbit_to_shiftx[bit] = cell; + sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j++); + log_assert(j == cell->getParam("\\A_WIDTH").as_int()); } } virtual void non_chain_user(const SigBit &bit, const Cell *cell, IdString port) override { - auto it = sigbit_to_shiftx.find(bit); - if (it == sigbit_to_shiftx.end()) + auto it = sigbit_to_shiftx_offset.find(bit); + if (it == sigbit_to_shiftx_offset.end()) return; if (cell->type == "$shiftx" && port == "\\A") return; - it->second = nullptr; + it->second = std::make_pair(nullptr, 0); } virtual bool analyze(vector &taps, const vector &qbits) override @@ -130,32 +132,34 @@ struct ShregmapTechXilinx7 : ShregmapTech return false; Cell *shiftx = nullptr; - int offset = 0; for (int i = 0; i < GetSize(taps); ++i) { // Check taps are sequential if (i != taps[i]) return false; // Check taps are not connected to a shift register, // or sequential to the same shift register - auto it = sigbit_to_shiftx.find(qbits[i]); + auto it = sigbit_to_shiftx_offset.find(qbits[i]); if (i == 0) { - if (it != sigbit_to_shiftx.end()) { - shiftx = it->second; + if (it != sigbit_to_shiftx_offset.end()) { + shiftx = it->second.first; // NULL indicates there are non-shiftx users if (shiftx == nullptr) return false; - offset = qbits[i].offset; + int offset = it->second.second; + if (offset != i) + return false; } } else { - if (it == sigbit_to_shiftx.end()) { + if (it == sigbit_to_shiftx_offset.end()) { if (shiftx != nullptr) return false; } else { - if (shiftx != it->second) + if (shiftx != it->second.first) return false; - if (qbits[i].offset != offset + i) + int offset = it->second.second; + if (offset != i) return false; } } @@ -178,36 +182,22 @@ struct ShregmapTechXilinx7 : ShregmapTech { const auto &tap = *taps.begin(); auto bit = tap.second; - auto it = sigbit_to_shiftx.find(bit); - if (it == sigbit_to_shiftx.end()) + auto it = sigbit_to_shiftx_offset.find(bit); + // If fixed-length, no fixup necessary + if (it == sigbit_to_shiftx_offset.end()) return true; - Cell* shiftx = it->second; - auto shiftx_a = shiftx->getPort("\\A").bits(); - - auto cell_q = cell->getPort("\\Q").as_bit(); - - int offset = 0; -#ifndef NDEBUG - for (auto bit : shiftx_a) { - if (bit == cell_q) - break; - ++offset; - } - offset -= taps.size() - 1; - log_assert(offset == 0); -#endif - for (size_t i = offset; i < offset + taps.size(); ++i) - shiftx_a[i] = cell_q; + auto cell_q = cell->getPort("\\Q"); + log_assert(cell_q.is_bit()); + Cell* shiftx = it->second.first; // FIXME: Hack to ensure that $shiftx gets optimised away // Without this, Yosys will refuse to optimise away a $shiftx // where \\A 's width is not perfectly \\B_WIDTH ** 2 // See YosysHQ/yosys#878 auto shiftx_bwidth = shiftx->getParam("\\B_WIDTH").as_int(); - shiftx_a.resize(1 << shiftx_bwidth, shiftx_a.back()); - shiftx->setPort("\\A", shiftx_a); - shiftx->setParam("\\A_WIDTH", shiftx_a.size()); + shiftx->setPort("\\A", cell_q.repeat(1 << shiftx_bwidth)); + shiftx->setParam("\\A_WIDTH", 1 << shiftx_bwidth); cell->setPort("\\L", shiftx->getPort("\\B")); From b94db546645e624b752203a4c4d2395dc84dff0c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 18 Mar 2019 13:35:54 -0700 Subject: [PATCH 019/149] shiftx NULL pointer check --- passes/techmap/shregmap.cc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 179a331fd..f3153b400 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -165,15 +165,17 @@ struct ShregmapTechXilinx7 : ShregmapTech } } - // Cannot implement variable-length shift registers - // greater than 128 since Q31 cannot be output onto - // fabric - if (shiftx && GetSize(taps) > 128) - return false; + if (shiftx) { + // Cannot implement variable-length shift registers + // greater than 128 since Q31 cannot be output onto + // fabric + if (GetSize(taps) > 128) + return false; - // Only map if $shiftx exclusively covers the shift register - if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) - return false; + // Only map if $shiftx exclusively covers the shift register + if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + return false; + } return true; } From ed32119d133166c78870137c6ce3db781b92c2e4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 18 Mar 2019 16:12:19 -0700 Subject: [PATCH 020/149] Fix shregmap to correctly recognise non chain users; cleanup --- passes/techmap/shregmap.cc | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index f3153b400..d95cadde5 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -120,7 +120,7 @@ struct ShregmapTechXilinx7 : ShregmapTech return; if (cell->type == "$shiftx" && port == "\\A") return; - it->second = std::make_pair(nullptr, 0); + sigbit_to_shiftx_offset.erase(it); } virtual bool analyze(vector &taps, const vector &qbits) override @@ -140,11 +140,11 @@ struct ShregmapTechXilinx7 : ShregmapTech // or sequential to the same shift register auto it = sigbit_to_shiftx_offset.find(qbits[i]); if (i == 0) { - if (it != sigbit_to_shiftx_offset.end()) { + if (it == sigbit_to_shiftx_offset.end()) { + return false; + } + else { shiftx = it->second.first; - // NULL indicates there are non-shiftx users - if (shiftx == nullptr) - return false; int offset = it->second.second; if (offset != i) return false; @@ -152,8 +152,7 @@ struct ShregmapTechXilinx7 : ShregmapTech } else { if (it == sigbit_to_shiftx_offset.end()) { - if (shiftx != nullptr) - return false; + return false; } else { if (shiftx != it->second.first) @@ -164,18 +163,17 @@ struct ShregmapTechXilinx7 : ShregmapTech } } } + log_assert(shiftx); - if (shiftx) { - // Cannot implement variable-length shift registers - // greater than 128 since Q31 cannot be output onto - // fabric - if (GetSize(taps) > 128) - return false; + // Cannot implement variable-length shift registers + // greater than 128 since Q31 cannot be output onto + // fabric + if (GetSize(taps) > 128) + return false; - // Only map if $shiftx exclusively covers the shift register - if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) - return false; - } + // Only map if $shiftx exclusively covers the shift register + if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + return false; return true; } From 0ea7eba5f13b20de28181a66181ee821820027db Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 13:08:43 -0700 Subject: [PATCH 021/149] Make output port a non chain user --- passes/techmap/shregmap.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index d95cadde5..3b3170e04 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -118,7 +118,7 @@ struct ShregmapTechXilinx7 : ShregmapTech auto it = sigbit_to_shiftx_offset.find(bit); if (it == sigbit_to_shiftx_offset.end()) return; - if (cell->type == "$shiftx" && port == "\\A") + if (cell && cell->type == "$shiftx" && port == "\\A") return; sigbit_to_shiftx_offset.erase(it); } @@ -228,8 +228,10 @@ struct ShregmapWorker for (auto wire : module->wires()) { if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) + for (auto bit : sigmap(wire)) { sigbit_with_non_chain_users.insert(bit); + if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {}); + } } if (wire->attributes.count("\\init")) { From f239cb821edb86c3ec48782139e982819f073a7c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 14:54:43 -0700 Subject: [PATCH 022/149] Fix INIT for variable length SRs that have been bumped up one --- techlibs/xilinx/cells_map.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 1d538e262..94a48dbc2 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -106,7 +106,7 @@ module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); else begin // For variable length, bump up to the next length // because we can't access Q31 - \$__SHREG_ #(.DEPTH(DEPTH+1), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + \$__SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); end end else begin From 4cd8f0297381c5fb9fe3b8cbb22d4240f2aaae63 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 15:05:08 -0700 Subject: [PATCH 023/149] shregmap -tech xilinx to delete $shiftx for var length SRL --- passes/techmap/shregmap.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 3b3170e04..bd537e7c2 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -187,19 +187,12 @@ struct ShregmapTechXilinx7 : ShregmapTech if (it == sigbit_to_shiftx_offset.end()) return true; - auto cell_q = cell->getPort("\\Q"); - log_assert(cell_q.is_bit()); - Cell* shiftx = it->second.first; - // FIXME: Hack to ensure that $shiftx gets optimised away - // Without this, Yosys will refuse to optimise away a $shiftx - // where \\A 's width is not perfectly \\B_WIDTH ** 2 - // See YosysHQ/yosys#878 - auto shiftx_bwidth = shiftx->getParam("\\B_WIDTH").as_int(); - shiftx->setPort("\\A", cell_q.repeat(1 << shiftx_bwidth)); - shiftx->setParam("\\A_WIDTH", 1 << shiftx_bwidth); cell->setPort("\\L", shiftx->getPort("\\B")); + cell->setPort("\\Q", shiftx->getPort("\\Y")); + + cell->module->remove(shiftx); return true; } From 9156e18f9215f7e8e5a36e068b137b01810769b1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 16:12:32 -0700 Subject: [PATCH 024/149] Fix spacing --- techlibs/xilinx/cells_map.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 94a48dbc2..00a0b494b 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -76,7 +76,7 @@ module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); if (&_TECHMAP_CONSTMSK_L_) assign Q = T4; else begin - MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); end From ae2a625d0507c9e7476497e0064ffa003aa761f1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 16:14:08 -0700 Subject: [PATCH 025/149] Restore original synth_xilinx commands --- techlibs/xilinx/synth_xilinx.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 61895e032..0eccb97f2 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -112,7 +112,7 @@ struct SynthXilinxPass : public Pass log(" opt -full\n"); log(" simplemap t:$dff*\n"); log(" shregmap -tech xilinx\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v +/xilinx/ff_map.v\n"); + log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); @@ -266,6 +266,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v"); } + Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); } From 5445cd4d00349f9d04f9e78c7c2804306fac6b65 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 17:44:33 -0700 Subject: [PATCH 026/149] Add support for variable length Xilinx SRL > 128 --- passes/techmap/shregmap.cc | 6 --- techlibs/xilinx/cells_map.v | 80 +++++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index bd537e7c2..a060b55df 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -165,12 +165,6 @@ struct ShregmapTechXilinx7 : ShregmapTech } log_assert(shiftx); - // Cannot implement variable-length shift registers - // greater than 128 since Q31 cannot be output onto - // fabric - if (GetSize(taps) > 128) - return false; - // Only map if $shiftx exclusively covers the shift register if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 00a0b494b..24383d626 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -105,23 +105,79 @@ module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); end else begin // For variable length, bump up to the next length - // because we can't access Q31 \$__SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); end end else begin - if (&_TECHMAP_CONSTMSK_L_) begin - // UG474 (v1.8, p34) states that: - // "There are no direct connections between slices to form longer shift - // registers, nor is the MC31 output at LUT B/C/D available." - wire T0; - \$__SHREG_ #(.DEPTH(128), .INIT(INIT[DEPTH-1:DEPTH-128]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(127), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(DEPTH-128), .INIT(INIT[DEPTH-128-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-1-128), .E(E), .Q(Q)); - end + \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + endgenerate +endmodule + +module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; + + // shregmap's INIT parameter shifts out LSB first; + // however Xilinx expects MSB first + function [DEPTH-1:0] brev; + input [DEPTH-1:0] din; + integer i; + begin + for (i = 0; i < DEPTH; i=i+1) + brev[i] = din[DEPTH-1-i]; + end + endfunction + localparam [DEPTH-1:0] INIT_R = brev(INIT); + + parameter _TECHMAP_CONSTMSK_L_ = 0; + parameter _TECHMAP_CONSTVAL_L_ = 0; + + generate + if (DEPTH == 1) begin + \$__SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(0), .E(E), .Q(Q)); + end + else if (DEPTH < 128) begin + \$__SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + else if (DEPTH == 128) begin + wire CE; + if (ENPOL == 0) + assign CE = ~E; + else if (ENPOL == 1) + assign CE = E; + else + assign CE = 1'b1; + + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; else begin - // No way to create variable length shift registers >128 bits as Q31 - // cannot be output to the fabric... - wire _TECHMAP_FAIL_ = 1; + wire T7, T8; + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); + end + end + else if (DEPTH > 128) begin + localparam lower_clog2 = $clog2((DEPTH+1)/2); + localparam lower_depth = 2 ** lower_clog2; + wire T0, T1, T2; + \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T2; + else begin + //assign Q = L[lower_clog2-1] ? T2 : T0; + // FIXME: Need to instantiate 2:1 MUX here since + // techmap with this file is run AFTER abc + LUT3 #(.INIT(8'b10101100)) fpga_mux (.I0(T2), .I1(T0), .I2(L[lower_clog2]), .O(Q)); end end endgenerate From 505e4c2d59ed81a1779644b7aaf61aee799c8f67 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 19 Mar 2019 21:58:05 -0700 Subject: [PATCH 027/149] Revert $__SHREG_ to orig; use $__XILINX_SHREG for variable length --- passes/techmap/shregmap.cc | 19 ++-- techlibs/xilinx/cells_map.v | 173 +++++++++++++++--------------------- 2 files changed, 84 insertions(+), 108 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index a060b55df..1729418e6 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -176,19 +176,30 @@ struct ShregmapTechXilinx7 : ShregmapTech { const auto &tap = *taps.begin(); auto bit = tap.second; + auto it = sigbit_to_shiftx_offset.find(bit); // If fixed-length, no fixup necessary if (it == sigbit_to_shiftx_offset.end()) return true; + auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_"); + newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); + newcell->setParam("\\INIT", cell->getParam("\\INIT")); + newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL")); + newcell->setParam("\\ENPOL", cell->getParam("\\ENPOL")); + + newcell->setPort("\\C", cell->getPort("\\C")); + newcell->setPort("\\D", cell->getPort("\\D")); + newcell->setPort("\\E", cell->getPort("\\E")); + Cell* shiftx = it->second.first; - cell->setPort("\\L", shiftx->getPort("\\B")); - cell->setPort("\\Q", shiftx->getPort("\\Y")); + newcell->setPort("\\L", shiftx->getPort("\\B")); + newcell->setPort("\\Q", shiftx->getPort("\\Y")); cell->module->remove(shiftx); - return true; + return false; } }; @@ -442,8 +453,6 @@ start_cell: first_cell->type = shreg_cell_type_str; first_cell->setPort(q_port, last_cell->getPort(q_port)); - if (!first_cell->hasPort("\\L")) - first_cell->setPort("\\L", depth-1); first_cell->setParam("\\DEPTH", depth); if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 24383d626..71ef45085 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -17,101 +17,13 @@ * */ -module \$__SHREG_ (input C, input D, input [31:0] L, input E, output Q); +module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; parameter CLKPOL = 1; parameter ENPOL = 2; - wire CE; - // shregmap's INIT parameter shifts out LSB first; - // however Xilinx expects MSB first - function [DEPTH-1:0] brev; - input [DEPTH-1:0] din; - integer i; - begin - for (i = 0; i < DEPTH; i=i+1) - brev[i] = din[DEPTH-1-i]; - end - endfunction - localparam [DEPTH-1:0] INIT_R = brev(INIT); - - parameter _TECHMAP_CONSTMSK_L_ = 0; - parameter _TECHMAP_CONSTVAL_L_ = 0; - - generate - if (ENPOL == 0) - assign CE = ~E; - else if (ENPOL == 1) - assign CE = E; - else - assign CE = 1'b1; - if (DEPTH == 1) begin - wire _TECHMAP_FAIL_ = ~&_TECHMAP_CONSTMSK_L_ || _TECHMAP_CONSTVAL_L_ != 0; - if (CLKPOL) - FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); - else - FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); - end else - if (DEPTH <= 16) begin - SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); - end else - if (DEPTH > 17 && DEPTH <= 32) begin - SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); - end else - if (DEPTH > 33 && DEPTH <= 64) begin - wire T0, T1, T2; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - \$__SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); - if (&_TECHMAP_CONSTMSK_L_) - assign Q = T2; - else - MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); - end else - if (DEPTH > 65 && DEPTH <= 96) begin - wire T0, T1, T2, T3, T4, T5, T6; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - \$__SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); - if (&_TECHMAP_CONSTMSK_L_) - assign Q = T4; - else begin - MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); - MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); - end - end else - if (DEPTH > 97 && DEPTH <= 128) begin - wire T0, T1, T2, T3, T4, T5, T6, T7, T8; - SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); - SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); - SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); - \$__SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); - if (&_TECHMAP_CONSTMSK_L_) - assign Q = T6; - else begin - MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); - MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); - MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); - end - end - else if (DEPTH <= 128 || (DEPTH == 129 && &_TECHMAP_CONSTMSK_L_)) begin - // Handle cases where depth is just 1 over a convenient value, - if (&_TECHMAP_CONSTMSK_L_) begin - // For constant length, use the flop - wire T0; - \$__SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(DEPTH-1-1), .E(E), .Q(T0)); - \$__SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(0), .E(E), .Q(Q)); - end - else begin - // For variable length, bump up to the next length - \$__SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); - end - end - else begin - \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); - end - endgenerate + \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q)); endmodule module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); @@ -135,22 +47,77 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o parameter _TECHMAP_CONSTMSK_L_ = 0; parameter _TECHMAP_CONSTVAL_L_ = 0; + wire CE; generate + if (ENPOL == 0) + assign CE = ~E; + else if (ENPOL == 1) + assign CE = E; + else + assign CE = 1'b1; if (DEPTH == 1) begin - \$__SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(0), .E(E), .Q(Q)); - end - else if (DEPTH < 128) begin - \$__SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); - end - else if (DEPTH == 128) begin - wire CE; - if (ENPOL == 0) - assign CE = ~E; - else if (ENPOL == 1) - assign CE = E; + //wire _TECHMAP_FAIL_ = ~&_TECHMAP_CONSTMSK_L_ || _TECHMAP_CONSTVAL_L_ != 0; + if (CLKPOL) + FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); else - assign CE = 1'b1; - + FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + end else + if (DEPTH <= 16) begin + SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); + end else + if (DEPTH > 17 && DEPTH <= 32) begin + SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); + end else + if (DEPTH > 33 && DEPTH <= 64) begin + wire T0, T1, T2; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T2; + else + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); + end else + if (DEPTH > 65 && DEPTH <= 96) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T4; + else begin + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); + end + end else + if (DEPTH > 97 && DEPTH < 128) begin + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else begin + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); + end + end + else if (DEPTH < 128 || (DEPTH == 129 && &_TECHMAP_CONSTMSK_L_)) begin + // Handle cases where depth is just 1 over a convenient value, + if (&_TECHMAP_CONSTMSK_L_) begin + // For constant length, use the flop + wire T0; + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(DEPTH-1-1), .E(E), .Q(T0)); + \$__XILINX_SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(0), .E(E), .Q(Q)); + end + else begin + // For variable length, bump up to the next length + \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + end + else if (DEPTH == 128) begin wire T0, T1, T2, T3, T4, T5, T6; SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); From 81c207fb9bc88c4e025ee058d767d33847682d19 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 20 Mar 2019 10:55:14 -0700 Subject: [PATCH 028/149] Fine tune cells_map.v --- techlibs/xilinx/cells_map.v | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 71ef45085..c23e3f81a 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -104,19 +104,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); end end - else if (DEPTH < 128 || (DEPTH == 129 && &_TECHMAP_CONSTMSK_L_)) begin - // Handle cases where depth is just 1 over a convenient value, - if (&_TECHMAP_CONSTMSK_L_) begin - // For constant length, use the flop - wire T0; - \$__XILINX_SHREG_ #(.DEPTH(DEPTH-1), .INIT(INIT[DEPTH-1:1]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(DEPTH-1-1), .E(E), .Q(T0)); - \$__XILINX_SHREG_ #(.DEPTH(1), .INIT(INIT[0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(0), .E(E), .Q(Q)); - end - else begin - // For variable length, bump up to the next length - \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); - end - end else if (DEPTH == 128) begin wire T0, T1, T2, T3, T4, T5, T6; SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); @@ -132,20 +119,29 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); end end - else if (DEPTH > 128) begin + else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin + // Handle cases where depth is just 1 over a convenient value, + // For variable length, bump up to the next length + \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + else /*if (DEPTH > 128)*/ begin localparam lower_clog2 = $clog2((DEPTH+1)/2); localparam lower_depth = 2 ** lower_clog2; - wire T0, T1, T2; - \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); - \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2)); - if (&_TECHMAP_CONSTMSK_L_) - assign Q = T2; + wire T0, T1, T2, T3; + if (&_TECHMAP_CONSTMSK_L_) begin + \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3)); + end else begin + \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); //assign Q = L[lower_clog2-1] ? T2 : T0; // FIXME: Need to instantiate 2:1 MUX here since // techmap with this file is run AFTER abc LUT3 #(.INIT(8'b10101100)) fpga_mux (.I0(T2), .I1(T0), .I2(L[lower_clog2]), .O(Q)); end + if (DEPTH == 2 * lower_depth) + assign SO = T3; end endgenerate endmodule From 2b911e270ba8012aa85f342838ed31b54568f257 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 20 Mar 2019 12:28:39 -0700 Subject: [PATCH 029/149] Fix spacing --- passes/techmap/shregmap.cc | 552 ++++++++++++++++++------------------- 1 file changed, 276 insertions(+), 276 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 1729418e6..028f4ba35 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -206,307 +206,307 @@ struct ShregmapTechXilinx7 : ShregmapTech struct ShregmapWorker { - Module *module; - SigMap sigmap; + Module *module; + SigMap sigmap; - const ShregmapOptions &opts; - int dff_count, shreg_count; + const ShregmapOptions &opts; + int dff_count, shreg_count; - pool remove_cells; - pool remove_init; + pool remove_cells; + pool remove_init; - dict sigbit_init; - dict sigbit_chain_next; - dict sigbit_chain_prev; - pool sigbit_with_non_chain_users; - pool chain_start_cells; + dict sigbit_init; + dict sigbit_chain_next; + dict sigbit_chain_prev; + pool sigbit_with_non_chain_users; + pool chain_start_cells; - void make_sigbit_chain_next_prev() - { - for (auto wire : module->wires()) + void make_sigbit_chain_next_prev() { - if (wire->port_output || wire->get_bool_attribute("\\keep")) { - for (auto bit : sigmap(wire)) { - sigbit_with_non_chain_users.insert(bit); - if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {}); - } - } - - if (wire->attributes.count("\\init")) { - SigSpec initsig = sigmap(wire); - Const initval = wire->attributes.at("\\init"); - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (initval[i] == State::S0 && !opts.zinit) - sigbit_init[initsig[i]] = false; - else if (initval[i] == State::S1) - sigbit_init[initsig[i]] = true; - } - } - - for (auto cell : module->cells()) - { - if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) - { - IdString d_port = opts.ffcells.at(cell->type).first; - IdString q_port = opts.ffcells.at(cell->type).second; - - SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); - SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); - - if (opts.init || sigbit_init.count(q_bit) == 0) + for (auto wire : module->wires()) { - if (sigbit_chain_next.count(d_bit)) { - sigbit_with_non_chain_users.insert(d_bit); - } else - sigbit_chain_next[d_bit] = cell; + if (wire->port_output || wire->get_bool_attribute("\\keep")) { + for (auto bit : sigmap(wire)) { + sigbit_with_non_chain_users.insert(bit); + if (opts.tech) opts.tech->non_chain_user(bit, nullptr, {}); + } + } - sigbit_chain_prev[q_bit] = cell; - continue; + if (wire->attributes.count("\\init")) { + SigSpec initsig = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (initval[i] == State::S0 && !opts.zinit) + sigbit_init[initsig[i]] = false; + else if (initval[i] == State::S1) + sigbit_init[initsig[i]] = true; + } } - } - for (auto conn : cell->connections()) - if (cell->input(conn.first)) - for (auto bit : sigmap(conn.second)) { - sigbit_with_non_chain_users.insert(bit); - if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first); - } - } - } - - void find_chain_start_cells() - { - for (auto it : sigbit_chain_next) - { - if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) - goto start_cell; - - if (sigbit_chain_prev.count(it.first) != 0) - { - Cell *c1 = sigbit_chain_prev.at(it.first); - Cell *c2 = it.second; - - if (c1->type != c2->type) - goto start_cell; - - if (c1->parameters != c2->parameters) - goto start_cell; - - IdString d_port = opts.ffcells.at(c1->type).first; - IdString q_port = opts.ffcells.at(c1->type).second; - - auto c1_conn = c1->connections(); - auto c2_conn = c1->connections(); - - c1_conn.erase(d_port); - c1_conn.erase(q_port); - - c2_conn.erase(d_port); - c2_conn.erase(q_port); - - if (c1_conn != c2_conn) - goto start_cell; - - continue; - } - -start_cell: - chain_start_cells.insert(it.second); - } - } - - vector create_chain(Cell *start_cell) - { - vector chain; - - Cell *c = start_cell; - while (c != nullptr) - { - chain.push_back(c); - - IdString q_port = opts.ffcells.at(c->type).second; - SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); - - if (sigbit_chain_next.count(q_bit) == 0) - break; - - c = sigbit_chain_next.at(q_bit); - if (chain_start_cells.count(c) != 0) - break; - } - - return chain; - } - - void process_chain(vector &chain) - { - if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after) - return; - - int cursor = opts.keep_before; - while (cursor < GetSize(chain) - opts.keep_after) - { - int depth = GetSize(chain) - opts.keep_after - cursor; - - if (opts.maxlen > 0) - depth = std::min(opts.maxlen, depth); - - Cell *first_cell = chain[cursor]; - IdString q_port = opts.ffcells.at(first_cell->type).second; - dict taps_dict; - - if (opts.tech) - { - vector qbits; - vector taps; - - for (int i = 0; i < depth; i++) + for (auto cell : module->cells()) { - Cell *cell = chain[cursor+i]; - auto qbit = sigmap(cell->getPort(q_port)); - qbits.push_back(qbit); + if (opts.ffcells.count(cell->type) && !cell->get_bool_attribute("\\keep")) + { + IdString d_port = opts.ffcells.at(cell->type).first; + IdString q_port = opts.ffcells.at(cell->type).second; - if (sigbit_with_non_chain_users.count(qbit)) - taps.push_back(i); + SigBit d_bit = sigmap(cell->getPort(d_port).as_bit()); + SigBit q_bit = sigmap(cell->getPort(q_port).as_bit()); + + if (opts.init || sigbit_init.count(q_bit) == 0) + { + if (sigbit_chain_next.count(d_bit)) { + sigbit_with_non_chain_users.insert(d_bit); + } else + sigbit_chain_next[d_bit] = cell; + + sigbit_chain_prev[q_bit] = cell; + continue; + } + } + + for (auto conn : cell->connections()) + if (cell->input(conn.first)) + for (auto bit : sigmap(conn.second)) { + sigbit_with_non_chain_users.insert(bit); + if (opts.tech) opts.tech->non_chain_user(bit, cell, conn.first); + } } - - while (depth > 0) - { - if (taps.empty() || taps.back() < depth-1) - taps.push_back(depth-1); - - if (opts.tech->analyze(taps, qbits)) - break; - - taps.pop_back(); - depth--; - } - - depth = 0; - for (auto tap : taps) { - taps_dict[tap] = qbits.at(tap); - log_assert(depth < tap+1); - depth = tap+1; - } - } - - if (depth < 2) { - cursor++; - continue; - } - - Cell *last_cell = chain[cursor+depth-1]; - - log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", - log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); - - dff_count += depth; - shreg_count += 1; - - string shreg_cell_type_str = "$__SHREG"; - if (opts.params) { - shreg_cell_type_str += "_"; - } else { - if (first_cell->type[1] != '_') - shreg_cell_type_str += "_"; - shreg_cell_type_str += first_cell->type.substr(1); - } - - if (opts.init) { - vector initval; - for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - if (sigbit_init.count(bit) == 0) - initval.push_back(State::Sx); - else if (sigbit_init.at(bit)) - initval.push_back(State::S1); - else - initval.push_back(State::S0); - remove_init.insert(bit); - } - first_cell->setParam("\\INIT", initval); - } - - if (opts.zinit) - for (int i = depth-1; i >= 0; i--) { - SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); - remove_init.insert(bit); - } - - if (opts.params) - { - int param_clkpol = -1; - int param_enpol = 2; - - if (first_cell->type == "$_DFF_N_") param_clkpol = 0; - if (first_cell->type == "$_DFF_P_") param_clkpol = 1; - - if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; - if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; - if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; - if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; - - log_assert(param_clkpol >= 0); - first_cell->setParam("\\CLKPOL", param_clkpol); - if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); - } - - first_cell->type = shreg_cell_type_str; - first_cell->setPort(q_port, last_cell->getPort(q_port)); - first_cell->setParam("\\DEPTH", depth); - - if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) - remove_cells.insert(first_cell); - - for (int i = 1; i < depth; i++) - remove_cells.insert(chain[cursor+i]); - cursor += depth; } - } - void cleanup() - { - for (auto cell : remove_cells) - module->remove(cell); - - for (auto wire : module->wires()) + void find_chain_start_cells() { - if (wire->attributes.count("\\init") == 0) - continue; + for (auto it : sigbit_chain_next) + { + if (opts.tech == nullptr && sigbit_with_non_chain_users.count(it.first)) + goto start_cell; - SigSpec initsig = sigmap(wire); - Const &initval = wire->attributes.at("\\init"); + if (sigbit_chain_prev.count(it.first) != 0) + { + Cell *c1 = sigbit_chain_prev.at(it.first); + Cell *c2 = it.second; - for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) - if (remove_init.count(initsig[i])) - initval[i] = State::Sx; + if (c1->type != c2->type) + goto start_cell; - if (SigSpec(initval).is_fully_undef()) - wire->attributes.erase("\\init"); + if (c1->parameters != c2->parameters) + goto start_cell; + + IdString d_port = opts.ffcells.at(c1->type).first; + IdString q_port = opts.ffcells.at(c1->type).second; + + auto c1_conn = c1->connections(); + auto c2_conn = c1->connections(); + + c1_conn.erase(d_port); + c1_conn.erase(q_port); + + c2_conn.erase(d_port); + c2_conn.erase(q_port); + + if (c1_conn != c2_conn) + goto start_cell; + + continue; + } + + start_cell: + chain_start_cells.insert(it.second); + } } - remove_cells.clear(); - sigbit_chain_next.clear(); - sigbit_chain_prev.clear(); - chain_start_cells.clear(); - } + vector create_chain(Cell *start_cell) + { + vector chain; - ShregmapWorker(Module *module, const ShregmapOptions &opts) : - module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) - { - if (opts.tech) - opts.tech->init(module, sigmap); + Cell *c = start_cell; + while (c != nullptr) + { + chain.push_back(c); - make_sigbit_chain_next_prev(); - find_chain_start_cells(); + IdString q_port = opts.ffcells.at(c->type).second; + SigBit q_bit = sigmap(c->getPort(q_port).as_bit()); - for (auto c : chain_start_cells) { - vector chain = create_chain(c); - process_chain(chain); + if (sigbit_chain_next.count(q_bit) == 0) + break; + + c = sigbit_chain_next.at(q_bit); + if (chain_start_cells.count(c) != 0) + break; + } + + return chain; } - cleanup(); - } + void process_chain(vector &chain) + { + if (GetSize(chain) < opts.keep_before + opts.minlen + opts.keep_after) + return; + + int cursor = opts.keep_before; + while (cursor < GetSize(chain) - opts.keep_after) + { + int depth = GetSize(chain) - opts.keep_after - cursor; + + if (opts.maxlen > 0) + depth = std::min(opts.maxlen, depth); + + Cell *first_cell = chain[cursor]; + IdString q_port = opts.ffcells.at(first_cell->type).second; + dict taps_dict; + + if (opts.tech) + { + vector qbits; + vector taps; + + for (int i = 0; i < depth; i++) + { + Cell *cell = chain[cursor+i]; + auto qbit = sigmap(cell->getPort(q_port)); + qbits.push_back(qbit); + + if (sigbit_with_non_chain_users.count(qbit)) + taps.push_back(i); + } + + while (depth > 0) + { + if (taps.empty() || taps.back() < depth-1) + taps.push_back(depth-1); + + if (opts.tech->analyze(taps, qbits)) + break; + + taps.pop_back(); + depth--; + } + + depth = 0; + for (auto tap : taps) { + taps_dict[tap] = qbits.at(tap); + log_assert(depth < tap+1); + depth = tap+1; + } + } + + if (depth < 2) { + cursor++; + continue; + } + + Cell *last_cell = chain[cursor+depth-1]; + + log("Converting %s.%s ... %s.%s to a shift register with depth %d.\n", + log_id(module), log_id(first_cell), log_id(module), log_id(last_cell), depth); + + dff_count += depth; + shreg_count += 1; + + string shreg_cell_type_str = "$__SHREG"; + if (opts.params) { + shreg_cell_type_str += "_"; + } else { + if (first_cell->type[1] != '_') + shreg_cell_type_str += "_"; + shreg_cell_type_str += first_cell->type.substr(1); + } + + if (opts.init) { + vector initval; + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + if (sigbit_init.count(bit) == 0) + initval.push_back(State::Sx); + else if (sigbit_init.at(bit)) + initval.push_back(State::S1); + else + initval.push_back(State::S0); + remove_init.insert(bit); + } + first_cell->setParam("\\INIT", initval); + } + + if (opts.zinit) + for (int i = depth-1; i >= 0; i--) { + SigBit bit = sigmap(chain[cursor+i]->getPort(q_port).as_bit()); + remove_init.insert(bit); + } + + if (opts.params) + { + int param_clkpol = -1; + int param_enpol = 2; + + if (first_cell->type == "$_DFF_N_") param_clkpol = 0; + if (first_cell->type == "$_DFF_P_") param_clkpol = 1; + + if (first_cell->type == "$_DFFE_NN_") param_clkpol = 0, param_enpol = 0; + if (first_cell->type == "$_DFFE_NP_") param_clkpol = 0, param_enpol = 1; + if (first_cell->type == "$_DFFE_PN_") param_clkpol = 1, param_enpol = 0; + if (first_cell->type == "$_DFFE_PP_") param_clkpol = 1, param_enpol = 1; + + log_assert(param_clkpol >= 0); + first_cell->setParam("\\CLKPOL", param_clkpol); + if (opts.ffe) first_cell->setParam("\\ENPOL", param_enpol); + } + + first_cell->type = shreg_cell_type_str; + first_cell->setPort(q_port, last_cell->getPort(q_port)); + first_cell->setParam("\\DEPTH", depth); + + if (opts.tech != nullptr && !opts.tech->fixup(first_cell, taps_dict)) + remove_cells.insert(first_cell); + + for (int i = 1; i < depth; i++) + remove_cells.insert(chain[cursor+i]); + cursor += depth; + } + } + + void cleanup() + { + for (auto cell : remove_cells) + module->remove(cell); + + for (auto wire : module->wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec initsig = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + + for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) + if (remove_init.count(initsig[i])) + initval[i] = State::Sx; + + if (SigSpec(initval).is_fully_undef()) + wire->attributes.erase("\\init"); + } + + remove_cells.clear(); + sigbit_chain_next.clear(); + sigbit_chain_prev.clear(); + chain_start_cells.clear(); + } + + ShregmapWorker(Module *module, const ShregmapOptions &opts) : + module(module), sigmap(module), opts(opts), dff_count(0), shreg_count(0) + { + if (opts.tech) + opts.tech->init(module, sigmap); + + make_sigbit_chain_next_prev(); + find_chain_start_cells(); + + for (auto c : chain_start_cells) { + vector chain = create_chain(c); + process_chain(chain); + } + + cleanup(); + } }; struct ShregmapPass : public Pass { From 5597270b9e2331d8836c8c24a073aadc1e19584a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 21 Mar 2019 10:20:27 -0700 Subject: [PATCH 030/149] Opt --- passes/techmap/shregmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 028f4ba35..d5221d46f 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -102,7 +102,7 @@ struct ShregmapTechXilinx7 : ShregmapTech virtual void init(const Module* module, const SigMap &sigmap) override { - for (auto i : module->cells_) { + for (const auto &i : module->cells_) { auto cell = i.second; if (cell->type != "$shiftx") continue; if (cell->getParam("\\Y_WIDTH") != 1) continue; From 4cc6b3e942a54e94f472df7817788dc321955a20 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 21 Mar 2019 15:04:44 -0700 Subject: [PATCH 031/149] Add '-nosrl' option to synth_xilinx --- techlibs/xilinx/synth_xilinx.cc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 0eccb97f2..5237cc4c6 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -64,10 +64,13 @@ struct SynthXilinxPass : public Pass log(" (this feature is experimental and incomplete)\n"); log("\n"); log(" -nobram\n"); - log(" disable infering of block rams\n"); + log(" disable inference of block rams\n"); log("\n"); log(" -nodram\n"); - log(" disable infering of distributed rams\n"); + log(" disable inference of distributed rams\n"); + log("\n"); + log(" -nobram\n"); + log(" disable inference of shift registers\n"); log("\n"); log(" -run :\n"); log(" only run the commands between the labels (see below). an empty\n"); @@ -110,8 +113,8 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" simplemap t:$dff*\n"); - log(" shregmap -tech xilinx\n"); + log(" simplemap t:$dff* (only without -nosrl)\n"); + log(" shregmap -tech xilinx (only without -nosrl)\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); @@ -149,6 +152,7 @@ struct SynthXilinxPass : public Pass bool vpr = false; bool nobram = false; bool nodram = false; + bool nosrl = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -193,6 +197,10 @@ struct SynthXilinxPass : public Pass nodram = true; continue; } + if (args[argidx] == "-nosrl") { + nosrl = true; + continue; + } break; } extra_args(args, argidx, design); @@ -257,8 +265,10 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); - Pass::call(design, "simplemap t:$dff*"); - Pass::call(design, "shregmap -tech xilinx"); + if (!nosrl) { + Pass::call(design, "simplemap t:$dff*"); + Pass::call(design, "shregmap -tech xilinx"); + } if (vpr) { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); From 03d108cd1f785fd32394746221fb81380b051ed1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Mar 2019 17:46:49 -0700 Subject: [PATCH 032/149] Working for 1 bit --- passes/techmap/shregmap.cc | 60 +++++++++++++++++++++++++++++++------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index d5221d46f..5c0f7191a 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -104,12 +104,23 @@ struct ShregmapTechXilinx7 : ShregmapTech { for (const auto &i : module->cells_) { auto cell = i.second; - if (cell->type != "$shiftx") continue; - if (cell->getParam("\\Y_WIDTH") != 1) continue; - int j = 0; - for (auto bit : sigmap(cell->getPort("\\A"))) - sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j++); - log_assert(j == cell->getParam("\\A_WIDTH").as_int()); + if (cell->type == "$shiftx") { + if (cell->getParam("\\Y_WIDTH") != 1) continue; + int j = 0; + for (auto bit : sigmap(cell->getPort("\\A"))) + sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j++); + log_assert(j == cell->getParam("\\A_WIDTH").as_int()); + } + else if (cell->type == "$pmux") { + if (cell->getParam("\\WIDTH") != 1) continue; + auto a_bit = sigmap(cell->getPort("\\A")).as_bit(); + sigbit_to_shiftx_offset[a_bit] = std::make_pair(cell, 0); + int j = cell->getParam("\\S_WIDTH").as_int(); + for (auto bit : sigmap(cell->getPort("\\B"))) + sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j--); + log_assert(j == 0); + + } } } @@ -118,8 +129,12 @@ struct ShregmapTechXilinx7 : ShregmapTech auto it = sigbit_to_shiftx_offset.find(bit); if (it == sigbit_to_shiftx_offset.end()) return; - if (cell && cell->type == "$shiftx" && port == "\\A") - return; + if (cell) { + if (cell->type == "$shiftx" && port == "\\A") + return; + if (cell->type == "$pmux" && (port == "\\A" || port == "\\B")) + return; + } sigbit_to_shiftx_offset.erase(it); } @@ -166,8 +181,15 @@ struct ShregmapTechXilinx7 : ShregmapTech log_assert(shiftx); // Only map if $shiftx exclusively covers the shift register - if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) - return false; + if (shiftx->type == "$shiftx") { + if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) + return false; + } + else if (shiftx->type == "$pmux") { + if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1) + return false; + } + else log_abort(); return true; } @@ -193,9 +215,25 @@ struct ShregmapTechXilinx7 : ShregmapTech newcell->setPort("\\E", cell->getPort("\\E")); Cell* shiftx = it->second.first; + RTLIL::SigSpec l_wire; + if (shiftx->type == "$shiftx") { + l_wire = shiftx->getPort("\\B"); + } + else if (shiftx->type == "$pmux") { + // Create a new encoder, out of a $pmux, that takes + // the existing pmux's 'S' input and transforms it + // back into a binary value + int clog2taps = ceil(log2(taps.size())); + RTLIL::SigSpec b_port; + for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) + b_port.append(RTLIL::Const(i, clog2taps)); + l_wire = cell->module->addWire(NEW_ID, clog2taps); + cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, shiftx->getPort("\\S"), l_wire); + } + else log_abort(); - newcell->setPort("\\L", shiftx->getPort("\\B")); newcell->setPort("\\Q", shiftx->getPort("\\Y")); + newcell->setPort("\\L", l_wire); cell->module->remove(shiftx); From 456295eb6686316dd6090ed32787bd91dc6e8d61 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Mar 2019 18:32:42 -0700 Subject: [PATCH 033/149] Fixes for multibit --- passes/techmap/shregmap.cc | 56 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 18 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 5c0f7191a..7e01ff134 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -95,7 +95,7 @@ struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechXilinx7 : ShregmapTech { - dict> sigbit_to_shiftx_offset; + dict> sigbit_to_shiftx_offset; const ShregmapOptions &opts; ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} @@ -108,18 +108,25 @@ struct ShregmapTechXilinx7 : ShregmapTech if (cell->getParam("\\Y_WIDTH") != 1) continue; int j = 0; for (auto bit : sigmap(cell->getPort("\\A"))) - sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j++); + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0); log_assert(j == cell->getParam("\\A_WIDTH").as_int()); } else if (cell->type == "$pmux") { - if (cell->getParam("\\WIDTH") != 1) continue; - auto a_bit = sigmap(cell->getPort("\\A")).as_bit(); - sigbit_to_shiftx_offset[a_bit] = std::make_pair(cell, 0); - int j = cell->getParam("\\S_WIDTH").as_int(); - for (auto bit : sigmap(cell->getPort("\\B"))) - sigbit_to_shiftx_offset[bit] = std::make_pair(cell, j--); + int width = cell->getParam("\\WIDTH").as_int(); + int j = 0; + for (auto bit : cell->getPort("\\A")) + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); + j = cell->getParam("\\S_WIDTH").as_int(); + int k = 0; + for (auto bit : sigmap(cell->getPort("\\B"))) { + printf("%d\n", bit.offset); + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++); + if (k == width) { + k = 0; + --j; + } + } log_assert(j == 0); - } } } @@ -140,6 +147,9 @@ struct ShregmapTechXilinx7 : ShregmapTech virtual bool analyze(vector &taps, const vector &qbits) override { + log("analyze() with %zu taps", taps.size()); + for (auto t : taps) log(" %d", t); + log("\n"); if (GetSize(taps) == 1) return taps[0] >= opts.minlen-1; @@ -147,6 +157,7 @@ struct ShregmapTechXilinx7 : ShregmapTech return false; Cell *shiftx = nullptr; + int group = 0; for (int i = 0; i < GetSize(taps); ++i) { // Check taps are sequential if (i != taps[i]) @@ -159,8 +170,8 @@ struct ShregmapTechXilinx7 : ShregmapTech return false; } else { - shiftx = it->second.first; - int offset = it->second.second; + int offset; + std::tie(shiftx,offset,group) = it->second; if (offset != i) return false; } @@ -170,11 +181,15 @@ struct ShregmapTechXilinx7 : ShregmapTech return false; } else { - if (shiftx != it->second.first) + Cell *shiftx_ = std::get<0>(it->second); + if (shiftx_ != shiftx) return false; - int offset = it->second.second; + int offset = std::get<1>(it->second); if (offset != i) return false; + int group_ = std::get<2>(it->second); + if (group_ != group) + return false; } } } @@ -214,10 +229,12 @@ struct ShregmapTechXilinx7 : ShregmapTech newcell->setPort("\\D", cell->getPort("\\D")); newcell->setPort("\\E", cell->getPort("\\E")); - Cell* shiftx = it->second.first; - RTLIL::SigSpec l_wire; + Cell* shiftx = std::get<0>(it->second); + RTLIL::SigSpec l_wire, q_wire; if (shiftx->type == "$shiftx") { l_wire = shiftx->getPort("\\B"); + q_wire = shiftx->getPort("\\Y"); + shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); } else if (shiftx->type == "$pmux") { // Create a new encoder, out of a $pmux, that takes @@ -229,14 +246,17 @@ struct ShregmapTechXilinx7 : ShregmapTech b_port.append(RTLIL::Const(i, clog2taps)); l_wire = cell->module->addWire(NEW_ID, clog2taps); cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, shiftx->getPort("\\S"), l_wire); + int group = std::get<2>(it->second); + RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); + q_wire = y_wire[group]; + y_wire[group] = cell->module->addWire(NEW_ID); + shiftx->setPort("\\Y", y_wire); } else log_abort(); - newcell->setPort("\\Q", shiftx->getPort("\\Y")); + newcell->setPort("\\Q", q_wire); newcell->setPort("\\L", l_wire); - cell->module->remove(shiftx); - return false; } }; From 0895093c7ce91e13c7fa8e878ae41f8877b3870d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Mar 2019 19:14:04 -0700 Subject: [PATCH 034/149] Leftover printf --- passes/techmap/shregmap.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 7e01ff134..d9a4aba99 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -119,7 +119,6 @@ struct ShregmapTechXilinx7 : ShregmapTech j = cell->getParam("\\S_WIDTH").as_int(); int k = 0; for (auto bit : sigmap(cell->getPort("\\B"))) { - printf("%d\n", bit.offset); sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++); if (k == width) { k = 0; From 098bd5758fe2e4cb7efa44503a1c498b0a2ace5e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 22 Mar 2019 23:22:19 -0700 Subject: [PATCH 035/149] Add support for SHREGMAP+$mux, also fine tune $pmux --- passes/techmap/shregmap.cc | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index d9a4aba99..fb48094ec 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -111,6 +111,14 @@ struct ShregmapTechXilinx7 : ShregmapTech sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j++, 0); log_assert(j == cell->getParam("\\A_WIDTH").as_int()); } + else if (cell->type == "$mux") { + int j = 0; + for (auto bit : cell->getPort("\\A")) + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); + j = 0; + for (auto bit : sigmap(cell->getPort("\\B"))) + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); + } else if (cell->type == "$pmux") { int width = cell->getParam("\\WIDTH").as_int(); int j = 0; @@ -140,6 +148,8 @@ struct ShregmapTechXilinx7 : ShregmapTech return; if (cell->type == "$pmux" && (port == "\\A" || port == "\\B")) return; + if (cell->type == "$mux" && (port == "\\A" || port == "\\B")) + return; } sigbit_to_shiftx_offset.erase(it); } @@ -203,6 +213,10 @@ struct ShregmapTechXilinx7 : ShregmapTech if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1) return false; } + else if (shiftx->type == "$mux") { + if (GetSize(taps) != 2) + return false; + } else log_abort(); return true; @@ -243,14 +257,23 @@ struct ShregmapTechXilinx7 : ShregmapTech RTLIL::SigSpec b_port; for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) b_port.append(RTLIL::Const(i, clog2taps)); + for (int i = (1 << clog2taps); i > shiftx->getParam("\\S_WIDTH").as_int(); i--) + b_port.append(RTLIL::Const(RTLIL::Sx, clog2taps)); l_wire = cell->module->addWire(NEW_ID, clog2taps); - cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, shiftx->getPort("\\S"), l_wire); + RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, (1 << clog2taps)); + cell->module->connect(s_wire.extract(0, shiftx->getParam("\\S_WIDTH").as_int()), shiftx->getPort("\\S")); + cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, s_wire, l_wire); int group = std::get<2>(it->second); RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); q_wire = y_wire[group]; y_wire[group] = cell->module->addWire(NEW_ID); shiftx->setPort("\\Y", y_wire); } + else if (shiftx->type == "$mux") { + l_wire = shiftx->getPort("\\S"); + q_wire = shiftx->getPort("\\Y"); + shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); + } else log_abort(); newcell->setPort("\\Q", q_wire); From bf83c074c82756b1cd23a9c3998b6c4d535dae29 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 23 Mar 2019 16:09:38 -0700 Subject: [PATCH 036/149] Cope with SHREG not having E port; Revert $pmux fine tune --- passes/techmap/shregmap.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index fb48094ec..7cf52c19a 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -240,7 +240,8 @@ struct ShregmapTechXilinx7 : ShregmapTech newcell->setPort("\\C", cell->getPort("\\C")); newcell->setPort("\\D", cell->getPort("\\D")); - newcell->setPort("\\E", cell->getPort("\\E")); + if (cell->hasPort("\\E")) + newcell->setPort("\\E", cell->getPort("\\E")); Cell* shiftx = std::get<0>(it->second); RTLIL::SigSpec l_wire, q_wire; @@ -257,10 +258,8 @@ struct ShregmapTechXilinx7 : ShregmapTech RTLIL::SigSpec b_port; for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) b_port.append(RTLIL::Const(i, clog2taps)); - for (int i = (1 << clog2taps); i > shiftx->getParam("\\S_WIDTH").as_int(); i--) - b_port.append(RTLIL::Const(RTLIL::Sx, clog2taps)); l_wire = cell->module->addWire(NEW_ID, clog2taps); - RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, (1 << clog2taps)); + RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, shiftx->getParam("\\S_WIDTH").as_int()); cell->module->connect(s_wire.extract(0, shiftx->getParam("\\S_WIDTH").as_int()), shiftx->getPort("\\S")); cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, s_wire, l_wire); int group = std::get<2>(it->second); From 2507d01b03cb4ec0a1345532d22688dd9a623948 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 23 Mar 2019 16:45:36 -0700 Subject: [PATCH 037/149] Add a pmux-to-shiftx optimisation to proc_mux --- passes/proc/proc_mux.cc | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 1329c1fef..7cac0327b 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -340,6 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; + bool shiftx = true; for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; @@ -348,6 +349,26 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); else result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); + + // Ignore output values which are entirely don't care + if (shiftx && !value.is_fully_undef()) { + // Keep checking if case condition is the same as the current case index + if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) + shiftx = (cs2->compare.front().as_int() == case_idx); + } + } + + // Transform into a $shiftx if possible + if (shiftx && last_mux_cell->type == "$pmux") { + // Sanity check that A port of $pmux should be 'bx + log_assert(last_mux_cell->getPort("\\A").is_fully_undef()); + // Because we went in reverse order above, un-reverse its B port here + auto b_port = last_mux_cell->getPort("\\B").chunks(); + std::reverse(b_port.begin(), b_port.end()); + // Create a $shiftx that shifts by the address line used in the case statement + mod->addShiftx(NEW_ID, b_port, sw->signal, last_mux_cell->getPort("\\Y")); + // Disconnect $pmux by replacing its output port with a floating wire + last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, last_mux_cell->getParam("\\WIDTH").as_int())); } } From b7a3d35c6b02f44dcad4052e2efe05c32fdada6b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 Mar 2019 11:16:56 -0700 Subject: [PATCH 038/149] Create one $shiftx per bit in width --- passes/proc/proc_mux.cc | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 7cac0327b..7d3d23408 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -340,7 +340,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; - bool shiftx = true; + bool shiftx = initial_val.is_fully_undef(); for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; @@ -355,20 +355,27 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // Keep checking if case condition is the same as the current case index if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) shiftx = (cs2->compare.front().as_int() == case_idx); + else + shiftx = false; } } - // Transform into a $shiftx if possible + // Transform into a $shiftx where possible if (shiftx && last_mux_cell->type == "$pmux") { - // Sanity check that A port of $pmux should be 'bx - log_assert(last_mux_cell->getPort("\\A").is_fully_undef()); - // Because we went in reverse order above, un-reverse its B port here - auto b_port = last_mux_cell->getPort("\\B").chunks(); - std::reverse(b_port.begin(), b_port.end()); - // Create a $shiftx that shifts by the address line used in the case statement - mod->addShiftx(NEW_ID, b_port, sw->signal, last_mux_cell->getPort("\\Y")); + // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement + auto pmux_b_port = last_mux_cell->getPort("\\B"); + auto pmux_y_port = last_mux_cell->getPort("\\Y"); + int width = last_mux_cell->getParam("\\WIDTH").as_int(); + for (int i = 0; i < width; ++i) { + RTLIL::SigSpec a_port; + // Because we went in reverse order above, un-reverse $pmux's B port here + for (int j = pmux_b_port.size()/width-1; j >= 0; --j) + a_port.append(pmux_b_port.extract(j*width+i, 1)); + // Create a $shiftx that shifts by the address line used in the case statement + mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1)); + } // Disconnect $pmux by replacing its output port with a floating wire - last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, last_mux_cell->getParam("\\WIDTH").as_int())); + last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width)); } } From f9fb05cf6684d855ce2fc776a20cd5552a4ef4a8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 25 Mar 2019 13:18:55 -0700 Subject: [PATCH 039/149] synth_xilinx to use shregmap with -minlen 3 --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 5237cc4c6..b6225a1a3 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -114,7 +114,7 @@ struct SynthXilinxPass : public Pass log(" dff2dffe\n"); log(" opt -full\n"); log(" simplemap t:$dff* (only without -nosrl)\n"); - log(" shregmap -tech xilinx (only without -nosrl)\n"); + log(" shregmap -tech xilinx -minlen 3 (only without -nosrl)\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); @@ -267,7 +267,7 @@ struct SynthXilinxPass : public Pass if (!nosrl) { Pass::call(design, "simplemap t:$dff*"); - Pass::call(design, "shregmap -tech xilinx"); + Pass::call(design, "shregmap -tech xilinx -minlen 3"); } if (vpr) { From 584d2030bf53c703febe8fda9cae73c72416c6cc Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 29 Mar 2019 16:32:44 +0100 Subject: [PATCH 040/149] Build Verilog parser with -DYYMAXDEPTH=100000, fixes #906 Signed-off-by: Clifford Wolf --- frontends/verilog/Makefile.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontends/verilog/Makefile.inc b/frontends/verilog/Makefile.inc index dbaace585..0a1f97ac0 100644 --- a/frontends/verilog/Makefile.inc +++ b/frontends/verilog/Makefile.inc @@ -14,6 +14,8 @@ frontends/verilog/verilog_lexer.cc: frontends/verilog/verilog_lexer.l $(Q) mkdir -p $(dir $@) $(P) flex -o frontends/verilog/verilog_lexer.cc $< +frontends/verilog/verilog_parser.tab.o: CXXFLAGS += -DYYMAXDEPTH=100000 + OBJS += frontends/verilog/verilog_parser.tab.o OBJS += frontends/verilog/verilog_lexer.o OBJS += frontends/verilog/preproc.o From 73b87e780798fe2c7958b75e4dfddc0dc2169d20 Mon Sep 17 00:00:00 2001 From: Jim Lawson Date: Mon, 1 Apr 2019 15:02:12 -0700 Subject: [PATCH 041/149] Refine memory support to deal with general Verilog memory definitions. --- backends/firrtl/firrtl.cc | 203 ++++++++++++++++++++++++++++++++------ 1 file changed, 173 insertions(+), 30 deletions(-) diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index eef6401b2..ed6e9f8ee 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -106,6 +106,95 @@ struct FirrtlWorker RTLIL::Design *design; std::string indent; + // Define read/write ports and memories. + // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction. + // For the moment, we don't handle $readmemh or $readmemb. + // These will be part of a subsequent PR. + struct read_port { + string name; + bool clk_enable; + bool clk_parity; + bool transparent; + RTLIL::SigSpec clk; + RTLIL::SigSpec ena; + RTLIL::SigSpec addr; + read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) { + // Current (3/13/2019) conventions: + // generate a constant 0 for clock and a constant 1 for enable if they are undefined. + if (!clk.is_fully_def()) + this->clk = SigSpec(RTLIL::Const(0, 1)); + if (!ena.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(1, 1)); + } + string gen_read(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str; + } + }; + struct write_port : read_port { + RTLIL::SigSpec mask; + write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) { + if (!clk.is_fully_def()) + this->clk = SigSpec(RTLIL::Const(0)); + if (!ena.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(0)); + if (!mask.is_fully_def()) + this->ena = SigSpec(RTLIL::Const(1)); + } + string gen_read(const char * /* indent */) { + log_error("gen_read called on write_port: %s\n", name.c_str()); + return stringf("gen_read called on write_port: %s\n", name.c_str()); + } + string gen_write(const char * indent) { + string addr_expr = make_expr(addr); + string ena_expr = make_expr(ena); + string clk_expr = make_expr(clk); + string mask_expr = make_expr(mask); + string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str()); + string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str()); + string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str()); + string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str()); + return addr_str + ena_str + clk_str + mask_str; + } + }; + /* Memories defined within this module. */ + struct memory { + string name; // memory name + int abits; // number of address bits + int size; // size (in units) of the memory + int width; // size (in bits) of each element + int read_latency; + int write_latency; + vector read_ports; + vector write_ports; + std::string init_file; + std::string init_file_srcFileSpec; + memory(string name, int abits, int size, int width) : name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {} + memory() : read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} + void add_memory_read_port(read_port &rp) { + read_ports.push_back(rp); + } + void add_memory_write_port(write_port &wp) { + write_ports.push_back(wp); + } + void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) { + this->init_file = init_file; + this->init_file_srcFileSpec = init_file_srcFileSpec; + } + + }; + dict memories; + + void register_memory(memory &m) + { + memories[m.name] = m; + } + void register_reverse_wire_map(string id, SigSpec sig) { for (int i = 0; i < GetSize(sig); i++) @@ -116,7 +205,7 @@ struct FirrtlWorker { } - string make_expr(const SigSpec &sig) + static string make_expr(const SigSpec &sig) { string expr; @@ -515,6 +604,7 @@ struct FirrtlWorker int abits = cell->parameters.at("\\ABITS").as_int(); int width = cell->parameters.at("\\WIDTH").as_int(); int size = cell->parameters.at("\\SIZE").as_int(); + memory m(mem_id, abits, size, width); int rd_ports = cell->parameters.at("\\RD_PORTS").as_int(); int wr_ports = cell->parameters.at("\\WR_PORTS").as_int(); @@ -531,33 +621,24 @@ struct FirrtlWorker if (offset != 0) log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" mem %s:\n", mem_id.c_str())); - cell_exprs.push_back(stringf(" data-type => UInt<%d>\n", width)); - cell_exprs.push_back(stringf(" depth => %d\n", size)); - - for (int i = 0; i < rd_ports; i++) - cell_exprs.push_back(stringf(" reader => r%d\n", i)); - - for (int i = 0; i < wr_ports; i++) - cell_exprs.push_back(stringf(" writer => w%d\n", i)); - - cell_exprs.push_back(stringf(" read-latency => 0\n")); - cell_exprs.push_back(stringf(" write-latency => 1\n")); - cell_exprs.push_back(stringf(" read-under-write => undefined\n")); - for (int i = 0; i < rd_ports; i++) { if (rd_clk_enable[i] != State::S0) log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); + SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits); SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width); - string addr_expr = make_expr(cell->getPort("\\RD_ADDR").extract(i*abits, abits)); - - cell_exprs.push_back(stringf(" %s.r%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.r%d.en <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.r%d.clk <= asClock(UInt<1>(0))\n", mem_id.c_str(), i)); - - register_reverse_wire_map(stringf("%s.r%d.data", mem_id.c_str(), i), data_sig); + string addr_expr = make_expr(addr_sig); + string name(stringf("%s.r%d", m.name.c_str(), i)); + bool clk_enable = false; + bool clk_parity = true; + bool transparency = false; + SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1); + read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig); + m.add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig); } for (int i = 0; i < wr_ports; i++) @@ -568,9 +649,16 @@ struct FirrtlWorker if (wr_clk_polarity[i] != State::S1) log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - string addr_expr = make_expr(cell->getPort("\\WR_ADDR").extract(i*abits, abits)); - string data_expr = make_expr(cell->getPort("\\WR_DATA").extract(i*width, width)); - string clk_expr = make_expr(cell->getPort("\\WR_CLK").extract(i)); + string name(stringf("%s.w%d", m.name.c_str(), i)); + bool clk_enable = true; + bool clk_parity = true; + bool transparency = false; + SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits); + string addr_expr = make_expr(addr_sig); + SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width); + string data_expr = make_expr(data_sig); + SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i); + string clk_expr = make_expr(clk_sig); SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width); string wen_expr = make_expr(wen_sig[0]); @@ -579,13 +667,50 @@ struct FirrtlWorker if (wen_sig[0] != wen_sig[i]) log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell)); - cell_exprs.push_back(stringf(" %s.w%d.addr <= %s\n", mem_id.c_str(), i, addr_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.data <= %s\n", mem_id.c_str(), i, data_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.en <= %s\n", mem_id.c_str(), i, wen_expr.c_str())); - cell_exprs.push_back(stringf(" %s.w%d.mask <= UInt<1>(1)\n", mem_id.c_str(), i)); - cell_exprs.push_back(stringf(" %s.w%d.clk <= asClock(%s)\n", mem_id.c_str(), i, clk_expr.c_str())); + SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1); + write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig); + m.add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); } + register_memory(m); + continue; + } + if (cell->type.in("$memwr", "$memrd", "$meminit")) + { + std::string cell_type = fid(cell->type); + std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string()); + memory *mp = nullptr; + if (cell->type == "$meminit" ) { + log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str()); + } else { + // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition. + auto addrSig = cell->getPort("\\ADDR"); + auto dataSig = cell->getPort("\\DATA"); + auto enableSig = cell->getPort("\\EN"); + auto clockSig = cell->getPort("\\CLK"); + Const clk_enable = cell->parameters.at("\\CLK_ENABLE"); + Const clk_polarity = cell->parameters.at("\\CLK_POLARITY"); + + mp = &memories.at(mem_id); + int portNum = 0; + bool transparency = false; + string data_expr = make_expr(dataSig); + if (cell->type.in("$memwr")) { + portNum = (int) mp->write_ports.size(); + write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig); + mp->add_memory_write_port(wp); + cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str())); + cell_exprs.push_back(wp.gen_write(indent.c_str())); + } else if (cell->type.in("$memrd")) { + portNum = (int) mp->read_ports.size(); + read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig); + mp->add_memory_read_port(rp); + cell_exprs.push_back(rp.gen_read(indent.c_str())); + register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig); + } + } continue; } @@ -763,6 +888,24 @@ struct FirrtlWorker f << stringf("\n"); + // If we have any memory definitions, output them. + for (auto kv : memories) { + memory m = kv.second; + f << stringf(" mem %s:\n", m.name.c_str()); + f << stringf(" data-type => UInt<%d>\n", m.width); + f << stringf(" depth => %d\n", m.size); + for (int i = 0; i < (int) m.read_ports.size(); i += 1) { + f << stringf(" reader => r%d\n", i); + } + for (int i = 0; i < (int) m.write_ports.size(); i += 1) { + f << stringf(" writer => w%d\n", i); + } + f << stringf(" read-latency => %d\n", m.read_latency); + f << stringf(" write-latency => %d\n", m.write_latency); + f << stringf(" read-under-write => undefined\n"); + } + f << stringf("\n"); + for (auto str : cell_exprs) f << str; From df92e9bdc23432847866e5b1101495e3424121e0 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Tue, 2 Apr 2019 19:21:01 +0200 Subject: [PATCH 042/149] Make nobram false by default for gowin --- techlibs/gowin/synth_gowin.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 9a3fcdbb6..c7983bade 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -73,7 +73,7 @@ struct SynthGowinPass : public ScriptPass vout_file = ""; retime = false; flatten = true; - nobram = true; + nobram = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE From 6acbc016f43b1464e6322b895f16d01ed51eea18 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 2 Apr 2019 19:47:50 +0100 Subject: [PATCH 043/149] memory_bram: Consider read enable for address expansion register Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 85ed1c053..804aa21f9 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -957,6 +957,8 @@ grow_read_ports:; SigSpec addr_ok_q = addr_ok; if ((pi.clocks || pi.make_outreg) && !addr_ok.empty()) { addr_ok_q = module->addWire(NEW_ID); + if (!pi.sig_en.empty()) + addr_ok = module->Mux(NEW_ID, addr_ok_q, addr_ok, pi.sig_en); module->addDff(NEW_ID, pi.sig_clock, addr_ok, addr_ok_q, pi.effective_clkpol); } From 39380c45ba6cb4d2aa3f8c5757a2f1a61f85f8eb Mon Sep 17 00:00:00 2001 From: Sylvain Munaut Date: Wed, 3 Apr 2019 14:50:12 +0200 Subject: [PATCH 044/149] proc_mux: Fix crash when trying to optimize non-existant mux to shiftx last_mux_cell can be NULL ... Signed-off-by: Sylvain Munaut --- passes/proc/proc_mux.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 7d3d23408..bac2dc2cd 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -361,7 +361,7 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d } // Transform into a $shiftx where possible - if (shiftx && last_mux_cell->type == "$pmux") { + if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") { // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement auto pmux_b_port = last_mux_cell->getPort("\\B"); auto pmux_y_port = last_mux_cell->getPort("\\Y"); From f7a0434d54261834a7371727741e5cdf24ec5ca0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 3 Apr 2019 07:05:28 -0700 Subject: [PATCH 045/149] Add changelog entry --- CHANGELOG | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG b/CHANGELOG index 42e01645e..95bbb3f33 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "gate2lut.v" techmap rule - Added "rename -src" - Added "equiv_opt" pass + - Added "shregmap -tech xilinx", used by "synth_xilinx" Yosys 0.7 .. Yosys 0.8 From 88630cd02cfb7cb124c949777280b60f66ee5eb5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 3 Apr 2019 07:14:20 -0700 Subject: [PATCH 046/149] Disable shregmap in synth_xilinx if -retime --- techlibs/xilinx/synth_xilinx.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index b6225a1a3..df30a22de 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -113,8 +113,8 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" simplemap t:$dff* (only without -nosrl)\n"); - log(" shregmap -tech xilinx -minlen 3 (only without -nosrl)\n"); + log(" simplemap t:$dff* (without -nosrl and without -retime only)\n"); + log(" shregmap -tech xilinx -minlen 3 (without -nosrl and without -retime only)\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); @@ -265,7 +265,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); - if (!nosrl) { + if (!nosrl && !retime) { Pass::call(design, "simplemap t:$dff*"); Pass::call(design, "shregmap -tech xilinx -minlen 3"); } From ff385a5ad0570cb56ae63d450e1dcba76ffaff7e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 3 Apr 2019 08:14:09 -0700 Subject: [PATCH 047/149] Remove duplicate STARTUPE2 --- techlibs/xilinx/cells_xtra.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 3f8efeebd..c23e67029 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -137,7 +137,6 @@ function xtract_cell_decl() xtract_cell_decl ROM64X1 #xtract_cell_decl SRL16E #xtract_cell_decl SRLC32E - xtract_cell_decl STARTUPE2 xtract_cell_decl STARTUPE2 "(* keep *)" xtract_cell_decl USR_ACCESSE2 xtract_cell_decl XADC From 0e2d929cead2a32ae176a408da257ec5b8b79f47 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 3 Apr 2019 08:28:07 -0700 Subject: [PATCH 048/149] -nosrl meant when -nobram --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index df30a22de..601a6811d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -69,7 +69,7 @@ struct SynthXilinxPass : public Pass log(" -nodram\n"); log(" disable inference of distributed rams\n"); log("\n"); - log(" -nobram\n"); + log(" -nosrl\n"); log(" disable inference of shift registers\n"); log("\n"); log(" -run :\n"); From aa693d5723ef1438d42cd35a26673703b1eff79f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 3 Apr 2019 08:35:32 -0700 Subject: [PATCH 049/149] Remove handling for $pmux, since #895 --- passes/techmap/shregmap.cc | 40 -------------------------------------- 1 file changed, 40 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 7cf52c19a..408e3f8c7 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -119,22 +119,6 @@ struct ShregmapTechXilinx7 : ShregmapTech for (auto bit : sigmap(cell->getPort("\\B"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); } - else if (cell->type == "$pmux") { - int width = cell->getParam("\\WIDTH").as_int(); - int j = 0; - for (auto bit : cell->getPort("\\A")) - sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); - j = cell->getParam("\\S_WIDTH").as_int(); - int k = 0; - for (auto bit : sigmap(cell->getPort("\\B"))) { - sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++); - if (k == width) { - k = 0; - --j; - } - } - log_assert(j == 0); - } } } @@ -146,8 +130,6 @@ struct ShregmapTechXilinx7 : ShregmapTech if (cell) { if (cell->type == "$shiftx" && port == "\\A") return; - if (cell->type == "$pmux" && (port == "\\A" || port == "\\B")) - return; if (cell->type == "$mux" && (port == "\\A" || port == "\\B")) return; } @@ -209,10 +191,6 @@ struct ShregmapTechXilinx7 : ShregmapTech if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; } - else if (shiftx->type == "$pmux") { - if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1) - return false; - } else if (shiftx->type == "$mux") { if (GetSize(taps) != 2) return false; @@ -250,24 +228,6 @@ struct ShregmapTechXilinx7 : ShregmapTech q_wire = shiftx->getPort("\\Y"); shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); } - else if (shiftx->type == "$pmux") { - // Create a new encoder, out of a $pmux, that takes - // the existing pmux's 'S' input and transforms it - // back into a binary value - int clog2taps = ceil(log2(taps.size())); - RTLIL::SigSpec b_port; - for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) - b_port.append(RTLIL::Const(i, clog2taps)); - l_wire = cell->module->addWire(NEW_ID, clog2taps); - RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, shiftx->getParam("\\S_WIDTH").as_int()); - cell->module->connect(s_wire.extract(0, shiftx->getParam("\\S_WIDTH").as_int()), shiftx->getPort("\\S")); - cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, s_wire, l_wire); - int group = std::get<2>(it->second); - RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); - q_wire = y_wire[group]; - y_wire[group] = cell->module->addWire(NEW_ID); - shiftx->setPort("\\Y", y_wire); - } else if (shiftx->type == "$mux") { l_wire = shiftx->getPort("\\S"); q_wire = shiftx->getPort("\\Y"); From 736e19f02d9980691e244e08b711c5e8c0b4fc76 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 4 Apr 2019 07:39:19 -0700 Subject: [PATCH 050/149] t:$dff* -> t:$dff t:$dffe --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 601a6811d..5a3725e7d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -113,7 +113,7 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" simplemap t:$dff* (without -nosrl and without -retime only)\n"); + log(" simplemap t:$dff t:$dffe (without -nosrl and without -retime only)\n"); log(" shregmap -tech xilinx -minlen 3 (without -nosrl and without -retime only)\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); @@ -266,7 +266,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "opt -full"); if (!nosrl && !retime) { - Pass::call(design, "simplemap t:$dff*"); + Pass::call(design, "simplemap t:$dff t:$dffe"); Pass::call(design, "shregmap -tech xilinx -minlen 3"); } From 77755b5a662a11a3dcc18c070e6ea859104fc872 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 4 Apr 2019 07:41:40 -0700 Subject: [PATCH 051/149] Cleanup comments --- techlibs/xilinx/cells_map.v | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index c23e3f81a..2c88e0141 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -56,7 +56,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o else assign CE = 1'b1; if (DEPTH == 1) begin - //wire _TECHMAP_FAIL_ = ~&_TECHMAP_CONSTMSK_L_ || _TECHMAP_CONSTVAL_L_ != 0; if (CLKPOL) FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); else @@ -120,11 +119,11 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o end end else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin - // Handle cases where depth is just 1 over a convenient value, - // For variable length, bump up to the next length + // Handle cases where fixed-length depth is + // just 1 over a convenient value \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); end - else /*if (DEPTH > 128)*/ begin + else begin localparam lower_clog2 = $clog2((DEPTH+1)/2); localparam lower_depth = 2 ** lower_clog2; wire T0, T1, T2, T3; @@ -135,9 +134,9 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o else begin \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); - //assign Q = L[lower_clog2-1] ? T2 : T0; // FIXME: Need to instantiate 2:1 MUX here since // techmap with this file is run AFTER abc + //assign Q = L[lower_clog2-1] ? T2 : T0; LUT3 #(.INIT(8'b10101100)) fpga_mux (.I0(T2), .I1(T0), .I2(L[lower_clog2]), .O(Q)); end if (DEPTH == 2 * lower_depth) From d9cb787391143a1749954f9e442fd37a13668b08 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 4 Apr 2019 07:48:13 -0700 Subject: [PATCH 052/149] synth_xilinx to map_cells before map_luts --- techlibs/xilinx/synth_xilinx.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 805ae8e6e..1260ab106 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -113,17 +113,17 @@ struct SynthXilinxPass : public Pass log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); - log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); - log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); - log(" clean\n"); - log("\n"); log(" map_cells:\n"); log(" techmap -map +/xilinx/cells_map.v\n"); log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); log(" clean\n"); log("\n"); + log(" map_luts:\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); + log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); + log(" clean\n"); + log("\n"); log(" check:\n"); log(" hierarchy -check\n"); log(" stat\n"); @@ -265,13 +265,6 @@ struct SynthXilinxPass : public Pass Pass::call(design, "opt -fast"); } - if (check_label(active, run_from, run_to, "map_luts")) - { - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); - Pass::call(design, "clean"); - Pass::call(design, "techmap -map +/xilinx/lut_map.v"); - } - if (check_label(active, run_from, run_to, "map_cells")) { Pass::call(design, "techmap -map +/xilinx/cells_map.v"); @@ -280,6 +273,13 @@ struct SynthXilinxPass : public Pass Pass::call(design, "clean"); } + if (check_label(active, run_from, run_to, "map_luts")) + { + Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + Pass::call(design, "clean"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v"); + } + if (check_label(active, run_from, run_to, "check")) { Pass::call(design, "hierarchy -check"); From 2fb02247a71253460cadef492f01dac8cb8c831b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 4 Apr 2019 08:10:40 -0700 Subject: [PATCH 053/149] Use soft-logic, not LUT3 instantiation --- techlibs/xilinx/cells_map.v | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 2c88e0141..4173814fd 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -134,10 +134,8 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o else begin \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); - // FIXME: Need to instantiate 2:1 MUX here since - // techmap with this file is run AFTER abc - //assign Q = L[lower_clog2-1] ? T2 : T0; - LUT3 #(.INIT(8'b10101100)) fpga_mux (.I0(T2), .I1(T0), .I2(L[lower_clog2]), .O(Q)); + wire [1023:0] _TECHMAP_DO_ = "techmap -map +/techmap.v"; + assign Q = L[lower_clog2] ? T2 : T0; end if (DEPTH == 2 * lower_depth) assign SO = T3; From e3f20b17afce26f08b277b757e32c33a473a8571 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 4 Apr 2019 08:13:10 -0700 Subject: [PATCH 054/149] Missing techmap entry in help --- techlibs/xilinx/synth_xilinx.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1260ab106..b82ab9337 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -123,6 +123,7 @@ struct SynthXilinxPass : public Pass log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); log(" clean\n"); + log(" techmap -map +/xilinx/lut_map.v\n"); log("\n"); log(" check:\n"); log(" hierarchy -check\n"); From 75ca06526a29dfac447265a52014305fb96d7ebf Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 4 Apr 2019 18:10:10 +0200 Subject: [PATCH 055/149] Added missing argument checking to "mutate" command Signed-off-by: Clifford Wolf --- passes/sat/mutate.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/passes/sat/mutate.cc b/passes/sat/mutate.cc index c50678c51..b53bbfeb2 100644 --- a/passes/sat/mutate.cc +++ b/passes/sat/mutate.cc @@ -934,6 +934,32 @@ struct MutatePass : public Pass { return; } + if (opts.module.empty()) + log_cmd_error("Missing -module argument.\n"); + + Module *module = design->module(opts.module); + if (module == nullptr) + log_cmd_error("Module %s not found.\n", log_id(opts.module)); + + if (opts.cell.empty()) + log_cmd_error("Missing -cell argument.\n"); + + Cell *cell = module->cell(opts.cell); + if (cell == nullptr) + log_cmd_error("Cell %s not found in module %s.\n", log_id(opts.cell), log_id(opts.module)); + + if (opts.port.empty()) + log_cmd_error("Missing -port argument.\n"); + + if (!cell->hasPort(opts.port)) + log_cmd_error("Port %s not found on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + + if (opts.portbit < 0) + log_cmd_error("Missing -portbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.portbit) + log_cmd_error("Out-of-range -portbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + if (opts.mode == "inv") { mutate_inv(design, opts); return; @@ -944,6 +970,12 @@ struct MutatePass : public Pass { return; } + if (opts.ctrlbit < 0) + log_cmd_error("Missing -ctrlbit argument.\n"); + + if (GetSize(cell->getPort(opts.port)) <= opts.ctrlbit) + log_cmd_error("Out-of-range -ctrlbit argument for port %s on cell %s.%s.\n", log_id(opts.port), log_id(opts.module), log_id(opts.cell)); + if (opts.mode == "cnot0" || opts.mode == "cnot1") { mutate_cnot(design, opts, opts.mode == "cnot1"); return; From dfb242c905ff10bb4038f080aeb74a820e8fbd00 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 5 Apr 2019 17:31:49 +0200 Subject: [PATCH 056/149] Add "read_ilang -lib" Signed-off-by: Clifford Wolf --- frontends/ilang/ilang_frontend.cc | 10 +++++++++- frontends/ilang/ilang_frontend.h | 1 + frontends/ilang/ilang_parser.y | 6 ++++-- kernel/rtlil.cc | 24 ++++++++++++++++++++++++ kernel/rtlil.h | 1 + 5 files changed, 39 insertions(+), 3 deletions(-) diff --git a/frontends/ilang/ilang_frontend.cc b/frontends/ilang/ilang_frontend.cc index 6b302a796..30d9ff79d 100644 --- a/frontends/ilang/ilang_frontend.cc +++ b/frontends/ilang/ilang_frontend.cc @@ -47,16 +47,20 @@ struct IlangFrontend : public Frontend { log(" -nooverwrite\n"); log(" ignore re-definitions of modules. (the default behavior is to\n"); log(" create an error message if the existing module is not a blackbox\n"); - log(" module, and overwrite the existing module if it is a blackbox module.)\n"); + log(" module, and overwrite the existing module if it is a blackbox module.)\n"); log("\n"); log(" -overwrite\n"); log(" overwrite existing modules with the same name\n"); log("\n"); + log(" -lib\n"); + log(" only create empty blackbox modules\n"); + log("\n"); } void execute(std::istream *&f, std::string filename, std::vector args, RTLIL::Design *design) YS_OVERRIDE { ILANG_FRONTEND::flag_nooverwrite = false; ILANG_FRONTEND::flag_overwrite = false; + ILANG_FRONTEND::flag_lib = false; log_header(design, "Executing ILANG frontend.\n"); @@ -73,6 +77,10 @@ struct IlangFrontend : public Frontend { ILANG_FRONTEND::flag_overwrite = true; continue; } + if (arg == "-lib") { + ILANG_FRONTEND::flag_lib = true; + continue; + } break; } extra_args(f, filename, args, argidx); diff --git a/frontends/ilang/ilang_frontend.h b/frontends/ilang/ilang_frontend.h index 052dd4cb2..f8a152841 100644 --- a/frontends/ilang/ilang_frontend.h +++ b/frontends/ilang/ilang_frontend.h @@ -34,6 +34,7 @@ namespace ILANG_FRONTEND { extern RTLIL::Design *current_design; extern bool flag_nooverwrite; extern bool flag_overwrite; + extern bool flag_lib; } YOSYS_NAMESPACE_END diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 5bcc01f42..f83824088 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -37,7 +37,7 @@ namespace ILANG_FRONTEND { std::vector*> switch_stack; std::vector case_stack; dict attrbuf; - bool flag_nooverwrite, flag_overwrite; + bool flag_nooverwrite, flag_overwrite, flag_lib; bool delete_current_module; } using namespace ILANG_FRONTEND; @@ -98,7 +98,7 @@ module: delete_current_module = false; if (current_design->has($2)) { RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()) { + if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { log("Ignoring blackbox re-definition of module %s.\n", $2); delete_current_module = true; } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { @@ -124,6 +124,8 @@ module: current_module->fixup_ports(); if (delete_current_module) delete current_module; + else if (flag_lib) + current_module->makeblackbox(); current_module = nullptr; } EOL; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index b3214579d..9ae20a317 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -641,6 +641,30 @@ RTLIL::Module::~Module() delete it->second; } +void RTLIL::Module::makeblackbox() +{ + pool delwires; + + for (auto it = wires_.begin(); it != wires_.end(); ++it) + if (!it->second->port_input && !it->second->port_output) + delwires.insert(it->second); + + for (auto it = memories.begin(); it != memories.end(); ++it) + delete it->second; + memories.clear(); + + for (auto it = cells_.begin(); it != cells_.end(); ++it) + delete it->second; + cells_.clear(); + + for (auto it = processes.begin(); it != processes.end(); ++it) + delete it->second; + processes.clear(); + + remove(delwires); + set_bool_attribute("\\blackbox"); +} + void RTLIL::Module::reprocess_module(RTLIL::Design *, dict) { log_error("Cannot reprocess_module module `%s' !\n", id2cstr(name)); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 52496e702..fb045bc72 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -976,6 +976,7 @@ public: virtual void sort(); virtual void check(); virtual void optimize(); + virtual void makeblackbox(); void connect(const RTLIL::SigSig &conn); void connect(const RTLIL::SigSpec &lhs, const RTLIL::SigSpec &rhs); From 544843da717734ab9bd9bd88f71db2475fc3abc0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 12:55:52 -0700 Subject: [PATCH 057/149] techmap inside map_cells stage --- techlibs/xilinx/cells_map.v | 1 - techlibs/xilinx/synth_xilinx.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 4173814fd..c80e51bd0 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -134,7 +134,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o else begin \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); - wire [1023:0] _TECHMAP_DO_ = "techmap -map +/techmap.v"; assign Q = L[lower_clog2] ? T2 : T0; end if (DEPTH == 2 * lower_depth) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 326684daf..cabf0b76e 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -283,7 +283,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_cells")) { - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/cells_map.v"); Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); Pass::call(design, "clean"); From 19271bd996a79cb4be1db658fcf18227ee0a1dff Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 14:42:25 -0700 Subject: [PATCH 058/149] abc -dff now implies "-D 0" otherwise retiming doesn't happen --- passes/techmap/abc.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 21b70f492..c828ad8ed 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1674,6 +1674,8 @@ struct AbcPass : public Pass { } if (arg == "-dff") { dff_mode = true; + if (delay_target.empty()) + delay_target = "-D 0"; continue; } if (arg == "-clk" && argidx+1 < args.size()) { From ff0912c75e2b15c02c9512466179e4b2a15eb3d1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 14:43:06 -0700 Subject: [PATCH 059/149] synth_xilinx to techmap FFs after abc call, otherwise -retime fails --- techlibs/xilinx/synth_xilinx.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 805ae8e6e..99c2be420 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -256,9 +256,9 @@ struct SynthXilinxPass : public Pass Pass::call(design, "opt -full"); if (vpr) { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v -D _EXPLICIT_CARRY"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); } else { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v"); + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); } Pass::call(design, "hierarchy -check"); @@ -269,7 +269,7 @@ struct SynthXilinxPass : public Pass { Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); - Pass::call(design, "techmap -map +/xilinx/lut_map.v"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); } if (check_label(active, run_from, run_to, "map_cells")) From 8b6085254a962da46d46724f2333abd076d32928 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 15:15:13 -0700 Subject: [PATCH 060/149] Resolve @daveshah1 comment, update synth_xilinx help --- techlibs/xilinx/ff_map.v | 8 ++++---- techlibs/xilinx/synth_xilinx.cc | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v index 13beaa6ae..c323206e8 100644 --- a/techlibs/xilinx/ff_map.v +++ b/techlibs/xilinx/ff_map.v @@ -28,14 +28,14 @@ module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPL module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PN0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule `endif diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 99c2be420..abc164533 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -110,13 +110,14 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v -map +/xilinx/ff_map.v\n"); + log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); + log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); - log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); + log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); log("\n"); log(" map_cells:\n"); log(" techmap -map +/xilinx/cells_map.v\n"); @@ -260,6 +261,7 @@ struct SynthXilinxPass : public Pass } else { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); } + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); From 3c253818cab2013dc4db55732d3e21cfa0dc3f19 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 15:30:19 -0700 Subject: [PATCH 061/149] "&nf -D 0" fails => use "-D 1" instead --- passes/techmap/abc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index c828ad8ed..4876f3009 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1675,7 +1675,7 @@ struct AbcPass : public Pass { if (arg == "-dff") { dff_mode = true; if (delay_target.empty()) - delay_target = "-D 0"; + delay_target = "-D 1"; continue; } if (arg == "-clk" && argidx+1 < args.size()) { From 23a6533e98df384afdeb38891404da17533c836b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 15:31:54 -0700 Subject: [PATCH 062/149] Retry --- techlibs/xilinx/ff_map.v | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v index c323206e8..3d5f78770 100644 --- a/techlibs/xilinx/ff_map.v +++ b/techlibs/xilinx/ff_map.v @@ -30,7 +30,7 @@ module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPL module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PN0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule From 97587015748eb9f7e0d55a1121f604b8b462b45a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 15:39:05 -0700 Subject: [PATCH 063/149] Move techamp t:$_DFF_?N? to before abc call --- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index abc164533..397c83ac6 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -111,10 +111,10 @@ struct SynthXilinxPass : public Pass log(" dff2dffe\n"); log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); + log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); @@ -261,7 +261,6 @@ struct SynthXilinxPass : public Pass } else { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); } - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); @@ -269,6 +268,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_luts")) { + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); From a5f33b5409d9325730204eb776e0046726d55d2c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 16:20:43 -0700 Subject: [PATCH 064/149] Move dffinit til after abc --- techlibs/xilinx/.synth_xilinx.cc.swn | Bin 24576 -> 0 bytes techlibs/xilinx/.synth_xilinx.cc.swo | Bin 20480 -> 0 bytes techlibs/xilinx/synth_xilinx.cc | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 techlibs/xilinx/.synth_xilinx.cc.swn delete mode 100644 techlibs/xilinx/.synth_xilinx.cc.swo diff --git a/techlibs/xilinx/.synth_xilinx.cc.swn b/techlibs/xilinx/.synth_xilinx.cc.swn deleted file mode 100644 index a6564691a9dd301e314532bf5953acd2a49674ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24576 zcmeI4e~cqneZbukD4UQ#n^vVNf_F~1+s&@Mw|9Yty~`!OUGJ^Mu6JX5?{c||EdLm< zr)PUC&v@@Pm!qwc7H9>cfvQRiw4m}MG=)}z7BvzSAyiU@6p)cN|naC&)V~TeBbwd-;a6oeQ&OO_;hAf-IhEY8+r&REQ-R!u{~clqdacA{$77aXfSI`P|d!r5)h-nM6(CEGDNvyM@zH_Wm7oF5LqCyKxBc)0{`zV;Iyxa{Q|Z4QLiTc6ZemJ*Z%i41M$^?_?LUvj`#i4 zK>W+R>sNZ;tDazAz84&QMHYxG5LqCyKxBc)0+9tG3q%%(ED%{BvOr{k$O8Wh7AWx` zFVE(`FAw7E|NGDXKYVp8_I3Cg{02M(Y54COVzE!dA3+t~08d>Xi@gI*!1J$)#Xbd( z!pGrb@T<^(9L&R8;3l{Zu7yutM|yZ4JOE8N2XBQ8EW=H30KR^0EcP@!2A_o@-iciHVb!=n)d@DY6j4JBzz=b4|PpwgM9HSK)*X~%Ap$IR-yv{vo zwHn*Xtf_<-JQYYExX>B+Q#XxHsZ*(Mt3;)4R4%9lXF}9*{+tL+-!V$n;+D}dsf0>! z6huw?XF)%~>%T4ZC>B>6G@H*EX9WSZYyqNf*QBmzQpg-0=E$Tk24$TsfpJnoeCMs?9~;w+E3*-~YrW}$me)uB9o#|T6OE_}(zuv*(qt7|LA z!U9;NRaI6^|MV=N8m8?eL$lX9R#P=fWuu{7+w}=Mq?_f?jKbK;Xto_JZ1oa{iqjpt zg8@a6UOSZy=b~Y_fx0YPP1=Tm8EDa|B=TMHLn0F*>bU4w)cH=#)8W0Jfy99e-!xUz zE|nXGGFvsHW3(!Un8mJ}HAi*maB@z{9?F<#S$3xp2o79~6;6px$1LmqD1&S$C(^4# z1i}LsW5t&n76X5jU>Vi{S%C{*@T49jHKXKo>4CJlajDHL(KK34si9liY|(J-hT#~& zX~~zcX|$M%97CGT>N@SNqgsX|T}(|%PdT}gSyDB#VN5BzYdX3K=z zlS&fHL_>GksiV|rNV`P2fkwwAE;tPjrIfn-pVY&sqLC+-rRo9<)(> zN?lf0VwYn~mEDS?24o_!-DOl&v|tvDu?cRn-A+rDDvr5j$hyq^rEXWXQp1)Idi|zYpOpTC50xFJIfTRlr5{F^s>smxlHPSgKjx9%66*r^D?tDCx~>(HXQ0$ z!7#1RR4lfh%bZRX(#33QHJx8iEu@Pl)2A}o*hW5+JykrrmdD1uI99OCzm0CyQ1J^! zr)4x|S->Uh@!@bfyx9nik!6~*-DZr0=JW1-5*bss%mV+ETFa?SRxPY$v+0FGW-Y7E zWD3iwu$)#K`Lx8Yr*lhdxz$v5fy*UgGI^C>TPmDM<-}ml12IwT%LzwX8GCsX~4&P3Kd&bbe!{An{ANwNPXkUE)J$rR2Kzo;lSo6hHxV!iB|LgQ>f z<(E?{E82LejlwdLPNvmLCUtTpt+1h6K{0PGeJYh(#2`U)B5Pq~V^OLsax$yyE1C47 z!qPcP&xmram85z6Hc+(3dT#ABV|7u*Q+clAT0=?Xsj-;JFRY|8tC$|SJMz#-D^;=D z+Z}VW&OP07m}d2gz`f%dou+BqEQ5Pd?Y2?k2F%cGFnp{wleF6p+TBju;wGWzZ{|q( zW~rcREc%#D>nz7uu5WfqE#~SO#S_z(S!LGN6R_N*OJ!@z&7oF5LqCyKxBc)0+9tG3q%%(EU>!; zh8=F{>>{4TL02P=L%fT!%Uf()I6IHYwzh;!Oo&r+e!hZVW772`i)&B(f3?ZD-byHH z$Nw8`e4XMtFKUN-rAVU5sVOAM^Z!4v&n$b>{rmsl;`#n7@M~}v{4Cr6Pq5$r5S)iK zcnka#{3m<=-+;&91F!_ovA6#rcmTHG9J~=e$3Ff&a3>svpMl5OyMG_t2Xk;UTo2E& zfB%>82k^VF1#g8D@RRWOI4qulZ^Ap_SD*yTFbl7S|6*VNS=rl%&%g)a9q@M8f(5t( zu7PLR=YJ9&hj&2}if|9S9$sL-|6kxA;Sb@Lp#o=M3S#g)d;i~sFT7`7TzJ0bi3!sS9ubSny42aU&+*4k$(9z%*F9CF?`YDW zcVxs)xg&(SW1wQS*ag#$b6v!~(>~21+pT+PElKCM zR+wSg0o`2;iN?urk0INz&HQ{zlIs+bR~>Qsgq#yQ46yUF8O$Zwr38 zy;^D2!%LG)`zx+@7rL6_B-8$iW1F|g{v?IP^|o$YO}ov!ms*l}*HUG66W6^o35KVj zxno`<1e?GQot~Bk_nOy;z9b0t8aHO$el!gzkNi0X)I2hP|?-;TLH7QE@doai7TKI}3 zIHk9=m`fMu)LrbJW(pjxln}Pt2SV0|Lh?HyLrRK#tRY>&lbA~rG*HH1$ofzkw$OXI z&Yur0X27=Yf7UhYp1IVmK9ox=sN?rwLYb`-HU4+7At@*}*xyFAYl)Llb+@mDim~gQ ztV1hKr_zCyTLn6+*=n#)dQ?sNJHhTTJH5Ny3-TsYIYSs6rJ|sGI6TU^G!aj?l4F_f zm+>OSx|ZoSf~Wr6B6Z^*p{(GcpuR}EBhjJOXc|qcvn}QdjqbGw?Gjcxoo+8@k;A)< z+}Z3gE#>K^?{plqY;aPkH_hn0N$1jVSCN=`<(^;eoxHtRr)>{;4Wg0cRbS@~RbOI8t1q!vt-e0^r1U{m_w=}1NqPQ%1J8@s@k}Yt|Ni^?&-1MR zUHA+5EPMh!0>2Hv2{v>)}iI3BCY-23KGk?t$CjRyYbjz;Ez9cmlo*e-019yWxH~1~1@4_&)px{5yOe zZj8S#YEd( z^D2h88tt_6HI+QBM{oa{iVSH5+D@w);!%tT7MkwbEzI*6m*wV|=)py&oAfGsjn-v1 zg~R9Sy{$?^Yo^zAW2!cCjVjNZu19v#TQ=OG;`&{UI44NsRD`FWP(N;bpc3BYo|drt zvaBr9WSP60ar7PMoGJG87FT+{}xS<(isSxsdkcEBCCzCvO3?=8$d0byzA#Cmx?K8d?X zACqQhsXiuAum89Ub~oi!&a<+p@9(F3?pNO9VBfml(=@ax_O!hB1W4DQT|~0$&%DYi zNyZmbCB0tncVL9i+vBRFMaYsrSS1PGSCu4Vf0e>|-q6Z_U;V*-XxOc+p0|DET}|FP z4JzO}AsK6XTsihi8M|!hZG;X^mF~*Qb44cmHbcixID2|iHN0I%-FU``bZ<89E36`P z-@3Vi^!u!ya=Xsw!)hfK2WIP?hwx$feN*_=KNQFtwq7sO8{S>JE<4`t_II6^g^f;c zt2>_7FV)KHF8Q32oFH=}sLucgEZGW-hH0pDw&rzzJZoj4(Bi|*TAypbT!NoZt9vle9!M{nft rZh+o9nDO2Q)791U?amI8JN*uBb@B!%y8?aNhhaNI`c5`#|LcDMt4eXQ diff --git a/techlibs/xilinx/.synth_xilinx.cc.swo b/techlibs/xilinx/.synth_xilinx.cc.swo deleted file mode 100644 index 6fc27ed3be0e70fedafe56653d4ea02d7b0fba9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI3dyHdM9mlVr$n1ik5{=Qo*)HsKn6|SI6fDa?cjnGaWwssK&h8GoOTBGRrw_D=5{=6opqRI;Ze8 zJ|dkRuWbII{;)_mwqn{V_E=rB9d3;|yj(N%l0CMp8+v1T%wB0YwW54Tl*|2v zg)yN8LJO?l0xhQ+zvy&j*UlYcsBevIVQ+ui{QC2UDMJf{76>g6S|GGQXo1iIp#?$< zgckU}w}8_;S@{TRagtk;lKcIJuJ1Rx&qv*F?_}AYl>00l)N%jso&W!RhN3(Jo&>jm z&jA(u>n)0MKe!K6z&YTl(-q|=Fb@85nxfnb?gn>(JHe-b0dgP--Ve5d&0rI_XEV}+ zo52mB4i19LK^n|}tzZjyW|N{k4Za5+07Z}kqu^}tgCRxH!3AI#41vc^Rg{Op?H~GC1vi5VxEzdu2-pN(M0-%1{BmOsl%XNRT#QBzH6kMy z!v^AkxgYV01&dp)1}mGIW%Hg?GC1iA_dR%`s)pt`yb&1Jw9Il(gqtBL1Vqh-vBLB! zi@U)izVyBauf&?pEzK&|R#?1T8isjPZ!Dtm>UFJAv6*IZ z#+P}y}~G2#T~uw z??-_$-F9YpRY+fKuoADD(7ml{Padyh_#%7{UcZ10v$0Y)TQ+k{SO6AjRG3*6KV1tj zL${qoVD_qI)|sJ|xWT0DI)n|2W*Lq#7@P5W(}9J}cH%&BqGQtlBSqTnRN~H2&Sjt| z%VtrVbC>}wI+B2VDZWRf7^}NU$D+tLopIjPuK2g30Pi|E7;wsmi7P<%;g)cXuew{ZQ z%@9qYH(=SO!5!|OH#`Z8yn(sG;bd2{7BCAcFVwRC7q z-NqdwZf|a9TU9&3D6!k1t97Ir^=KC_8PI4q#rfySo|IIV|4Kc01sah;CsYrSYrXYo z+0vA&#;co^7KVaGvqY20rydi?B}GOKuom?`&CzLSi5c?3cpe>;+w6dNl@SfNq?ftv zZ)fxe2aBG~4PK^xB3s!`u#_WOy>3zumwm^Zw#rz<9LRNhFLbYI4$b;L%?mW^ds#5| zbS?qZtzE6A=B869&X>Akl5})V6GMzfOxGOmD~CFWn6cfrG}%G9D%gj8$-IZLF{J-c zJRV;HuiLjWbW9mqGW80paibX>VGH?UcAuKdr6*Nv`ttM^sjTpvX4{BQGVvqQsd*&E z6imrO`(wlJ#7LNGRr$`Dq;mepWd+0mCcZM)CAL-A)AMd+i}>DWBxT- z70x0@xYgjs7IYg&9_uQQ3T6rPw(&HER{=>HCT4O0MSC${+U!EpH4MgruO{*v(2MG(_qY$-M%}vatGKJKh^lZAYfcQyN3sgr zZyH$5%kJZ4-j9UljC=XTTlOp-XAAVYJRiD9m zmd^j){ry8Y>wgzK2(AHjV1N;D9ykTOh_nB1zzg6ma64EA4zR&ENP;N%Eqnvt0C#{} z!PmeMun6YCS>Rdt0-gkqfuDmff}6qBKm}XCEARn42Yv;92CfEIfiuBounD{XKLGg$ zz5~7uj)N7j75oDJfP2AJ;7YIn&H?WRFTgMGVGswWgCTG#coKer$G~miMsNrm0Q*4% zoDEI}_rXW-O|T3cumH{iXM!`pN#Ir3`48atfNV}ah42$vAhbYef!ECfy*oKIGl_Yy zdk>2pDYmWT9V|9Y?4mCwe<_6w4bg5nnJi<$jLIVl?HOrfS&c@-8MP=*l;_#lMAMn9 zC{A+aA`(SMMugK*>~^bdnJf8P}_vI3~uM zOE_d7NZUcf@wILDAiwP$}sIEh}_c zQ(=Q^t|J*eBNB%raB4EA7I&~Ku>VUJ;J>9192mMn=6XW%t04nw4p$@D#+92>yUX!E z&vnJ)5a8++p{^X%1oXcS>sph==}+4sEZw>YN-S;2n8;ZaGS)I^aPdaVDT>0o)T&lx z@Bo9AJ6b5HzHsBh`Q37Cwlldiwk!6&Mp0v!kcyL5oPg2oQjv+wj0>1wim zwbkH}tNEJiIO90`Ga8q#$&MY8S$vWe)dM(cO{5FO37oYS+`5u~0iH^DE@%b{?E2C? zEyEaK9*n=8fDcY$Ta;)(nmVtW)(Tl;K%#bYq0!n}o!~5n*#f$*&bsSvM*07Y$H>!d z`&uo~bZ&jfe@)kC2ApQ?xkHFZILltIqn6kredyF0C%oj5yw_4CdAZdwmj(BRK~)kW zdaFdi8>$jz?5tAIL?zsFop+P6=bT`FkoT8smE~SW4d|P6h3QwoyTIDE&F6+2uy<*f zvf4cZD&F2(bOZt z1AoK${Bc0%_FKSB;3}{SYy&UjjQ#}pA$S;E0~#O=wu5(qzvH}4=lGw1`@vVh$HB*d z15)4;a1wY9XZA#68~7}^9vlZYFu~>E17HL^kM{c5j00-tQLvE@Rup$y^X7nli_C!TCpTI0?wmT{ zhWoJ;Brek3A-v{N+pAW5vTGq-ozZ*ccdV`_JfDj@WOqgq=dG4qqXU;bebw-m0=L>H zt%xda^T~~$U&s_@iU;7u%^YA&9Ln75BxDr6|MnGwcWg?yhZkvCDym$s6uD)YRy5+f z^%0lU?u`#FE*p&2-`=aKE#6IzXnT1WjE_^=qP)d|r-j97#3wO7uzkWlOVb1oc(Lxc29WawreH2XK-o4 zAF-k0+CGL8DNZ;QHdLIuZ$M!Yaj8wmJz>1{)DoH3v?+}|y11Yw!AM6zJ1%w`!QTX4 z=;$alxZB(^lbET*WY!+|-hHW@;~J(riv7WINczLtL(Ct%I$ql09UZabu2c>NYWmLj zb|>kMXg6nfM5p1kmSd9jBS>`2y|s2<*NTc#q?c-UM~UO2m0~Pcm`%?nlaumwsq^LJ z>%Z*wJa~Ox_UrJ~iMJ-=4ZM!xf2n~k^r?p3FXd5~|IHe2CBUi@jZilF$P&mB^8J!N zB~XIy5-4mPCHNd>fjW?@EHI*bJKd8=$R6-&oU9{b!o$*&+l!^|*U2pwSVoUSjCn3D z&-Dfce9kyH#kxY^7HfwbIuuw;my^Ri9m|c7I7;^9La20kt;2-D(%0wp^7Xj>ZPC}y z#SYT@i~cuMU=H!=(yO0q$8*DVI+i!xI?0>e~s7ZdXovb$Zf}$7UTi>as$wyQW7l*=~?iqwS~Z$w@IuCf`YJzfF6z xhHLX-cc(e*y~DSN_j?-an7D$~r^U?mHuWg6mii(u`DA)>QcQpKDK=33{{Uz)2x Date: Fri, 5 Apr 2019 16:28:14 -0700 Subject: [PATCH 065/149] Fix S0 -> S1 --- passes/techmap/abc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 4876f3009..e2a152348 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1728,7 +1728,7 @@ struct AbcPass : public Pass { signal_init[initsig[i]] = State::S0; break; case State::S1: - signal_init[initsig[i]] = State::S0; + signal_init[initsig[i]] = State::S1; break; default: break; From ad602438b8313c3dd243c5fabf6f20036487d1ba Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 16:28:46 -0700 Subject: [PATCH 066/149] Add retime test --- tests/simple/retime.v | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/simple/retime.v diff --git a/tests/simple/retime.v b/tests/simple/retime.v new file mode 100644 index 000000000..30b6087dc --- /dev/null +++ b/tests/simple/retime.v @@ -0,0 +1,6 @@ +module retime_test(input clk, input [7:0] a, output z); + reg [7:0] ff = 8'hF5; + always @(posedge clk) + ff <= {ff[6:0], ^a}; + assign z = ff[7]; +endmodule From 1d526b7f061fb7e7961fa4d0b318b27cfda469d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 5 Apr 2019 17:35:49 -0700 Subject: [PATCH 067/149] Call shregmap twice -- once for variable, another for fixed --- passes/techmap/shregmap.cc | 46 ++++++++++++--------------------- techlibs/xilinx/cells_map.v | 3 +++ techlibs/xilinx/synth_xilinx.cc | 19 ++++++++------ 3 files changed, 31 insertions(+), 37 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 408e3f8c7..a805ac5a6 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -138,11 +138,8 @@ struct ShregmapTechXilinx7 : ShregmapTech virtual bool analyze(vector &taps, const vector &qbits) override { - log("analyze() with %zu taps", taps.size()); - for (auto t : taps) log(" %d", t); - log("\n"); if (GetSize(taps) == 1) - return taps[0] >= opts.minlen-1; + return taps[0] >= opts.minlen-1 && sigbit_to_shiftx_offset.count(qbits[0]); if (taps.back() < opts.minlen-1) return false; @@ -150,38 +147,31 @@ struct ShregmapTechXilinx7 : ShregmapTech Cell *shiftx = nullptr; int group = 0; for (int i = 0; i < GetSize(taps); ++i) { + auto it = sigbit_to_shiftx_offset.find(qbits[i]); + if (it == sigbit_to_shiftx_offset.end()) + return false; + // Check taps are sequential if (i != taps[i]) return false; // Check taps are not connected to a shift register, // or sequential to the same shift register - auto it = sigbit_to_shiftx_offset.find(qbits[i]); if (i == 0) { - if (it == sigbit_to_shiftx_offset.end()) { + int offset; + std::tie(shiftx,offset,group) = it->second; + if (offset != i) return false; - } - else { - int offset; - std::tie(shiftx,offset,group) = it->second; - if (offset != i) - return false; - } } else { - if (it == sigbit_to_shiftx_offset.end()) { + Cell *shiftx_ = std::get<0>(it->second); + if (shiftx_ != shiftx) + return false; + int offset = std::get<1>(it->second); + if (offset != i) + return false; + int group_ = std::get<2>(it->second); + if (group_ != group) return false; - } - else { - Cell *shiftx_ = std::get<0>(it->second); - if (shiftx_ != shiftx) - return false; - int offset = std::get<1>(it->second); - if (offset != i) - return false; - int group_ = std::get<2>(it->second); - if (group_ != group) - return false; - } } } log_assert(shiftx); @@ -206,9 +196,7 @@ struct ShregmapTechXilinx7 : ShregmapTech auto bit = tap.second; auto it = sigbit_to_shiftx_offset.find(bit); - // If fixed-length, no fixup necessary - if (it == sigbit_to_shiftx_offset.end()) - return true; + log_assert(it != sigbit_to_shiftx_offset.end()); auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_"); newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index c80e51bd0..704ab21b1 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -141,3 +141,6 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o end endgenerate endmodule + +`ifndef SRL_ONLY +`endif diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 2676f5915..57bde998f 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -113,22 +113,23 @@ struct SynthXilinxPass : public Pass log(" dffsr2dff\n"); log(" dff2dffe\n"); log(" opt -full\n"); - log(" simplemap t:$dff t:$dffe (without -nosrl and without -retime only)\n"); - log(" shregmap -tech xilinx -minlen 3 (without -nosrl and without -retime only)\n"); + log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); + log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); - log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); + log(" techmap -map +/techmap.v -map +/xilinx/cells_map.v\n"); log(" clean\n"); log("\n"); log(" map_luts:\n"); log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); - log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); + log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n"); + log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); + log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); + log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); log("\n"); log(" check:\n"); log(" hierarchy -check\n"); @@ -266,7 +267,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); - if (!nosrl && !retime) { + if (!nosrl) { Pass::call(design, "simplemap t:$dff t:$dffe"); Pass::call(design, "shregmap -tech xilinx -minlen 3"); } @@ -292,7 +293,9 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); - Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); + if (!nosrl) + Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); } From 2bf3ca64435b11726d87cc0d34e887a79351ec45 Mon Sep 17 00:00:00 2001 From: David Shah Date: Sun, 7 Apr 2019 16:56:31 +0100 Subject: [PATCH 068/149] memory_bram: Fix multiport make_transp Signed-off-by: David Shah --- passes/memory/memory_bram.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/passes/memory/memory_bram.cc b/passes/memory/memory_bram.cc index 804aa21f9..ddc56d9b5 100644 --- a/passes/memory/memory_bram.cc +++ b/passes/memory/memory_bram.cc @@ -744,7 +744,8 @@ grow_read_ports:; if (clken) { clock_domains[pi.clocks] = clkdom; clock_polarities[pi.clkpol] = clkdom.second; - read_transp[pi.transp] = transp; + if (!pi.make_transp) + read_transp[pi.transp] = transp; pi.sig_clock = clkdom.first; pi.sig_en = rd_en[cell_port_i]; pi.effective_clkpol = clkdom.second; From d3930ca79eb11952d8e64588e46b0788845997c4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 12:01:06 -0700 Subject: [PATCH 069/149] Revert "Remove handling for $pmux, since #895" This reverts commit aa693d5723ef1438d42cd35a26673703b1eff79f. --- passes/techmap/shregmap.cc | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index a805ac5a6..39ca60b80 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -119,6 +119,22 @@ struct ShregmapTechXilinx7 : ShregmapTech for (auto bit : sigmap(cell->getPort("\\B"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); } + else if (cell->type == "$pmux") { + int width = cell->getParam("\\WIDTH").as_int(); + int j = 0; + for (auto bit : cell->getPort("\\A")) + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); + j = cell->getParam("\\S_WIDTH").as_int(); + int k = 0; + for (auto bit : sigmap(cell->getPort("\\B"))) { + sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++); + if (k == width) { + k = 0; + --j; + } + } + log_assert(j == 0); + } } } @@ -130,6 +146,8 @@ struct ShregmapTechXilinx7 : ShregmapTech if (cell) { if (cell->type == "$shiftx" && port == "\\A") return; + if (cell->type == "$pmux" && (port == "\\A" || port == "\\B")) + return; if (cell->type == "$mux" && (port == "\\A" || port == "\\B")) return; } @@ -181,6 +199,10 @@ struct ShregmapTechXilinx7 : ShregmapTech if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; } + else if (shiftx->type == "$pmux") { + if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1) + return false; + } else if (shiftx->type == "$mux") { if (GetSize(taps) != 2) return false; @@ -216,6 +238,24 @@ struct ShregmapTechXilinx7 : ShregmapTech q_wire = shiftx->getPort("\\Y"); shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); } + else if (shiftx->type == "$pmux") { + // Create a new encoder, out of a $pmux, that takes + // the existing pmux's 'S' input and transforms it + // back into a binary value + int clog2taps = ceil(log2(taps.size())); + RTLIL::SigSpec b_port; + for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) + b_port.append(RTLIL::Const(i, clog2taps)); + l_wire = cell->module->addWire(NEW_ID, clog2taps); + RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, shiftx->getParam("\\S_WIDTH").as_int()); + cell->module->connect(s_wire.extract(0, shiftx->getParam("\\S_WIDTH").as_int()), shiftx->getPort("\\S")); + cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, s_wire, l_wire); + int group = std::get<2>(it->second); + RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); + q_wire = y_wire[group]; + y_wire[group] = cell->module->addWire(NEW_ID); + shiftx->setPort("\\Y", y_wire); + } else if (shiftx->type == "$mux") { l_wire = shiftx->getPort("\\S"); q_wire = shiftx->getPort("\\Y"); From 93b16219110d3175ffee1874e6fa0a3cb25383f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 15:57:07 -0700 Subject: [PATCH 070/149] Cope with undoing #895 --- passes/techmap/shregmap.cc | 40 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index 39ca60b80..bd75cd95e 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -96,6 +96,7 @@ struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechXilinx7 : ShregmapTech { dict> sigbit_to_shiftx_offset; + dict sigbit_to_eq_input; const ShregmapOptions &opts; ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} @@ -113,16 +114,17 @@ struct ShregmapTechXilinx7 : ShregmapTech } else if (cell->type == "$mux") { int j = 0; - for (auto bit : cell->getPort("\\A")) + for (auto bit : sigmap(cell->getPort("\\A"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); j = 0; for (auto bit : sigmap(cell->getPort("\\B"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); } else if (cell->type == "$pmux") { + if (!cell->get_bool_attribute("\\shiftx_compatible")) continue; int width = cell->getParam("\\WIDTH").as_int(); int j = 0; - for (auto bit : cell->getPort("\\A")) + for (auto bit : sigmap(cell->getPort("\\A"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); j = cell->getParam("\\S_WIDTH").as_int(); int k = 0; @@ -135,6 +137,15 @@ struct ShregmapTechXilinx7 : ShregmapTech } log_assert(j == 0); } + else if (cell->type == "$eq") { + auto b_wire = cell->getPort("\\B"); + // Keep track of $eq cells that compare against the value 1 + // in anticipation that they drive the select (S) port of a $pmux + if (b_wire.is_fully_const() && b_wire.as_int() == 1) { + auto y_wire = sigmap(cell->getPort("\\Y").as_bit()); + sigbit_to_eq_input[y_wire] = cell->getPort("\\A"); + } + } } } @@ -239,19 +250,20 @@ struct ShregmapTechXilinx7 : ShregmapTech shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); } else if (shiftx->type == "$pmux") { - // Create a new encoder, out of a $pmux, that takes - // the existing pmux's 'S' input and transforms it - // back into a binary value - int clog2taps = ceil(log2(taps.size())); - RTLIL::SigSpec b_port; - for (int i = shiftx->getParam("\\S_WIDTH").as_int(); i > 0; i--) - b_port.append(RTLIL::Const(i, clog2taps)); - l_wire = cell->module->addWire(NEW_ID, clog2taps); - RTLIL::SigSpec s_wire = cell->module->addWire(NEW_ID, shiftx->getParam("\\S_WIDTH").as_int()); - cell->module->connect(s_wire.extract(0, shiftx->getParam("\\S_WIDTH").as_int()), shiftx->getPort("\\S")); - cell->module->addPmux(NEW_ID, RTLIL::Const(0, clog2taps), b_port, s_wire, l_wire); - int group = std::get<2>(it->second); + // If the 'A' port is fully undef, then opt_expr -mux_undef + // has not been applied, so find the second-to-last bit of + // the 'S' port (corresponding to $eq cell comparing for 1) + // otherwise use the last bit of 'S' + const auto& s_wire_bits = shiftx->getPort("\\S").bits(); + SigBit s1; + if (shiftx->getPort("\\A").is_fully_undef()) + s1 = s_wire_bits[s_wire_bits.size() - 2]; + else + s1 = s_wire_bits[s_wire_bits.size() - 1]; RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); + l_wire = sigbit_to_eq_input.at(s1); + log_assert(l_wire.size() == ceil(log2(taps.size()))); + int group = std::get<2>(it->second); q_wire = y_wire[group]; y_wire[group] = cell->module->addWire(NEW_ID); shiftx->setPort("\\Y", y_wire); From 13fc70d7a44965fc87aa76682b32d4961efb093d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 16:05:24 -0700 Subject: [PATCH 071/149] Undo #895 by instead setting an attribute --- passes/proc/proc_mux.cc | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index bac2dc2cd..6ac59bfb2 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -360,23 +360,9 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d } } - // Transform into a $shiftx where possible - if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") { - // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement - auto pmux_b_port = last_mux_cell->getPort("\\B"); - auto pmux_y_port = last_mux_cell->getPort("\\Y"); - int width = last_mux_cell->getParam("\\WIDTH").as_int(); - for (int i = 0; i < width; ++i) { - RTLIL::SigSpec a_port; - // Because we went in reverse order above, un-reverse $pmux's B port here - for (int j = pmux_b_port.size()/width-1; j >= 0; --j) - a_port.append(pmux_b_port.extract(j*width+i, 1)); - // Create a $shiftx that shifts by the address line used in the case statement - mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1)); - } - // Disconnect $pmux by replacing its output port with a floating wire - last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width)); - } + // Mark this pmux as being $shiftx compatible + if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") + last_mux_cell->set_bool_attribute("\\shiftx_compatible"); } return result; From f6c354c55bcba26978c8dd04c3cc4f02231aebe4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 16:22:07 -0700 Subject: [PATCH 072/149] Update CHANGELOG --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 95bbb3f33..36b64e111 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,7 +16,7 @@ Yosys 0.8 .. Yosys 0.8-dev - Added "gate2lut.v" techmap rule - Added "rename -src" - Added "equiv_opt" pass - - Added "shregmap -tech xilinx", used by "synth_xilinx" + - "synth_xilinx" to now infer hard shift registers, using new "shregmap -tech xilinx" Yosys 0.7 .. Yosys 0.8 From 6797f6b6c4660622dbde27ced83fdd37a874f00d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 16:24:20 -0700 Subject: [PATCH 073/149] $_XILINX_SHREG_ to preserve src attribute --- passes/techmap/shregmap.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index bd75cd95e..ec43b5654 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -232,6 +232,7 @@ struct ShregmapTechXilinx7 : ShregmapTech log_assert(it != sigbit_to_shiftx_offset.end()); auto newcell = cell->module->addCell(NEW_ID, "$__XILINX_SHREG_"); + newcell->set_src_attribute(cell->get_src_attribute()); newcell->setParam("\\DEPTH", cell->getParam("\\DEPTH")); newcell->setParam("\\INIT", cell->getParam("\\INIT")); newcell->setParam("\\CLKPOL", cell->getParam("\\CLKPOL")); From 0deaccbaae436bc94ad5b2913fa39a9368c09ace Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 8 Apr 2019 16:46:33 -0700 Subject: [PATCH 074/149] Fix a few typos --- passes/pmgen/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 223b43059..7a46558b1 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -83,8 +83,8 @@ They are declared like state variables, just using the `udata` statement: udata min_data_width max_data_width udata data_port_name -They are atomatically initialzed to the default constructed value of their type -when ther pattern matcher object is constructed. +They are automatically initialized to the default constructed value of their type +when the pattern matcher object is constructed. Embedded C++ code ----------------- @@ -158,7 +158,7 @@ Finally, `filter ` narrows down the remaining list of cells. For performance reasons `filter` statements should only be used for things that can't be done using `select` and `index`. -The `optional` statement marks optional matches. I.e. the matcher will also +The `optional` statement marks optional matches. That is, the matcher will also explore the case where `mul` is set to `nullptr`. Without the `optional` statement a match may only be assigned nullptr when one of the `if` expressions evaluates to `false`. From 5e0339855fc1f83b98694ed37dd2f195c3d8f52c Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 9 Apr 2019 09:01:53 -0700 Subject: [PATCH 075/149] Add additional cells sim models for core 7-series primatives. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- techlibs/xilinx/cells_sim.v | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index ff5ff0726..315fd54c8 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -30,10 +30,15 @@ module GND(output G); endmodule module IBUF(output O, input I); + parameter IOSTANDARD = "default"; + parameter IBUF_LOW_PWR = 0; assign O = I; endmodule module OBUF(output O, input I); + parameter IOSTANDARD = "default"; + parameter DRIVE = 12; + parameter SLEW = "SLOW"; assign O = I; endmodule @@ -41,6 +46,42 @@ module BUFG(output O, input I); assign O = I; endmodule +module BUFGCTRL( + output O, + input I0, input I1, + input S0, input S1, + input CE0, input CE1, + input IGNORE0, input IGNORE1); + +parameter INIT_OUT = 0; +parameter PRESELECT_I0 = 0; +parameter PRESELECT_I1 = 0; +parameter IS_CE0_INVERTED = 0; +parameter IS_CE1_INVERTED = 0; +parameter IS_S0_INVERTED = 0; +parameter IS_S1_INVERTED = 0; +parameter IS_IGNORE0_INVERTED = 0; +parameter IS_IGNORE1_INVERTED = 0; + +wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT); +wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT); +wire S0_true = (S0 ^ IS_S0_INVERTED); +wire S1_true = (S1 ^ IS_S1_INVERTED); + +assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT); + +endmodule + +module BUFHCE(output O, input I, input CE); + +parameter INIT_OUT = 0; +parameter CE_TYPE = "SYNC"; +parameter IS_CE_INVERTED = 0; + +assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT); + +endmodule + // module OBUFT(output O, input I, T); // assign O = T ? 1'bz : I; // endmodule @@ -98,6 +139,22 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5); assign O = I0 ? s1[1] : s1[0]; endmodule +module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5); + parameter [63:0] INIT = 0; + wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0]; + wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0]; + wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O6 = I0 ? s1[1] : s1[0]; + + wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0]; + wire [ 7: 0] s5_3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s5_2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s5_1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O5 = I0 ? s5_1[1] : s5_1[0]; +endmodule + module MUXCY(output O, input CI, DI, S); assign O = S ? CI : DI; endmodule From 5855024cccfbcb1919e3225f519bc9f0421c4056 Mon Sep 17 00:00:00 2001 From: Zachary Snow Date: Tue, 9 Apr 2019 12:28:32 -0400 Subject: [PATCH 076/149] support repeat loops with constant repeat counts outside of constant functions --- frontends/ast/simplify.cc | 21 +++++++++++++++++++- tests/sat/counters-repeat.v | 38 ++++++++++++++++++++++++++++++++++++ tests/sat/counters-repeat.ys | 10 ++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tests/sat/counters-repeat.v create mode 100644 tests/sat/counters-repeat.ys diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 63b71b800..76da5a97c 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1030,7 +1030,26 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, log_file_error(filename, linenum, "While loops are only allowed in constant functions!\n"); if (type == AST_REPEAT) - log_file_error(filename, linenum, "Repeat loops are only allowed in constant functions!\n"); + { + AstNode *count = children[0]; + AstNode *body = children[1]; + + // eval count expression + while (count->simplify(true, false, false, stage, 32, true, false)) { } + + if (count->type != AST_CONSTANT) + log_file_error(filename, linenum, "Repeat loops outside must have constant repeat counts!\n"); + + // convert to a block with the body repeated n times + type = AST_BLOCK; + children.clear(); + for (int i = 0; i < count->bitsAsConst().as_int(); i++) + children.insert(children.begin(), body->clone()); + + delete count; + delete body; + did_something = true; + } // unroll for loops and generate-for blocks if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0) diff --git a/tests/sat/counters-repeat.v b/tests/sat/counters-repeat.v new file mode 100644 index 000000000..2ea45499a --- /dev/null +++ b/tests/sat/counters-repeat.v @@ -0,0 +1,38 @@ +// coverage for repeat loops outside of constant functions + +module counter1(clk, rst, ping); + input clk, rst; + output ping; + reg [31:0] count; + + always @(posedge clk) begin + if (rst) + count <= 0; + else + count <= count + 1; + end + + assign ping = &count; +endmodule + +module counter2(clk, rst, ping); + input clk, rst; + output ping; + reg [31:0] count; + + integer i; + reg carry; + + always @(posedge clk) begin + carry = 1; + i = 0; + repeat (32) begin + count[i] <= !rst & (count[i] ^ carry); + carry = count[i] & carry; + i = i+1; + end + end + + assign ping = &count; +endmodule + diff --git a/tests/sat/counters-repeat.ys b/tests/sat/counters-repeat.ys new file mode 100644 index 000000000..b3dcfe08a --- /dev/null +++ b/tests/sat/counters-repeat.ys @@ -0,0 +1,10 @@ + +read_verilog counters-repeat.v +proc; opt + +expose -shared counter1 counter2 +miter -equiv -make_assert -make_outputs counter1 counter2 miter + +cd miter; flatten; opt +sat -verify -prove-asserts -tempinduct -set-at 1 in_rst 1 -seq 1 -show-inputs -show-outputs + From e107ccdde82247e28c9c994240e4d4bf694f673f Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Tue, 9 Apr 2019 11:43:19 -0700 Subject: [PATCH 077/149] Fix LUT6_2 definition. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- techlibs/xilinx/cells_sim.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 315fd54c8..c96e0d8f1 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -149,9 +149,9 @@ module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5); assign O6 = I0 ? s1[1] : s1[0]; wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0]; - wire [ 7: 0] s5_3 = I3 ? s4[15: 8] : s4[ 7: 0]; - wire [ 3: 0] s5_2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; - wire [ 1: 0] s5_1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0]; + wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0]; + wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0]; assign O5 = I0 ? s5_1[1] : s5_1[0]; endmodule From 78d35a86c0e94f1c5e1606f9953d1f340132f02e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Apr 2019 08:31:35 -0700 Subject: [PATCH 078/149] Revert ""&nf -D 0" fails => use "-D 1" instead" This reverts commit 3c253818cab2013dc4db55732d3e21cfa0dc3f19. --- passes/techmap/abc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index e2a152348..f94fc7589 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1675,7 +1675,7 @@ struct AbcPass : public Pass { if (arg == "-dff") { dff_mode = true; if (delay_target.empty()) - delay_target = "-D 1"; + delay_target = "-D 0"; continue; } if (arg == "-clk" && argidx+1 < args.size()) { From 5f4024ffd2a59e3c0c7edce4057c47d3a005e18f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Apr 2019 08:31:40 -0700 Subject: [PATCH 079/149] Revert "abc -dff now implies "-D 0" otherwise retiming doesn't happen" This reverts commit 19271bd996a79cb4be1db658fcf18227ee0a1dff. --- passes/techmap/abc.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index f94fc7589..3adbe0a04 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -1674,8 +1674,6 @@ struct AbcPass : public Pass { } if (arg == "-dff") { dff_mode = true; - if (delay_target.empty()) - delay_target = "-D 0"; continue; } if (arg == "-clk" && argidx+1 < args.size()) { From 9a6da9a79a22e984ee3eec02caa230b66f10e11a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 10 Apr 2019 08:32:53 -0700 Subject: [PATCH 080/149] synth_* with -retime option now calls abc with -D 1 as well --- techlibs/achronix/synth_achronix.cc | 4 ++-- techlibs/anlogic/synth_anlogic.cc | 2 +- techlibs/coolrunner2/synth_coolrunner2.cc | 2 +- techlibs/easic/synth_easic.cc | 2 +- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/gowin/synth_gowin.cc | 2 +- techlibs/greenpak4/synth_greenpak4.cc | 2 +- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/intel/synth_intel.cc | 6 +++--- techlibs/sf2/synth_sf2.cc | 2 +- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 626860d9c..3dbf20911 100755 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -152,12 +152,12 @@ struct SynthAchronixPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); + run("abc -markgroups -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) { - run("abc -lut 4" + string(retime ? " -dff" : "")); + run("abc -lut 4" + string(retime ? " -dff -D 1" : "")); run("clean"); } diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index 620bf3965..258e3d722 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -164,7 +164,7 @@ struct SynthAnlogicPass : public ScriptPass run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/anlogic/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc index 21bbcaef4..fa4fe0f5b 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cc +++ b/techlibs/coolrunner2/synth_coolrunner2.cc @@ -161,7 +161,7 @@ struct SynthCoolrunner2Pass : public ScriptPass if (check_label("map_pla")) { - run("abc -sop -I 40 -P 56"); + run("abc -sop -I 40 -P 56" + string(retime ? " -dff -D 1" : "")); run("clean"); } diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc index dd9e3dab7..7bacc7890 100644 --- a/techlibs/easic/synth_easic.cc +++ b/techlibs/easic/synth_easic.cc @@ -158,7 +158,7 @@ struct SynthEasicPass : public ScriptPass run("techmap"); run("opt -fast"); if (retime || help_mode) { - run("abc -dff", " (only if -retime)"); + run("abc -dff -D 1", " (only if -retime)"); run("opt_clean", "(only if -retime)"); } } diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 4b889d672..45f101451 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -242,7 +242,7 @@ struct SynthEcp5Pass : public ScriptPass else run("techmap -map +/techmap.v -map +/ecp5/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 9a3fcdbb6..0ebd77d63 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -163,7 +163,7 @@ struct SynthGowinPass : public ScriptPass run("splitnets -ports"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index eeb001b46..3222be2e3 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -165,7 +165,7 @@ struct SynthGreenPAK4Pass : public ScriptPass run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); run("opt -fast"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 8899bfcc4..d114b6269 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -274,7 +274,7 @@ struct SynthIce40Pass : public ScriptPass else run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); run("ice40_opt"); } diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index 0f1d7a7b5..290282bd9 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -210,15 +210,15 @@ struct SynthIntelPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); + run("abc -markgroups -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) { if(family_opt=="a10gx" || family_opt=="cyclonev") - run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff -D 1" : "")); else - run("abc -lut 4" + string(retime ? " -dff" : "")); + run("abc -lut 4" + string(retime ? " -dff -D 1" : "")); run("clean"); } diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 0924df7a6..3c5a58b4c 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -181,7 +181,7 @@ struct SynthSf2Pass : public ScriptPass run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/sf2/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 397c83ac6..a462b9052 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -115,7 +115,7 @@ struct SynthXilinxPass : public Pass log("\n"); log(" map_luts:\n"); log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff -D 1]\n"); log(" clean\n"); log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); log("\n"); @@ -269,7 +269,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_luts")) { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff -D 1" : "")); Pass::call(design, "clean"); Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); } From adc6efb58468a7e2f85f756d4a9d4686ad0a8c45 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 12:34:51 -0700 Subject: [PATCH 081/149] Recognise default entry in case even if all cases covered (#931) --- passes/proc/proc_rmdead.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc index 7c334e661..d2f8d9ead 100644 --- a/passes/proc/proc_rmdead.cc +++ b/passes/proc/proc_rmdead.cc @@ -34,7 +34,7 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) for (size_t i = 0; i < sw->cases.size(); i++) { - bool is_default = GetSize(sw->cases[i]->compare) == 0 && (!pool.empty() || GetSize(sw->signal) == 0); + bool is_default = GetSize(sw->cases[i]->compare) == 0 || GetSize(sw->signal) == 0; for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) { RTLIL::SigSpec sig = sw->cases[i]->compare[j]; From 7685469ee2f7bc038c4fd6fe98f93eb08d6fac7c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 15:03:40 -0700 Subject: [PATCH 082/149] Add default entry to testcase --- tests/various/muxcover.ys | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index 7ac460f13..594e62af6 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -8,12 +8,13 @@ read_verilog -formal < Date: Thu, 11 Apr 2019 15:09:13 -0700 Subject: [PATCH 083/149] Spelling fixes --- passes/techmap/pmuxtree.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index b7a22dc3b..6a923f481 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -71,9 +71,9 @@ struct PmuxtreePass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" pmuxtree [options] [selection]\n"); + log(" pmuxtree [selection]\n"); log("\n"); - log("This pass transforms $pmux cells to a trees of $mux cells.\n"); + log("This pass transforms $pmux cells to trees of $mux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE From e8c26f2839611f5b52c29f711670888b02066064 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 15:52:04 -0700 Subject: [PATCH 084/149] WIP --- passes/techmap/Makefile.inc | 1 + passes/techmap/pmux2shiftx.cc | 88 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 passes/techmap/pmux2shiftx.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index cf9e198ad..81df499da 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,6 +37,7 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o +OBJS += passes/techmap/pmux2shiftx.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc new file mode 100644 index 000000000..6569f995f --- /dev/null +++ b/passes/techmap/pmux2shiftx.cc @@ -0,0 +1,88 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Pmux2ShiftxPass : public Pass { + Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" pmux2shiftx [selection]\n"); + log("\n"); + log("This pass transforms $pmux cells to $shiftx cells.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PMUX2SHIFTX pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + { + if (cell->type != "$pmux") + continue; + + // Create a new encoder, out of a $pmux, that takes + // the existing pmux's 'S' input and transforms it + // back into a binary value + const int s_width = cell->getParam("\\S_WIDTH").as_int(); + const int width = cell->getParam("\\WIDTH").as_int(); + const int clog2width = ceil(log2(s_width)); + RTLIL::SigSpec shiftx_a; + RTLIL::SigSpec pmux_a; + RTLIL::SigSpec pmux_b; + RTLIL::SigSpec b_port = cell->getPort("\\B"); + if (!cell->getPort("\\A").is_fully_undef()) { + pmux_a = RTLIL::Const(RTLIL::S0, clog2width); + shiftx_a.append(cell->getPort("\\A")); + for (int i = s_width; i > 0; i--) { + shiftx_a.append(b_port.extract((i-1)*width, width)); + pmux_b.append(RTLIL::Const(i, clog2width)); + } + + } + else { + pmux_a = RTLIL::Const(RTLIL::Sx, clog2width); + for (int i = s_width-1; i >= 0; i--) { + shiftx_a.append(b_port.extract(i*width, width)); + pmux_b.append(RTLIL::Const(i, clog2width)); + } + } + RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); + RTLIL::SigSpec shiftx_s = module->addWire(NEW_ID, 1 << clog2width); + module->addPmux(NEW_ID, pmux_a, pmux_b, cell->getPort("\\S"), pmux_y); + module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); + module->remove(cell); + } + } +} Pmux2ShiftxPass; + +PRIVATE_NAMESPACE_END From b1f1db2fcf0e27fbd9cb7b94ab5c9d8879ad9694 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 16:17:09 -0700 Subject: [PATCH 085/149] Fixes --- passes/techmap/pmux2shiftx.cc | 38 ++++++++++++++++------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc index 6569f995f..9b05f8f6d 100644 --- a/passes/techmap/pmux2shiftx.cc +++ b/passes/techmap/pmux2shiftx.cc @@ -53,32 +53,28 @@ struct Pmux2ShiftxPass : public Pass { // Create a new encoder, out of a $pmux, that takes // the existing pmux's 'S' input and transforms it // back into a binary value - const int s_width = cell->getParam("\\S_WIDTH").as_int(); + RTLIL::SigSpec shiftx_a; + RTLIL::SigSpec pmux_s; + + int s_width = cell->getParam("\\S_WIDTH").as_int(); + if (!cell->getPort("\\A").is_fully_undef()) { + ++s_width; + shiftx_a.append(cell->getPort("\\A")); + pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); + } const int width = cell->getParam("\\WIDTH").as_int(); const int clog2width = ceil(log2(s_width)); - RTLIL::SigSpec shiftx_a; - RTLIL::SigSpec pmux_a; - RTLIL::SigSpec pmux_b; - RTLIL::SigSpec b_port = cell->getPort("\\B"); - if (!cell->getPort("\\A").is_fully_undef()) { - pmux_a = RTLIL::Const(RTLIL::S0, clog2width); - shiftx_a.append(cell->getPort("\\A")); - for (int i = s_width; i > 0; i--) { - shiftx_a.append(b_port.extract((i-1)*width, width)); - pmux_b.append(RTLIL::Const(i, clog2width)); - } - } - else { - pmux_a = RTLIL::Const(RTLIL::Sx, clog2width); - for (int i = s_width-1; i >= 0; i--) { - shiftx_a.append(b_port.extract(i*width, width)); - pmux_b.append(RTLIL::Const(i, clog2width)); - } - } + RTLIL::SigSpec pmux_b; + pmux_b.append(RTLIL::Const(0, clog2width)); + for (int i = s_width-1; i > 0; i--) + pmux_b.append(RTLIL::Const(i, clog2width)); + shiftx_a.append(cell->getPort("\\B")); + pmux_s.append(cell->getPort("\\S")); + RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); RTLIL::SigSpec shiftx_s = module->addWire(NEW_ID, 1 << clog2width); - module->addPmux(NEW_ID, pmux_a, pmux_b, cell->getPort("\\S"), pmux_y); + module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); module->remove(cell); } From b15b410b41cca3a79bfcfc9c91f665815f31ab5b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 16:18:01 -0700 Subject: [PATCH 086/149] Remove unused --- passes/techmap/pmux2shiftx.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc index 9b05f8f6d..08cb06d5f 100644 --- a/passes/techmap/pmux2shiftx.cc +++ b/passes/techmap/pmux2shiftx.cc @@ -73,7 +73,6 @@ struct Pmux2ShiftxPass : public Pass { pmux_s.append(cell->getPort("\\S")); RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); - RTLIL::SigSpec shiftx_s = module->addWire(NEW_ID, 1 << clog2width); module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); module->remove(cell); From f587950bde58b326e1f7319c84d5652a0dc43216 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 16:20:43 -0700 Subject: [PATCH 087/149] More unused --- passes/techmap/pmux2shiftx.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc index 08cb06d5f..f8cdf5783 100644 --- a/passes/techmap/pmux2shiftx.cc +++ b/passes/techmap/pmux2shiftx.cc @@ -62,7 +62,6 @@ struct Pmux2ShiftxPass : public Pass { shiftx_a.append(cell->getPort("\\A")); pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); } - const int width = cell->getParam("\\WIDTH").as_int(); const int clog2width = ceil(log2(s_width)); RTLIL::SigSpec pmux_b; From 3c1f1a6605a4463117ba358fc9528c4999628b81 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 16:25:59 -0700 Subject: [PATCH 088/149] Fix ordering of when to insert zero index --- passes/techmap/pmux2shiftx.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc index f8cdf5783..6ffc27a4c 100644 --- a/passes/techmap/pmux2shiftx.cc +++ b/passes/techmap/pmux2shiftx.cc @@ -65,8 +65,7 @@ struct Pmux2ShiftxPass : public Pass { const int clog2width = ceil(log2(s_width)); RTLIL::SigSpec pmux_b; - pmux_b.append(RTLIL::Const(0, clog2width)); - for (int i = s_width-1; i > 0; i--) + for (int i = s_width-1; i >= 0; i--) pmux_b.append(RTLIL::Const(i, clog2width)); shiftx_a.append(cell->getPort("\\B")); pmux_s.append(cell->getPort("\\S")); From 643ae9bfc534c20444dfcd33083c6c188c2f1ec8 Mon Sep 17 00:00:00 2001 From: Diego Date: Thu, 11 Apr 2019 19:59:03 -0500 Subject: [PATCH 089/149] Fixing issues in CycloneV cell sim --- techlibs/intel/cyclonev/cells_sim.v | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v index fa27c2c8e..9b2a10e72 100644 --- a/techlibs/intel/cyclonev/cells_sim.v +++ b/techlibs/intel/cyclonev/cells_sim.v @@ -85,7 +85,7 @@ module cyclonev_lcell_comb begin upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad); lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad); - lut5 = (datae) ? upper_mask_value : lower_mask_value; + lut5 = (datae) ? upper_lut_value : lower_lut_value; end endfunction // lut5 @@ -95,15 +95,16 @@ module cyclonev_lcell_comb input dataa, datab, datac, datad, datae, dataf; reg upper_lut_value; reg lower_lut_value; + reg out_0, out_1, out_2, out_3; begin upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae); lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae); - lut6 = (dataf) ? upper_mask_value : lower_mask_value; + lut6 = (dataf) ? upper_lut_value : lower_lut_value; end endfunction // lut6 assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]}; - +`ifdef ADVANCED_ALM always @(*) begin if(extended_lut == "on") shared_lut_alm = datag; @@ -115,6 +116,11 @@ module cyclonev_lcell_comb out_2 = lut4(mask_c, dataa, datab, datac, datad); out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad); end +`else + `ifdef DEBUG + initial $display("Advanced ALM lut combine is not implemented yet"); + `endif +`endif endmodule // cyclonev_lcell_comb From 1f9235ede5d5fee4ce0ad13c2905f624e9493426 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 12 Apr 2019 09:30:49 -0700 Subject: [PATCH 090/149] Remove BUFGCTRL, BUFHCE and LUT6_2 from cells_xtra. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- techlibs/xilinx/cells_sim.v | 22 ++++++++++---------- techlibs/xilinx/cells_xtra.sh | 6 +++--- techlibs/xilinx/cells_xtra.v | 38 ----------------------------------- 3 files changed, 14 insertions(+), 52 deletions(-) diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index c96e0d8f1..0c8f282a4 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -53,15 +53,15 @@ module BUFGCTRL( input CE0, input CE1, input IGNORE0, input IGNORE1); -parameter INIT_OUT = 0; -parameter PRESELECT_I0 = 0; -parameter PRESELECT_I1 = 0; -parameter IS_CE0_INVERTED = 0; -parameter IS_CE1_INVERTED = 0; -parameter IS_S0_INVERTED = 0; -parameter IS_S1_INVERTED = 0; -parameter IS_IGNORE0_INVERTED = 0; -parameter IS_IGNORE1_INVERTED = 0; +parameter [0:0] INIT_OUT = 1'b0; +parameter PRESELECT_I0 = "FALSE"; +parameter PRESELECT_I1 = "FALSE"; +parameter [0:0] IS_CE0_INVERTED = 1'b0; +parameter [0:0] IS_CE1_INVERTED = 1'b0; +parameter [0:0] IS_S0_INVERTED = 1'b0; +parameter [0:0] IS_S1_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT); wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT); @@ -74,9 +74,9 @@ endmodule module BUFHCE(output O, input I, input CE); -parameter INIT_OUT = 0; +parameter [0:0] INIT_OUT = 1'b0; parameter CE_TYPE = "SYNC"; -parameter IS_CE_INVERTED = 0; +parameter [0:0] IS_CE_INVERTED = 1'b0; assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT); diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 56520ea10..8b06c3155 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -28,12 +28,12 @@ function xtract_cell_decl() # xtract_cell_decl BUFG xtract_cell_decl BUFGCE xtract_cell_decl BUFGCE_1 - xtract_cell_decl BUFGCTRL + #xtract_cell_decl BUFGCTRL xtract_cell_decl BUFGMUX xtract_cell_decl BUFGMUX_1 xtract_cell_decl BUFGMUX_CTRL xtract_cell_decl BUFH - xtract_cell_decl BUFHCE + #xtract_cell_decl BUFHCE xtract_cell_decl BUFIO xtract_cell_decl BUFMR xtract_cell_decl BUFMRCE @@ -92,7 +92,7 @@ function xtract_cell_decl() # xtract_cell_decl LUT4 # xtract_cell_decl LUT5 # xtract_cell_decl LUT6 - xtract_cell_decl LUT6_2 + #xtract_cell_decl LUT6_2 xtract_cell_decl MMCME2_ADV xtract_cell_decl MMCME2_BASE # xtract_cell_decl MUXF7 diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 497518d35..4fb6798be 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -30,29 +30,6 @@ module BUFGCE_1 (...); input CE, I; endmodule -module BUFGCTRL (...); - output O; - input CE0; - input CE1; - input I0; - input I1; - input IGNORE0; - input IGNORE1; - input S0; - input S1; - parameter integer INIT_OUT = 0; - parameter PRESELECT_I0 = "FALSE"; - parameter PRESELECT_I1 = "FALSE"; - parameter [0:0] IS_CE0_INVERTED = 1'b0; - parameter [0:0] IS_CE1_INVERTED = 1'b0; - parameter [0:0] IS_I0_INVERTED = 1'b0; - parameter [0:0] IS_I1_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; - parameter [0:0] IS_S0_INVERTED = 1'b0; - parameter [0:0] IS_S1_INVERTED = 1'b0; -endmodule - module BUFGMUX (...); parameter CLK_SEL_TYPE = "SYNC"; output O; @@ -77,15 +54,6 @@ module BUFH (...); input I; endmodule -module BUFHCE (...); - parameter CE_TYPE = "SYNC"; - parameter integer INIT_OUT = 0; - parameter [0:0] IS_CE_INVERTED = 1'b0; - output O; - input CE; - input I; -endmodule - module BUFIO (...); output O; input I; @@ -2420,12 +2388,6 @@ module LDPE (...); input D, G, GE, PRE; endmodule -module LUT6_2 (...); - parameter [63:0] INIT = 64'h0000000000000000; - input I0, I1, I2, I3, I4, I5; - output O5, O6; -endmodule - module MMCME2_ADV (...); parameter BANDWIDTH = "OPTIMIZED"; parameter real CLKFBOUT_MULT_F = 5.000; From f9272fc56d7179f04a9f776bf056eedfc33dd358 Mon Sep 17 00:00:00 2001 From: Diego Date: Fri, 12 Apr 2019 23:40:02 -0500 Subject: [PATCH 091/149] GoWin enablement: DRAM, initial BRAM, DRAM init, DRAM sim and synth_gowin flow --- techlibs/gowin/Makefile.inc | 10 +++ techlibs/gowin/bram.txt | 29 +++++++ techlibs/gowin/brams_init3.vh | 12 +++ techlibs/gowin/brams_map.v | 103 ++++++++++++++++++++++++ techlibs/gowin/cells_map.v | 6 +- techlibs/gowin/cells_sim.v | 134 +++++++++++++++++++++++++++++++ techlibs/gowin/determine_init.cc | 72 +++++++++++++++++ techlibs/gowin/dram.txt | 17 ++++ techlibs/gowin/drams_map.v | 31 +++++++ techlibs/gowin/synth_gowin.cc | 56 ++++++++++--- 10 files changed, 459 insertions(+), 11 deletions(-) create mode 100644 techlibs/gowin/bram.txt create mode 100644 techlibs/gowin/brams_init3.vh create mode 100644 techlibs/gowin/brams_map.v create mode 100644 techlibs/gowin/determine_init.cc create mode 100644 techlibs/gowin/dram.txt create mode 100644 techlibs/gowin/drams_map.v diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 2f82def7d..6f2159349 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -1,7 +1,17 @@ OBJS += techlibs/gowin/synth_gowin.o +OBJS += techlibs/gowin/determine_init.o + $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt)) + + + +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh)) diff --git a/techlibs/gowin/bram.txt b/techlibs/gowin/bram.txt new file mode 100644 index 000000000..b5f9a981c --- /dev/null +++ b/techlibs/gowin/bram.txt @@ -0,0 +1,29 @@ +bram $__GW1NR_SDP +# uncomment when done +# init 1 + abits 10 @a10d18 + dbits 16 @a10d18 + abits 11 @a11d9 + dbits 8 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + groups 2 + ports 1 1 + wrmode 1 0 + enable 1 1 @a10d18 + enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +match $__GW1NR_SDP + min bits 2048 + min efficiency 5 + shuffle_enable B + make_transp +endmatch diff --git a/techlibs/gowin/brams_init3.vh b/techlibs/gowin/brams_init3.vh new file mode 100644 index 000000000..84397fa24 --- /dev/null +++ b/techlibs/gowin/brams_init3.vh @@ -0,0 +1,12 @@ +localparam [15:0] INIT_0 = { + INIT[ 60], INIT[ 56], INIT[ 52], INIT[ 48], INIT[ 44], INIT[ 40], INIT[ 36], INIT[ 32], INIT[ 28], INIT[ 24], INIT[ 20], INIT[ 16], INIT[ 12], INIT[ 8], INIT[ 4], INIT[ 0] +}; +localparam [15:0] INIT_1 = { + INIT[ 61], INIT[ 57], INIT[ 53], INIT[ 49], INIT[ 45], INIT[ 41], INIT[ 37], INIT[ 33], INIT[ 29], INIT[ 25], INIT[ 21], INIT[ 17], INIT[ 13], INIT[ 9], INIT[ 5], INIT[ 1] +}; +localparam [15:0] INIT_2 = { + INIT[ 62], INIT[ 58], INIT[ 54], INIT[ 50], INIT[ 46], INIT[ 42], INIT[ 38], INIT[ 34], INIT[ 30], INIT[ 26], INIT[ 22], INIT[ 18], INIT[ 14], INIT[ 10], INIT[ 6], INIT[ 2] +}; +localparam [15:0] INIT_3 = { + INIT[ 63], INIT[ 59], INIT[ 55], INIT[ 51], INIT[ 47], INIT[ 43], INIT[ 39], INIT[ 35], INIT[ 31], INIT[ 27], INIT[ 23], INIT[ 19], INIT[ 15], INIT[ 11], INIT[ 7], INIT[ 3] +}; diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v new file mode 100644 index 000000000..e963cfa88 --- /dev/null +++ b/techlibs/gowin/brams_map.v @@ -0,0 +1,103 @@ +/* Semi Dual Port (SDP) memory have the following configurations: + * Memory Config RAM(BIT) Port Mode Memory Depth Data Depth + * ----------------|---------| ----------|--------------|------------| + * B-SRAM_16K_SD1 16K 16Kx1 16,384 1 + * B-SRAM_8K_SD2 16K 8Kx2 8,192 2 + * B-SRAM_4K_SD4 16K 4Kx2 4,096 4 + */ +module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 16; + parameter CFG_ENABLE_A = 3; + + parameter [16383:0] INIT = 16384'hx; + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + input [CFG_DBITS-1:0] A1DATA; + input [CFG_ENABLE_A-1:0] A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + output [CFG_DBITS-1:0] B1DATA; + input B1EN; + + + generate if (CFG_DBITS == 1) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(1), + .BIT_WIDTH_1(1), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS == 2) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(2), + .BIT_WIDTH_1(2), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 4) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(4), + .BIT_WIDTH_1(4), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 8) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(8), + .BIT_WIDTH_1(8), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 16) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(16), + .BIT_WIDTH_1(16), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else begin + wire TECHMAP_FAIL = 1'b1; + end endgenerate + +endmodule diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index e1f85effa..ebdc88a0a 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -1,5 +1,9 @@ module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule +module \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule + +module \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule +module \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule +module \$__DFFS_PP1_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 14441c2fc..ebb238bad 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D); Q <= D; endmodule +module DFFR (output reg Q, input D, CLK, RESET); + parameter [0:0] INIT = 1'b0; + initial Q = INIT; + always @(posedge CLK) begin + if (RESET) + Q <= 1'b0; + else + Q <= D; + end +endmodule // DFFR (positive clock edge; synchronous reset) + module VCC(output V); assign V = 1; endmodule @@ -63,3 +74,126 @@ module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM); assign {COUT, SUM} = CIN + I1 + I0; endmodule // alu +module RAM16S4 (DO, DI, AD, WRE, CLK); + parameter WIDTH = 4; + parameter INIT_0 = 16'h0000; + parameter INIT_1 = 16'h0000; + parameter INIT_2 = 16'h0000; + parameter INIT_3 = 16'h0000; + + input [WIDTH-1:0] AD; + input [WIDTH-1:0] DI; + output [WIDTH-1:0] DO; + input CLK; + input WRE; + + reg [15:0] mem0, mem1, mem2, mem3; + + initial begin + mem0 = INIT_0; + mem1 = INIT_1; + mem2 = INIT_2; + mem3 = INIT_3; + end + + assign DO[0] = mem0[AD]; + assign DO[1] = mem1[AD]; + assign DO[2] = mem2[AD]; + assign DO[3] = mem3[AD]; + + always @(posedge CLK) begin + if (WRE) begin + mem0[AD] <= DI[0]; + mem1[AD] <= DI[1]; + mem2[AD] <= DI[2]; + mem3[AD] <= DI[3]; + end + end + +endmodule // RAM16S4 + + +(* blackbox *) +module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB); +//1'b0: Bypass mode; 1'b1 Pipeline mode +parameter READ_MODE = 1'b0; +parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32 +parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32 +parameter BLK_SEL = 3'b000; +parameter RESET_MODE = "SYNC"; +parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + +input CLKA, CEA, CLKB, CEB; +input OCE; // clock enable of memory output register +input RESETA, RESETB; // resets output registers, not memory contents +input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled +input [13:0] ADA, ADB; +input [31:0] DI; +input [2:0] BLKSEL; +output [31:0] DO; + +endmodule + diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc new file mode 100644 index 000000000..991e5245a --- /dev/null +++ b/techlibs/gowin/determine_init.cc @@ -0,0 +1,72 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Icenowy Zheng + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DetermineInitPass : public Pass { + DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" determine_init [selection]\n"); + log("\n"); + log("Determine the init value of cells that doesn't allow unknown init value.\n"); + log("\n"); + } + + Const determine_init(Const init) + { + for (int i = 0; i < GetSize(init); i++) { + if (init[i] != State::S0 && init[i] != State::S1) + init[i] = State::S0; + } + + return init; + } + + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); + + extra_args(args, args.size(), design); + + size_t cnt = 0; + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + { + if (cell->type == "\\RAM16S4") + { + cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0"))); + cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1"))); + cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2"))); + cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3"))); + cnt++; + } + } + } + log_header(design, "Updated %lu cells with determined init value.\n", cnt); + } +} DetermineInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/dram.txt b/techlibs/gowin/dram.txt new file mode 100644 index 000000000..9db530251 --- /dev/null +++ b/techlibs/gowin/dram.txt @@ -0,0 +1,17 @@ +bram $__GW1NR_RAM16S4 + init 1 + abits 4 + dbits 4 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 1 + clocks 0 1 + clkpol 0 1 +endbram + +match $__GW1NR_RAM16S4 + make_outreg + min wports 1 +endmatch diff --git a/techlibs/gowin/drams_map.v b/techlibs/gowin/drams_map.v new file mode 100644 index 000000000..a50ab365a --- /dev/null +++ b/techlibs/gowin/drams_map.v @@ -0,0 +1,31 @@ +module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 4; + parameter CFG_DBITS = 4; + + parameter [63:0] INIT = 64'bx; + input CLK1; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + input A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input B1EN; + + `include "brams_init3.vh" + + RAM16S4 + #(.INIT_0(INIT_0), + .INIT_1(INIT_1), + .INIT_2(INIT_2), + .INIT_3(INIT_3)) + _TECHMAP_REPLACE_ + (.AD(B1ADDR), + .DI(B1DATA), + .DO(A1DATA), + .CLK(CLK1), + .WRE(B1EN)); + + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 9a3fcdbb6..8d5fed231 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -49,9 +49,15 @@ struct SynthGowinPass : public ScriptPass log(" from label is synonymous to 'begin', and empty to label is\n"); log(" synonymous to the end of the command list.\n"); log("\n"); + log(" -nodffe\n"); + log(" do not use flipflops with CE in output netlist\n"); + log("\n"); log(" -nobram\n"); log(" do not use BRAM cells in output netlist\n"); log("\n"); + log(" -nodram\n"); + log(" do not use distributed RAM cells in output netlist\n"); + log("\n"); log(" -noflatten\n"); log(" do not flatten design before synthesis\n"); log("\n"); @@ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass } string top_opt, vout_file; - bool retime, flatten, nobram; + bool retime, nobram, nodram, flatten, nodffe; void clear_flags() YS_OVERRIDE { @@ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass vout_file = ""; retime = false; flatten = true; - nobram = true; + nobram = false; + nodffe = false; + nodram = false; } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -108,6 +116,14 @@ struct SynthGowinPass : public ScriptPass nobram = true; continue; } + if (args[argidx] == "-nodram") { + nodram = true; + continue; + } + if (args[argidx] == "-nodffe") { + nodffe = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass { run("synth -run coarse"); } - if (!nobram && check_label("bram", "(skip if -nobram)")) + + if (!nobram && check_label("bram", "(skip if -nobram)")) { run("memory_bram -rules +/gowin/bram.txt"); - run("techmap -map +/gowin/brams_map.v"); + run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v"); } + + if (!nodram && check_label("dram", "(skip if -nodram)")) + { + run("memory_bram -rules +/gowin/dram.txt"); + run("techmap -map +/gowin/drams_map.v"); + run("determine_init"); + } + if (check_label("fine")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); - run("opt -fine"); - run("clean -purge"); - run("splitnets -ports"); - run("setundef -undriven -zero"); + run("techmap -map +/techmap.v"); if (retime || help_mode) run("abc -dff", "(only if -retime)"); } + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("dff2dffs"); + run("opt_clean"); + if (!nodffe) + run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + run("techmap -map +/gowin/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + } + if (check_label("map_luts")) { run("abc -lut 4"); @@ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass { run("techmap -map +/gowin/cells_map.v"); run("hilomap -hicell VCC V -locell GND G"); - run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); - run("clean -purge"); + run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)"); + run("dffinit -ff DFF Q INIT"); + run("clean"); + } if (check_label("check")) From 6323e73cc94627125a275b22b0b8ea290e750bc3 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 15 Apr 2019 14:29:46 +0000 Subject: [PATCH 092/149] README: fix some incorrect quoting. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4048ecbc7..d000c5d63 100644 --- a/README.md +++ b/README.md @@ -312,10 +312,10 @@ Verilog Attributes and non-standard features passes to identify input and output ports of cells. The Verilog backend also does not output blackbox modules on default. -- The ``dynports'' attribute is used by the Verilog front-end to mark modules +- The ``dynports`` attribute is used by the Verilog front-end to mark modules that have ports with a width that depends on a parameter. -- The ``hdlname'' attribute is used by some passes to document the original +- The ``hdlname`` attribute is used by some passes to document the original (HDL) name of a module when renaming a module. - The ``keep`` attribute on cells and wires is used to mark objects that should From b3378745fd993f48b8114fb08e5019b34374ee72 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 15 Apr 2019 17:52:45 -0700 Subject: [PATCH 093/149] Revert "Recognise default entry in case even if all cases covered (fix for #931)" --- passes/proc/proc_rmdead.cc | 2 +- tests/various/muxcover.ys | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc index d2f8d9ead..7c334e661 100644 --- a/passes/proc/proc_rmdead.cc +++ b/passes/proc/proc_rmdead.cc @@ -34,7 +34,7 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) for (size_t i = 0; i < sw->cases.size(); i++) { - bool is_default = GetSize(sw->cases[i]->compare) == 0 || GetSize(sw->signal) == 0; + bool is_default = GetSize(sw->cases[i]->compare) == 0 && (!pool.empty() || GetSize(sw->signal) == 0); for (size_t j = 0; j < sw->cases[i]->compare.size(); j++) { RTLIL::SigSpec sig = sw->cases[i]->compare[j]; diff --git a/tests/various/muxcover.ys b/tests/various/muxcover.ys index 594e62af6..7ac460f13 100644 --- a/tests/various/muxcover.ys +++ b/tests/various/muxcover.ys @@ -8,13 +8,12 @@ read_verilog -formal < Date: Tue, 16 Apr 2019 11:07:51 -0700 Subject: [PATCH 094/149] Revert #895 --- passes/proc/proc_mux.cc | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index bac2dc2cd..1329c1fef 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -340,7 +340,6 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; - bool shiftx = initial_val.is_fully_undef(); for (size_t i = 0; i < sw->cases.size(); i++) { int case_idx = sw->cases.size() - i - 1; RTLIL::CaseRule *cs2 = sw->cases[case_idx]; @@ -349,33 +348,6 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d append_pmux(mod, sw->signal, cs2->compare, value, last_mux_cell, sw, ifxmode); else result = gen_mux(mod, sw->signal, cs2->compare, value, result, last_mux_cell, sw, ifxmode); - - // Ignore output values which are entirely don't care - if (shiftx && !value.is_fully_undef()) { - // Keep checking if case condition is the same as the current case index - if (cs2->compare.size() == 1 && cs2->compare.front().is_fully_const()) - shiftx = (cs2->compare.front().as_int() == case_idx); - else - shiftx = false; - } - } - - // Transform into a $shiftx where possible - if (shiftx && last_mux_cell && last_mux_cell->type == "$pmux") { - // Create bit-blasted $shiftx-es that shifts by the address line used in the case statement - auto pmux_b_port = last_mux_cell->getPort("\\B"); - auto pmux_y_port = last_mux_cell->getPort("\\Y"); - int width = last_mux_cell->getParam("\\WIDTH").as_int(); - for (int i = 0; i < width; ++i) { - RTLIL::SigSpec a_port; - // Because we went in reverse order above, un-reverse $pmux's B port here - for (int j = pmux_b_port.size()/width-1; j >= 0; --j) - a_port.append(pmux_b_port.extract(j*width+i, 1)); - // Create a $shiftx that shifts by the address line used in the case statement - mod->addShiftx(NEW_ID, a_port, sw->signal, pmux_y_port.extract(i, 1)); - } - // Disconnect $pmux by replacing its output port with a floating wire - last_mux_cell->setPort("\\Y", mod->addWire(NEW_ID, width)); } } From ea8ac0aaad3a1f89ead8eb44b2fef5927f29a099 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Wed, 17 Apr 2019 13:51:34 +0200 Subject: [PATCH 095/149] Update to ABC d1b6413 Signed-off-by: Clifford Wolf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 8586e9766..f705db9ec 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ OBJS = kernel/version_$(GIT_REV).o # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = 2ddc57d +ABCREV = d1b6413 ABCPULL = 1 ABCURL ?= https://github.com/berkeley-abc/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 From 88be1cbfa50238d77d9489218a8cca7275731da9 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 18 Apr 2019 15:07:43 +0200 Subject: [PATCH 096/149] Improve proc full_case detection and handling, fixes #931 Signed-off-by: Clifford Wolf --- passes/proc/proc_mux.cc | 50 ++++++++++++++++++++++++++++++++++++++ passes/proc/proc_rmdead.cc | 18 ++++++++++---- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/passes/proc/proc_mux.cc b/passes/proc/proc_mux.cc index 1329c1fef..aac0b121c 100644 --- a/passes/proc/proc_mux.cc +++ b/passes/proc/proc_mux.cc @@ -108,6 +108,7 @@ struct SigSnippets struct SnippetSwCache { + dict, hash_ptr_ops> full_case_bits_cache; dict, hash_ptr_ops> cache; const SigSnippets *snippets; int current_snippet; @@ -268,6 +269,49 @@ void append_pmux(RTLIL::Module *mod, const RTLIL::SigSpec &signal, const std::ve last_mux_cell->parameters["\\S_WIDTH"] = last_mux_cell->getPort("\\S").size(); } +const pool &get_full_case_bits(SnippetSwCache &swcache, RTLIL::SwitchRule *sw) +{ + if (!swcache.full_case_bits_cache.count(sw)) + { + pool bits; + + if (sw->get_bool_attribute("\\full_case")) + { + bool first_case = true; + + for (auto cs : sw->cases) + { + pool case_bits; + + for (auto it : cs->actions) { + for (auto bit : it.first) + case_bits.insert(bit); + } + + for (auto it : cs->switches) { + for (auto bit : get_full_case_bits(swcache, it)) + case_bits.insert(bit); + } + + if (first_case) { + first_case = false; + bits = case_bits; + } else { + pool new_bits; + for (auto bit : bits) + if (case_bits.count(bit)) + new_bits.insert(bit); + bits.swap(new_bits); + } + } + } + + bits.swap(swcache.full_case_bits_cache[sw]); + } + + return swcache.full_case_bits_cache.at(sw); +} + RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, dict &swpara, RTLIL::CaseRule *cs, const RTLIL::SigSpec &sig, const RTLIL::SigSpec &defval, bool ifxmode) { @@ -337,6 +381,12 @@ RTLIL::SigSpec signal_to_mux_tree(RTLIL::Module *mod, SnippetSwCache &swcache, d } } + // mask default bits that are irrelevant because the output is driven by a full case + const pool &full_case_bits = get_full_case_bits(swcache, sw); + for (int i = 0; i < GetSize(sig); i++) + if (full_case_bits.count(sig[i])) + result[i] = State::Sx; + // evaluate in reverse order to give the first entry the top priority RTLIL::SigSpec initial_val = result; RTLIL::Cell *last_mux_cell = NULL; diff --git a/passes/proc/proc_rmdead.cc b/passes/proc/proc_rmdead.cc index 7c334e661..4f40be446 100644 --- a/passes/proc/proc_rmdead.cc +++ b/passes/proc/proc_rmdead.cc @@ -28,7 +28,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) +void proc_rmdead(RTLIL::SwitchRule *sw, int &counter, int &full_case_counter) { BitPatternPool pool(sw->signal); @@ -56,11 +56,16 @@ void proc_rmdead(RTLIL::SwitchRule *sw, int &counter) } for (auto switch_it : sw->cases[i]->switches) - proc_rmdead(switch_it, counter); + proc_rmdead(switch_it, counter, full_case_counter); if (is_default) pool.take_all(); } + + if (pool.empty() && !sw->get_bool_attribute("\\full_case")) { + sw->set_bool_attribute("\\full_case"); + full_case_counter++; + } } struct ProcRmdeadPass : public Pass { @@ -87,12 +92,15 @@ struct ProcRmdeadPass : public Pass { for (auto &proc_it : mod->processes) { if (!design->selected(mod, proc_it.second)) continue; - int counter = 0; + int counter = 0, full_case_counter = 0; for (auto switch_it : proc_it.second->root_case.switches) - proc_rmdead(switch_it, counter); + proc_rmdead(switch_it, counter, full_case_counter); if (counter > 0) log("Removed %d dead cases from process %s in module %s.\n", counter, - proc_it.first.c_str(), log_id(mod)); + log_id(proc_it.first), log_id(mod)); + if (full_case_counter > 0) + log("Marked %d switch rules as full_case in process %s in module %s.\n", + full_case_counter, log_id(proc_it.first), log_id(mod)); total_counter += counter; } } From 6008bb7002f874e5c748eaa2050e7b6c17b32745 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 07:59:16 -0700 Subject: [PATCH 097/149] Revert "synth_* with -retime option now calls abc with -D 1 as well" This reverts commit 9a6da9a79a22e984ee3eec02caa230b66f10e11a. --- techlibs/achronix/synth_achronix.cc | 4 ++-- techlibs/anlogic/synth_anlogic.cc | 2 +- techlibs/coolrunner2/synth_coolrunner2.cc | 2 +- techlibs/easic/synth_easic.cc | 2 +- techlibs/ecp5/synth_ecp5.cc | 2 +- techlibs/gowin/synth_gowin.cc | 2 +- techlibs/greenpak4/synth_greenpak4.cc | 2 +- techlibs/ice40/synth_ice40.cc | 2 +- techlibs/intel/synth_intel.cc | 6 +++--- techlibs/sf2/synth_sf2.cc | 2 +- techlibs/xilinx/synth_xilinx.cc | 4 ++-- 11 files changed, 15 insertions(+), 15 deletions(-) diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 3dbf20911..626860d9c 100755 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -152,12 +152,12 @@ struct SynthAchronixPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff -D 1", "(only if -retime)"); + run("abc -markgroups -dff", "(only if -retime)"); } if (check_label("map_luts")) { - run("abc -lut 4" + string(retime ? " -dff -D 1" : "")); + run("abc -lut 4" + string(retime ? " -dff" : "")); run("clean"); } diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index 258e3d722..620bf3965 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -164,7 +164,7 @@ struct SynthAnlogicPass : public ScriptPass run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/anlogic/arith_map.v"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc index fa4fe0f5b..21bbcaef4 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cc +++ b/techlibs/coolrunner2/synth_coolrunner2.cc @@ -161,7 +161,7 @@ struct SynthCoolrunner2Pass : public ScriptPass if (check_label("map_pla")) { - run("abc -sop -I 40 -P 56" + string(retime ? " -dff -D 1" : "")); + run("abc -sop -I 40 -P 56"); run("clean"); } diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc index 7bacc7890..dd9e3dab7 100644 --- a/techlibs/easic/synth_easic.cc +++ b/techlibs/easic/synth_easic.cc @@ -158,7 +158,7 @@ struct SynthEasicPass : public ScriptPass run("techmap"); run("opt -fast"); if (retime || help_mode) { - run("abc -dff -D 1", " (only if -retime)"); + run("abc -dff", " (only if -retime)"); run("opt_clean", "(only if -retime)"); } } diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 45f101451..4b889d672 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -242,7 +242,7 @@ struct SynthEcp5Pass : public ScriptPass else run("techmap -map +/techmap.v -map +/ecp5/arith_map.v"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 0ebd77d63..9a3fcdbb6 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -163,7 +163,7 @@ struct SynthGowinPass : public ScriptPass run("splitnets -ports"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); } if (check_label("map_luts")) diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index 3222be2e3..eeb001b46 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -165,7 +165,7 @@ struct SynthGreenPAK4Pass : public ScriptPass run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); run("opt -fast"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); } if (check_label("map_luts")) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index d114b6269..8899bfcc4 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -274,7 +274,7 @@ struct SynthIce40Pass : public ScriptPass else run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); run("ice40_opt"); } diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index 290282bd9..0f1d7a7b5 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -210,15 +210,15 @@ struct SynthIntelPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff -D 1", "(only if -retime)"); + run("abc -markgroups -dff", "(only if -retime)"); } if (check_label("map_luts")) { if(family_opt=="a10gx" || family_opt=="cyclonev") - run("abc -luts 2:2,3,6:5" + string(retime ? " -dff -D 1" : "")); + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); else - run("abc -lut 4" + string(retime ? " -dff -D 1" : "")); + run("abc -lut 4" + string(retime ? " -dff" : "")); run("clean"); } diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 3c5a58b4c..0924df7a6 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -181,7 +181,7 @@ struct SynthSf2Pass : public ScriptPass run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/sf2/arith_map.v"); if (retime || help_mode) - run("abc -dff -D 1", "(only if -retime)"); + run("abc -dff", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index a462b9052..397c83ac6 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -115,7 +115,7 @@ struct SynthXilinxPass : public Pass log("\n"); log(" map_luts:\n"); log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff -D 1]\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); log("\n"); @@ -269,7 +269,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_luts")) { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff -D 1" : "")); + Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); } From f4abc21d8ad79621cc24852bd76abf40a9d9f702 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 18 Apr 2019 17:42:12 +0200 Subject: [PATCH 098/149] Add "whitebox" attribute, add "read_verilog -wb" Signed-off-by: Clifford Wolf --- README.md | 4 ++++ backends/blif/blif.cc | 6 +++--- backends/edif/edif.cc | 6 +++--- backends/intersynth/intersynth.cc | 2 +- backends/smt2/smt2.cc | 2 +- backends/smv/smv.cc | 2 +- backends/spice/spice.cc | 2 +- backends/table/table.cc | 2 +- backends/verilog/verilog_backend.cc | 2 +- frontends/ast/ast.cc | 22 ++++++++++++++++++++-- frontends/ast/ast.h | 4 ++-- frontends/verilog/verilog_frontend.cc | 14 ++++++++++++-- frontends/verilog/verilog_frontend.h | 3 +++ frontends/verilog/verilog_parser.y | 10 +++++----- kernel/rtlil.cc | 6 +++--- kernel/rtlil.h | 4 ++++ passes/cmds/add.cc | 2 +- passes/cmds/bugpoint.cc | 8 ++++---- passes/cmds/show.cc | 4 ++-- passes/hierarchy/hierarchy.cc | 10 +++++----- passes/hierarchy/uniquify.cc | 2 +- passes/techmap/dfflibmap.cc | 2 +- passes/techmap/techmap.cc | 4 ++-- 23 files changed, 81 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index d000c5d63..5c94c34e5 100644 --- a/README.md +++ b/README.md @@ -312,6 +312,10 @@ Verilog Attributes and non-standard features passes to identify input and output ports of cells. The Verilog backend also does not output blackbox modules on default. +- The ``whitebox`` attribute on modules triggers the same behavior as + ``blackbox``, but is for whitebox modules, i.e. library modules that + contain a behavioral model of the cell type. + - The ``dynports`` attribute is used by the Verilog front-end to mark modules that have ports with a width that depends on a parameter. diff --git a/backends/blif/blif.cc b/backends/blif/blif.cc index 0db5ff27c..b6dbd84cb 100644 --- a/backends/blif/blif.cc +++ b/backends/blif/blif.cc @@ -140,7 +140,7 @@ struct BlifDumper return "subckt"; if (!design->modules_.count(RTLIL::escape_id(cell_type))) return "gate"; - if (design->modules_.at(RTLIL::escape_id(cell_type))->get_bool_attribute("\\blackbox")) + if (design->modules_.at(RTLIL::escape_id(cell_type))->get_blackbox_attribute()) return "gate"; return "subckt"; } @@ -196,7 +196,7 @@ struct BlifDumper } f << stringf("\n"); - if (module->get_bool_attribute("\\blackbox")) { + if (module->get_blackbox_attribute()) { f << stringf(".blackbox\n"); f << stringf(".end\n"); return; @@ -640,7 +640,7 @@ struct BlifBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox") && !config.blackbox_mode) + if (module->get_blackbox_attribute() && !config.blackbox_mode) continue; if (module->processes.size() != 0) diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 7e30b67af..6d9469538 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -178,7 +178,7 @@ struct EdifBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (top_module_name.empty()) @@ -192,7 +192,7 @@ struct EdifBackend : public Backend { for (auto cell_it : module->cells_) { RTLIL::Cell *cell = cell_it.second; - if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { + if (!design->modules_.count(cell->type) || design->modules_.at(cell->type)->get_blackbox_attribute()) { lib_cell_ports[cell->type]; for (auto p : cell->connections()) lib_cell_ports[cell->type][p.first] = GetSize(p.second); @@ -302,7 +302,7 @@ struct EdifBackend : public Backend { *f << stringf(" (technology (numberDefinition))\n"); for (auto module : sorted_modules) { - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; SigMap sigmap(module); diff --git a/backends/intersynth/intersynth.cc b/backends/intersynth/intersynth.cc index 2eb08dbe9..b0e3cd252 100644 --- a/backends/intersynth/intersynth.cc +++ b/backends/intersynth/intersynth.cc @@ -127,7 +127,7 @@ struct IntersynthBackend : public Backend { RTLIL::Module *module = module_it.second; SigMap sigmap(module); - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (module->memories.size() == 0 && module->processes.size() == 0 && module->cells_.size() == 0) continue; diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 688535f33..e318a4051 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -1543,7 +1543,7 @@ struct Smt2Backend : public Backend { for (auto module : sorted_modules) { - if (module->get_bool_attribute("\\blackbox") || module->has_memories_warn() || module->has_processes_warn()) + if (module->get_blackbox_attribute() || module->has_memories_warn() || module->has_processes_warn()) continue; log("Creating SMT-LIBv2 representation of module %s.\n", log_id(module)); diff --git a/backends/smv/smv.cc b/backends/smv/smv.cc index f379c9c48..d75456c1b 100644 --- a/backends/smv/smv.cc +++ b/backends/smv/smv.cc @@ -739,7 +739,7 @@ struct SmvBackend : public Backend { pool modules; for (auto module : design->modules()) - if (!module->get_bool_attribute("\\blackbox") && !module->has_memories_warn() && !module->has_processes_warn()) + if (!module->get_blackbox_attribute() && !module->has_memories_warn() && !module->has_processes_warn()) modules.insert(module); if (template_f.is_open()) diff --git a/backends/spice/spice.cc b/backends/spice/spice.cc index b6a3f1e77..6738a4bbd 100644 --- a/backends/spice/spice.cc +++ b/backends/spice/spice.cc @@ -212,7 +212,7 @@ struct SpiceBackend : public Backend { for (auto module_it : design->modules_) { RTLIL::Module *module = module_it.second; - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; if (module->processes.size() != 0) diff --git a/backends/table/table.cc b/backends/table/table.cc index b75169ea4..796f18059 100644 --- a/backends/table/table.cc +++ b/backends/table/table.cc @@ -67,7 +67,7 @@ struct TableBackend : public Backend { for (auto module : design->modules()) { - if (module->get_bool_attribute("\\blackbox")) + if (module->get_blackbox_attribute()) continue; SigMap sigmap(module); diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 83d83f488..855409d0b 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1770,7 +1770,7 @@ struct VerilogBackend : public Backend { *f << stringf("/* Generated by %s */\n", yosys_version_str); for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) { - if (it->second->get_bool_attribute("\\blackbox") != blackboxes) + if (it->second->get_blackbox_attribute() != blackboxes) continue; if (selected && !design->selected_whole_module(it->first)) { if (design->selected_module(it->first)) diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index d48996167..720b3f3d1 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -46,7 +46,7 @@ namespace AST { // instantiate global variables (private API) namespace AST_INTERNAL { bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_noopt, flag_icells, flag_autowire; + bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_wb, flag_noopt, flag_icells, flag_autowire; AstNode *current_ast, *current_ast_mod; std::map current_scope; const dict *genRTLIL_subst_ptr = NULL; @@ -956,7 +956,18 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast log("--- END OF AST DUMP ---\n"); } + if (flag_wb) { + if (!ast->attributes.count("\\whitebox")) + goto blackbox_module; + AstNode *n = ast->attributes.at("\\whitebox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Whitebox attribute with non-constant value!\n"); + if (!n->asBool()) + goto blackbox_module; + } + if (flag_lib) { + blackbox_module: std::vector new_children; for (auto child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) { @@ -970,6 +981,10 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast } } ast->children.swap(new_children); + if (ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); } @@ -1010,6 +1025,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast current_module->nomem2reg = flag_nomem2reg; current_module->mem2reg = flag_mem2reg; current_module->lib = flag_lib; + current_module->wb = flag_wb; current_module->noopt = flag_noopt; current_module->icells = flag_icells; current_module->autowire = flag_autowire; @@ -1026,7 +1042,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast // create AstModule instances for all modules in the AST tree and add them to 'design' void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, - bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; @@ -1040,6 +1056,7 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_nomem2reg = nomem2reg; flag_mem2reg = mem2reg; flag_lib = lib; + flag_wb = wb; flag_noopt = noopt; flag_icells = icells; flag_autowire = autowire; @@ -1374,6 +1391,7 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail) YS_OVERRIDE; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 504f8b3f3..4e2c5abb5 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -148,6 +148,10 @@ struct VerilogFrontend : public Frontend { log(" -lib\n"); log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); log("\n"); + log(" -wb\n"); + log(" like -lib, except do not touch modules with the whitebox\n"); + log(" attribute set. This also implies -DBLACKBOX.\n"); + log("\n"); log(" -noopt\n"); log(" don't perform basic optimizations (such as const folding) in the\n"); log(" high-level front-end.\n"); @@ -228,6 +232,7 @@ struct VerilogFrontend : public Frontend { norestrict_mode = false; assume_asserts_mode = false; lib_mode = false; + wb_mode = false; default_nettype_wire = true; log_header(design, "Executing Verilog-2005 frontend.\n"); @@ -329,11 +334,16 @@ struct VerilogFrontend : public Frontend { flag_nodpi = true; continue; } - if (arg == "-lib") { + if (arg == "-lib" && !wb_mode) { lib_mode = true; defines_map["BLACKBOX"] = string(); continue; } + if (arg == "-wb" && !lib_mode) { + wb_mode = true; + defines_map["BLACKBOX"] = string(); + continue; + } if (arg == "-noopt") { flag_noopt = true; continue; @@ -429,7 +439,7 @@ struct VerilogFrontend : public Frontend { if (flag_nodpi) error_on_dpi_function(current_ast); - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, wb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 523bbc897..b5cf70c57 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -72,6 +72,9 @@ namespace VERILOG_FRONTEND // running in -lib mode extern bool lib_mode; + // running in -wb mode + extern bool wb_mode; + // lexer input stream extern std::istream *lexin; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 52685f637..122eb1230 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND { std::vector case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode; + bool sv_mode, formal_mode, lib_mode, wb_mode; bool noassert_mode, noassume_mode, norestrict_mode; bool assume_asserts_mode, assert_assumes_mode; bool current_wire_rand, current_wire_const; @@ -1906,7 +1906,7 @@ basic_expr: if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1917,7 +1917,7 @@ basic_expr: frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1925,14 +1925,14 @@ basic_expr: delete $2; } | TOK_CONSTVAL TOK_CONSTVAL { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONSTVAL { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); + $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 9ae20a317..2f8715755 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -589,7 +589,7 @@ std::vector RTLIL::Design::selected_modules() const std::vector result; result.reserve(modules_.size()); for (auto &it : modules_) - if (selected_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) + if (selected_module(it.first) && !it.second->get_blackbox_attribute()) result.push_back(it.second); return result; } @@ -599,7 +599,7 @@ std::vector RTLIL::Design::selected_whole_modules() const std::vector result; result.reserve(modules_.size()); for (auto &it : modules_) - if (selected_whole_module(it.first) && !it.second->get_bool_attribute("\\blackbox")) + if (selected_whole_module(it.first) && !it.second->get_blackbox_attribute()) result.push_back(it.second); return result; } @@ -609,7 +609,7 @@ std::vector RTLIL::Design::selected_whole_modules_warn() const std::vector result; result.reserve(modules_.size()); for (auto &it : modules_) - if (it.second->get_bool_attribute("\\blackbox")) + if (it.second->get_blackbox_attribute()) continue; else if (selected_whole_module(it.first)) result.push_back(it.second); diff --git a/kernel/rtlil.h b/kernel/rtlil.h index fb045bc72..176dc3fc2 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -569,6 +569,10 @@ struct RTLIL::AttrObject void set_bool_attribute(RTLIL::IdString id); bool get_bool_attribute(RTLIL::IdString id) const; + bool get_blackbox_attribute() const { + return get_bool_attribute("\\blackbox") || get_bool_attribute("\\whitebox"); + } + void set_strpool_attribute(RTLIL::IdString id, const pool &data); void add_strpool_attribute(RTLIL::IdString id, const pool &data); pool get_strpool_attribute(RTLIL::IdString id) const; diff --git a/passes/cmds/add.cc b/passes/cmds/add.cc index cfccca966..af6f7043d 100644 --- a/passes/cmds/add.cc +++ b/passes/cmds/add.cc @@ -71,7 +71,7 @@ static void add_wire(RTLIL::Design *design, RTLIL::Module *module, std::string n RTLIL::Module *mod = design->modules_.at(it.second->type); if (!design->selected_whole_module(mod->name)) continue; - if (mod->get_bool_attribute("\\blackbox")) + if (mod->get_blackbox_attribute()) continue; if (it.second->hasPort(name)) continue; diff --git a/passes/cmds/bugpoint.cc b/passes/cmds/bugpoint.cc index 606276e64..4b22f6d2d 100644 --- a/passes/cmds/bugpoint.cc +++ b/passes/cmds/bugpoint.cc @@ -128,7 +128,7 @@ struct BugpointPass : public Pass { { for (auto &it : design_copy->modules_) { - if (it.second->get_bool_attribute("\\blackbox")) + if (it.second->get_blackbox_attribute()) continue; if (index++ == seed) @@ -143,7 +143,7 @@ struct BugpointPass : public Pass { { for (auto mod : design_copy->modules()) { - if (mod->get_bool_attribute("\\blackbox")) + if (mod->get_blackbox_attribute()) continue; for (auto wire : mod->wires()) @@ -168,7 +168,7 @@ struct BugpointPass : public Pass { { for (auto mod : design_copy->modules()) { - if (mod->get_bool_attribute("\\blackbox")) + if (mod->get_blackbox_attribute()) continue; for (auto &it : mod->cells_) @@ -186,7 +186,7 @@ struct BugpointPass : public Pass { { for (auto mod : design_copy->modules()) { - if (mod->get_bool_attribute("\\blackbox")) + if (mod->get_blackbox_attribute()) continue; for (auto cell : mod->cells()) diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 58acd302d..8b1b43f44 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -555,7 +555,7 @@ struct ShowWorker if (!design->selected_module(module->name)) continue; if (design->selected_whole_module(module->name)) { - if (module->get_bool_attribute("\\blackbox")) { + if (module->get_blackbox_attribute()) { // log("Skipping blackbox module %s.\n", id2cstr(module->name)); continue; } else @@ -771,7 +771,7 @@ struct ShowPass : public Pass { if (format != "ps" && format != "dot") { int modcount = 0; for (auto &mod_it : design->modules_) { - if (mod_it.second->get_bool_attribute("\\blackbox")) + if (mod_it.second->get_blackbox_attribute()) continue; if (mod_it.second->cells_.empty() && mod_it.second->connections().empty()) continue; diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 88c339e8c..b8ff99884 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -346,9 +346,9 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check } RTLIL::Module *mod = design->modules_[cell->type]; - if (design->modules_.at(cell->type)->get_bool_attribute("\\blackbox")) { + if (design->modules_.at(cell->type)->get_blackbox_attribute()) { if (flag_simcheck) - log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox module.\n", + log_error("Module `%s' referenced in module `%s' in cell `%s' is a blackbox/whitebox module.\n", cell->type.c_str(), module->name.c_str(), cell->name.c_str()); continue; } @@ -451,7 +451,7 @@ void hierarchy_worker(RTLIL::Design *design, std::setname.c_str()); - else if (!mod->get_bool_attribute("\\blackbox")) + else if (!mod->get_blackbox_attribute()) log("Used module: %*s%s\n", indent, "", mod->name.c_str()); used.insert(mod); @@ -491,7 +491,7 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib) int del_counter = 0; for (auto mod : del_modules) { - if (!purge_lib && mod->get_bool_attribute("\\blackbox")) + if (!purge_lib && mod->get_blackbox_attribute()) continue; log("Removing unused module `%s'.\n", mod->name.c_str()); design->modules_.erase(mod->name); @@ -910,7 +910,7 @@ struct HierarchyPass : public Pass { if (m == nullptr) continue; - if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { + if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { IdString new_m_name = m->derive(design, cell->parameters, true); if (new_m_name.empty()) continue; diff --git a/passes/hierarchy/uniquify.cc b/passes/hierarchy/uniquify.cc index e6154e94f..ad3220918 100644 --- a/passes/hierarchy/uniquify.cc +++ b/passes/hierarchy/uniquify.cc @@ -75,7 +75,7 @@ struct UniquifyPass : public Pass { if (tmod == nullptr) continue; - if (tmod->get_bool_attribute("\\blackbox")) + if (tmod->get_blackbox_attribute()) continue; if (tmod->get_bool_attribute("\\unique") && newname == tmod->name) diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index 274177a68..b5c0498d0 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -664,7 +664,7 @@ struct DfflibmapPass : public Pass { logmap_all(); for (auto &it : design->modules_) - if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) + if (design->selected(it.second) && !it.second->get_blackbox_attribute()) dfflibmap(design, it.second, prepare_mode); cell_mappings.clear(); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index d0e5e2236..d694e8165 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -472,7 +472,7 @@ struct TechmapWorker RTLIL::Module *tpl = map->modules_[tpl_name]; std::map parameters(cell->parameters.begin(), cell->parameters.end()); - if (tpl->get_bool_attribute("\\blackbox")) + if (tpl->get_blackbox_attribute()) continue; if (!flatten_mode) @@ -1209,7 +1209,7 @@ struct FlattenPass : public Pass { dict new_modules; for (auto mod : vector(design->modules())) - if (used_modules[mod->name] || mod->get_bool_attribute("\\blackbox")) { + if (used_modules[mod->name] || mod->get_blackbox_attribute()) { new_modules[mod->name] = mod; } else { log("Deleting now unused module %s.\n", log_id(mod)); From 9aa94370a54c016421740d2ce32ef0aa338d0dbd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 08:46:41 -0700 Subject: [PATCH 099/149] ABC to call retime all the time --- passes/techmap/abc.cc | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 3adbe0a04..aaf580eff 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -29,17 +29,17 @@ // Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM 5 (11): 558-562, doi:10.1145/368996.369025 // http://en.wikipedia.org/wiki/Topological_sorting -#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" -#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; strash; dch -f; if; mfs2" -#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; strash; dch -f; cover {I} {P}" -#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; strash; &get -n; &dch -f; &nf {D}; &put" +#define ABC_COMMAND_LIB "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" +#define ABC_COMMAND_CTR "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_COMMAND_LUT "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; if; mfs2" +#define ABC_COMMAND_SOP "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; dch -f; cover {I} {P}" +#define ABC_COMMAND_DFL "strash; ifraig; scorr; dc2; dretime; retime {D}; strash; &get -n; &dch -f; &nf {D}; &put" -#define ABC_FAST_COMMAND_LIB "strash; dretime; map {D}" -#define ABC_FAST_COMMAND_CTR "strash; dretime; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" -#define ABC_FAST_COMMAND_LUT "strash; dretime; if" -#define ABC_FAST_COMMAND_SOP "strash; dretime; cover -I {I} -P {P}" -#define ABC_FAST_COMMAND_DFL "strash; dretime; map" +#define ABC_FAST_COMMAND_LIB "strash; dretime; retime {D}; map {D}" +#define ABC_FAST_COMMAND_CTR "strash; dretime; retime {D}; map {D}; buffer; upsize {D}; dnsize {D}; stime -p" +#define ABC_FAST_COMMAND_LUT "strash; dretime; retime {D}; if" +#define ABC_FAST_COMMAND_SOP "strash; dretime; retime {D}; cover -I {I} -P {P}" +#define ABC_FAST_COMMAND_DFL "strash; dretime; retime {D}; map" #include "kernel/register.h" #include "kernel/sigtools.h" @@ -731,10 +731,6 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin else abc_script += fast_mode ? ABC_FAST_COMMAND_DFL : ABC_COMMAND_DFL; - if (script_file.empty() && !delay_target.empty()) - for (size_t pos = abc_script.find("dretime;"); pos != std::string::npos; pos = abc_script.find("dretime;", pos+1)) - abc_script = abc_script.substr(0, pos) + "dretime; retime -o {D};" + abc_script.substr(pos+8); - for (size_t pos = abc_script.find("{D}"); pos != std::string::npos; pos = abc_script.find("{D}", pos)) abc_script = abc_script.substr(0, pos) + delay_target + abc_script.substr(pos+3); From 070a2d2fd6b2d79a71be1ab5b8fe40e40e690433 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 09:55:03 -0700 Subject: [PATCH 100/149] Fix abc's remap_name to not ignore [^0-9] when extracting sid --- passes/techmap/abc.cc | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index aaf580eff..547115459 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -331,19 +331,23 @@ std::string remap_name(RTLIL::IdString abc_name, RTLIL::Wire **orig_wire = nullp { std::string abc_sname = abc_name.substr(1); if (abc_sname.substr(0, 5) == "ys__n") { - int sid = std::stoi(abc_sname.substr(5)); bool inv = abc_sname.back() == 'v'; - for (auto sig : signal_list) { - if (sig.id == sid && sig.bit.wire != nullptr) { - std::stringstream sstr; - sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); - if (sig.bit.wire->width != 1) - sstr << "[" << sig.bit.offset << "]"; - if (inv) - sstr << "_inv"; - if (orig_wire != nullptr) - *orig_wire = sig.bit.wire; - return sstr.str(); + if (inv) abc_sname.pop_back(); + abc_sname.erase(0, 5); + if (abc_sname.find_last_not_of("012345689") == std::string::npos) { + int sid = std::stoi(abc_sname); + for (auto sig : signal_list) { + if (sig.id == sid && sig.bit.wire != nullptr) { + std::stringstream sstr; + sstr << "$abc$" << map_autoidx << "$" << sig.bit.wire->name.substr(1); + if (sig.bit.wire->width != 1) + sstr << "[" << sig.bit.offset << "]"; + if (inv) + sstr << "_inv"; + if (orig_wire != nullptr) + *orig_wire = sig.bit.wire; + return sstr.str(); + } } } } From 290a798cec4dae02886877a342b00c1ba7d5b22d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 10:19:45 -0700 Subject: [PATCH 101/149] Ignore 'whitebox' attr in flatten with "-wb" option --- kernel/rtlil.h | 4 ++-- passes/techmap/techmap.cc | 24 +++++++++++++++++++----- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 176dc3fc2..9e396d6f6 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -569,8 +569,8 @@ struct RTLIL::AttrObject void set_bool_attribute(RTLIL::IdString id); bool get_bool_attribute(RTLIL::IdString id) const; - bool get_blackbox_attribute() const { - return get_bool_attribute("\\blackbox") || get_bool_attribute("\\whitebox"); + bool get_blackbox_attribute(bool ignore_wb=false) const { + return get_bool_attribute("\\blackbox") || (!ignore_wb && get_bool_attribute("\\whitebox")); } void set_strpool_attribute(RTLIL::IdString id, const pool &data); diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index d694e8165..82c815e2e 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -84,6 +84,7 @@ struct TechmapWorker bool flatten_mode; bool recursive_mode; bool autoproc_mode; + bool ignore_wb; TechmapWorker() { @@ -92,6 +93,7 @@ struct TechmapWorker flatten_mode = false; recursive_mode = false; autoproc_mode = false; + ignore_wb = false; } std::string constmap_tpl_name(SigMap &sigmap, RTLIL::Module *tpl, RTLIL::Cell *cell, bool verbose) @@ -472,7 +474,7 @@ struct TechmapWorker RTLIL::Module *tpl = map->modules_[tpl_name]; std::map parameters(cell->parameters.begin(), cell->parameters.end()); - if (tpl->get_blackbox_attribute()) + if (tpl->get_blackbox_attribute(ignore_wb)) continue; if (!flatten_mode) @@ -1145,7 +1147,7 @@ struct FlattenPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" flatten [selection]\n"); + log(" flatten [options] [selection]\n"); log("\n"); log("This pass flattens the design by replacing cells by their implementation. This\n"); log("pass is very similar to the 'techmap' pass. The only difference is that this\n"); @@ -1154,17 +1156,29 @@ struct FlattenPass : public Pass { log("Cells and/or modules with the 'keep_hierarchy' attribute set will not be\n"); log("flattened by this command.\n"); log("\n"); + log(" -wb\n"); + log(" Ignore the 'whitebox' attribute on cell implementations.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { log_header(design, "Executing FLATTEN pass (flatten design).\n"); log_push(); - extra_args(args, 1, design); - TechmapWorker worker; worker.flatten_mode = true; + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-wb") { + worker.ignore_wb = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + std::map> celltypeMap; for (auto module : design->modules()) celltypeMap[module->name].insert(module->name); @@ -1209,7 +1223,7 @@ struct FlattenPass : public Pass { dict new_modules; for (auto mod : vector(design->modules())) - if (used_modules[mod->name] || mod->get_blackbox_attribute()) { + if (used_modules[mod->name] || mod->get_blackbox_attribute(worker.ignore_wb)) { new_modules[mod->name] = mod; } else { log("Deleting now unused module %s.\n", log_id(mod)); From 4ef03e19a8eafc324d3442f0642abf858071fdd4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 10:30:45 -0700 Subject: [PATCH 102/149] write_json to not write contents (cells/wires) of whiteboxes --- backends/json/json.cc | 115 ++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/backends/json/json.cc b/backends/json/json.cc index f5c687981..b4f82a3fe 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -130,72 +130,75 @@ struct JsonWriter f << stringf(" }"); first = false; } - f << stringf("\n },\n"); + f << stringf("\n }"); - f << stringf(" \"cells\": {"); - first = true; - for (auto c : module->cells()) { - if (use_selection && !module->selected(c)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(c->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); - f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); - if (aig_mode) { - Aig aig(c); - if (!aig.name.empty()) { - f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); - aig_models.insert(aig); + if (!module->get_blackbox_attribute()) { + f << stringf(",\n \"cells\": {"); + first = true; + for (auto c : module->cells()) { + if (use_selection && !module->selected(c)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(c->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); + f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); + if (aig_mode) { + Aig aig(c); + if (!aig.name.empty()) { + f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); + aig_models.insert(aig); + } } - } - f << stringf(" \"parameters\": {"); - write_parameters(c->parameters); - f << stringf("\n },\n"); - f << stringf(" \"attributes\": {"); - write_parameters(c->attributes); - f << stringf("\n },\n"); - if (c->known()) { - f << stringf(" \"port_directions\": {"); + f << stringf(" \"parameters\": {"); + write_parameters(c->parameters); + f << stringf("\n },\n"); + f << stringf(" \"attributes\": {"); + write_parameters(c->attributes); + f << stringf("\n },\n"); + if (c->known()) { + f << stringf(" \"port_directions\": {"); + bool first2 = true; + for (auto &conn : c->connections()) { + string direction = "output"; + if (c->input(conn.first)) + direction = c->output(conn.first) ? "inout" : "input"; + f << stringf("%s\n", first2 ? "" : ","); + f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); + first2 = false; + } + f << stringf("\n },\n"); + } + f << stringf(" \"connections\": {"); bool first2 = true; for (auto &conn : c->connections()) { - string direction = "output"; - if (c->input(conn.first)) - direction = c->output(conn.first) ? "inout" : "input"; f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); + f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); first2 = false; } - f << stringf("\n },\n"); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; } - f << stringf(" \"connections\": {"); - bool first2 = true; - for (auto &conn : c->connections()) { - f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); - first2 = false; - } - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; - } - f << stringf("\n },\n"); + f << stringf("\n },\n"); - f << stringf(" \"netnames\": {"); - first = true; - for (auto w : module->wires()) { - if (use_selection && !module->selected(w)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(w->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); - f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); - f << stringf(" \"attributes\": {"); - write_parameters(w->attributes); - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; + f << stringf(" \"netnames\": {"); + first = true; + for (auto w : module->wires()) { + if (use_selection && !module->selected(w)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(w->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); + f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); + f << stringf(" \"attributes\": {"); + write_parameters(w->attributes); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; + } + f << stringf("\n }"); } - f << stringf("\n }\n"); + f << stringf("\n"); f << stringf(" }"); } From e6253244899760e580fd822f3017259f8f15a45c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 18 Apr 2019 18:51:36 +0200 Subject: [PATCH 103/149] Update to ABC 3709744 Signed-off-by: Clifford Wolf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f705db9ec..4f47d8abb 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ OBJS = kernel/version_$(GIT_REV).o # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = d1b6413 +ABCREV = 3709744 ABCPULL = 1 ABCURL ?= https://github.com/berkeley-abc/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 From 8f93999129bfcd957dbb312d804c01525af6d07e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 18 Apr 2019 23:05:59 -0700 Subject: [PATCH 104/149] Revert "write_json to not write contents (cells/wires) of whiteboxes" This reverts commit 4ef03e19a8eafc324d3442f0642abf858071fdd4. --- backends/json/json.cc | 115 ++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/backends/json/json.cc b/backends/json/json.cc index b4f82a3fe..f5c687981 100644 --- a/backends/json/json.cc +++ b/backends/json/json.cc @@ -130,75 +130,72 @@ struct JsonWriter f << stringf(" }"); first = false; } - f << stringf("\n }"); + f << stringf("\n },\n"); - if (!module->get_blackbox_attribute()) { - f << stringf(",\n \"cells\": {"); - first = true; - for (auto c : module->cells()) { - if (use_selection && !module->selected(c)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(c->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); - f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); - if (aig_mode) { - Aig aig(c); - if (!aig.name.empty()) { - f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); - aig_models.insert(aig); - } + f << stringf(" \"cells\": {"); + first = true; + for (auto c : module->cells()) { + if (use_selection && !module->selected(c)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(c->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", c->name[0] == '$' ? "1" : "0"); + f << stringf(" \"type\": %s,\n", get_name(c->type).c_str()); + if (aig_mode) { + Aig aig(c); + if (!aig.name.empty()) { + f << stringf(" \"model\": \"%s\",\n", aig.name.c_str()); + aig_models.insert(aig); } - f << stringf(" \"parameters\": {"); - write_parameters(c->parameters); - f << stringf("\n },\n"); - f << stringf(" \"attributes\": {"); - write_parameters(c->attributes); - f << stringf("\n },\n"); - if (c->known()) { - f << stringf(" \"port_directions\": {"); - bool first2 = true; - for (auto &conn : c->connections()) { - string direction = "output"; - if (c->input(conn.first)) - direction = c->output(conn.first) ? "inout" : "input"; - f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); - first2 = false; - } - f << stringf("\n },\n"); - } - f << stringf(" \"connections\": {"); + } + f << stringf(" \"parameters\": {"); + write_parameters(c->parameters); + f << stringf("\n },\n"); + f << stringf(" \"attributes\": {"); + write_parameters(c->attributes); + f << stringf("\n },\n"); + if (c->known()) { + f << stringf(" \"port_directions\": {"); bool first2 = true; for (auto &conn : c->connections()) { + string direction = "output"; + if (c->input(conn.first)) + direction = c->output(conn.first) ? "inout" : "input"; f << stringf("%s\n", first2 ? "" : ","); - f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); + f << stringf(" %s: \"%s\"", get_name(conn.first).c_str(), direction.c_str()); first2 = false; } - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; + f << stringf("\n },\n"); } - f << stringf("\n },\n"); - - f << stringf(" \"netnames\": {"); - first = true; - for (auto w : module->wires()) { - if (use_selection && !module->selected(w)) - continue; - f << stringf("%s\n", first ? "" : ","); - f << stringf(" %s: {\n", get_name(w->name).c_str()); - f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); - f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); - f << stringf(" \"attributes\": {"); - write_parameters(w->attributes); - f << stringf("\n }\n"); - f << stringf(" }"); - first = false; + f << stringf(" \"connections\": {"); + bool first2 = true; + for (auto &conn : c->connections()) { + f << stringf("%s\n", first2 ? "" : ","); + f << stringf(" %s: %s", get_name(conn.first).c_str(), get_bits(conn.second).c_str()); + first2 = false; } - f << stringf("\n }"); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; } - f << stringf("\n"); + f << stringf("\n },\n"); + + f << stringf(" \"netnames\": {"); + first = true; + for (auto w : module->wires()) { + if (use_selection && !module->selected(w)) + continue; + f << stringf("%s\n", first ? "" : ","); + f << stringf(" %s: {\n", get_name(w->name).c_str()); + f << stringf(" \"hide_name\": %s,\n", w->name[0] == '$' ? "1" : "0"); + f << stringf(" \"bits\": %s,\n", get_bits(w).c_str()); + f << stringf(" \"attributes\": {"); + write_parameters(w->attributes); + f << stringf("\n }\n"); + f << stringf(" }"); + first = false; + } + f << stringf("\n }\n"); f << stringf(" }"); } From 9dec3d997821e274b71e67c38582c29f4ae5dfac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 11 Apr 2019 15:09:13 -0700 Subject: [PATCH 105/149] Spelling fixes --- passes/techmap/pmuxtree.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/pmuxtree.cc b/passes/techmap/pmuxtree.cc index b7a22dc3b..6a923f481 100644 --- a/passes/techmap/pmuxtree.cc +++ b/passes/techmap/pmuxtree.cc @@ -71,9 +71,9 @@ struct PmuxtreePass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" pmuxtree [options] [selection]\n"); + log(" pmuxtree [selection]\n"); log("\n"); - log("This pass transforms $pmux cells to a trees of $mux cells.\n"); + log("This pass transforms $pmux cells to trees of $mux cells.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE From ea2a21445efa49d2e3f4bb730ceb0a9034f7cb7a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 14:04:12 +0200 Subject: [PATCH 106/149] Add tests/aiger/.gitignore Signed-off-by: Clifford Wolf --- tests/aiger/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tests/aiger/.gitignore diff --git a/tests/aiger/.gitignore b/tests/aiger/.gitignore new file mode 100644 index 000000000..073f46157 --- /dev/null +++ b/tests/aiger/.gitignore @@ -0,0 +1,2 @@ +*.log +*.out From 148caecca30ec4e8ebd459993f28560438131cb8 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 21:17:12 +0200 Subject: [PATCH 107/149] Change "ne" to "neq" in btor2 output we need to do this because they changed the parser: https://github.com/Boolector/btor2tools/commit/e97fc9cedabadeec4f621de22096e514f862c690 Signed-off-by: Clifford Wolf --- backends/btor/btor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/btor/btor.cc b/backends/btor/btor.cc index 55c494996..91f238fa5 100644 --- a/backends/btor/btor.cc +++ b/backends/btor/btor.cc @@ -340,7 +340,7 @@ struct BtorWorker if (cell->type == "$lt") btor_op = "lt"; if (cell->type == "$le") btor_op = "lte"; if (cell->type.in("$eq", "$eqx")) btor_op = "eq"; - if (cell->type.in("$ne", "$nex")) btor_op = "ne"; + if (cell->type.in("$ne", "$nex")) btor_op = "neq"; if (cell->type == "$ge") btor_op = "gte"; if (cell->type == "$gt") btor_op = "gt"; log_assert(!btor_op.empty()); From eafc4bd49f3ff1e6a9e934aae065de183ca3a90e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 00:37:43 +0200 Subject: [PATCH 108/149] Improve "show" handling of 0/1/X/Z padding Signed-off-by: Clifford Wolf --- passes/cmds/show.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/passes/cmds/show.cc b/passes/cmds/show.cc index 58acd302d..0eadd904a 100644 --- a/passes/cmds/show.cc +++ b/passes/cmds/show.cc @@ -237,15 +237,34 @@ struct ShowWorker int idx = single_idx_count++; for (int rep, i = int(sig.chunks().size())-1; i >= 0; i -= rep) { const RTLIL::SigChunk &c = sig.chunks().at(i); - net = gen_signode_simple(c, false); - log_assert(!net.empty()); + if (!driver && c.wire == nullptr) { + RTLIL::State s1 = c.data.front(); + for (auto s2 : c.data) + if (s1 != s2) + goto not_const_stream; + net.clear(); + } else { + not_const_stream: + net = gen_signode_simple(c, false); + log_assert(!net.empty()); + } for (rep = 1; i-rep >= 0 && c == sig.chunks().at(i-rep); rep++) {} std::string repinfo = rep > 1 ? stringf("%dx ", rep) : ""; if (driver) { + log_assert(!net.empty()); label_string += stringf(" %d:%d - %s%d:%d |", i, pos, pos-c.width+1, repinfo.c_str(), c.offset+c.width-1, c.offset); net_conn_map[net].in.insert(stringf("x%d:s%d", idx, i)); net_conn_map[net].bits = rep*c.width; net_conn_map[net].color = nextColor(c, net_conn_map[net].color); + } else + if (net.empty()) { + log_assert(rep == 1); + label_string += stringf("%c -> %d:%d |", + c.data.front() == State::S0 ? '0' : + c.data.front() == State::S1 ? '1' : + c.data.front() == State::Sx ? 'X' : + c.data.front() == State::Sz ? 'Z' : '?', + pos, pos-rep*c.width+1); } else { label_string += stringf(" %s%d:%d - %d:%d |", i, repinfo.c_str(), c.offset+c.width-1, c.offset, pos, pos-rep*c.width+1); net_conn_map[net].out.insert(stringf("x%d:s%d", idx, i)); From 1bf8c2b823992569830cf0d248cb12bfccd5f384 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 14:03:05 +0200 Subject: [PATCH 109/149] Import initial pmux2shiftx from eddieh Signed-off-by: Clifford Wolf --- passes/opt/Makefile.inc | 1 + passes/opt/pmux2shiftx.cc | 81 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 passes/opt/pmux2shiftx.cc diff --git a/passes/opt/Makefile.inc b/passes/opt/Makefile.inc index c3e0a2a40..337fee9e4 100644 --- a/passes/opt/Makefile.inc +++ b/passes/opt/Makefile.inc @@ -13,5 +13,6 @@ OBJS += passes/opt/wreduce.o OBJS += passes/opt/opt_demorgan.o OBJS += passes/opt/rmports.o OBJS += passes/opt/opt_lut.o +OBJS += passes/opt/pmux2shiftx.o endif diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc new file mode 100644 index 000000000..6ffc27a4c --- /dev/null +++ b/passes/opt/pmux2shiftx.cc @@ -0,0 +1,81 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Pmux2ShiftxPass : public Pass { + Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" pmux2shiftx [selection]\n"); + log("\n"); + log("This pass transforms $pmux cells to $shiftx cells.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing PMUX2SHIFTX pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + for (auto cell : module->selected_cells()) + { + if (cell->type != "$pmux") + continue; + + // Create a new encoder, out of a $pmux, that takes + // the existing pmux's 'S' input and transforms it + // back into a binary value + RTLIL::SigSpec shiftx_a; + RTLIL::SigSpec pmux_s; + + int s_width = cell->getParam("\\S_WIDTH").as_int(); + if (!cell->getPort("\\A").is_fully_undef()) { + ++s_width; + shiftx_a.append(cell->getPort("\\A")); + pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); + } + const int clog2width = ceil(log2(s_width)); + + RTLIL::SigSpec pmux_b; + for (int i = s_width-1; i >= 0; i--) + pmux_b.append(RTLIL::Const(i, clog2width)); + shiftx_a.append(cell->getPort("\\B")); + pmux_s.append(cell->getPort("\\S")); + + RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); + module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); + module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); + module->remove(cell); + } + } +} Pmux2ShiftxPass; + +PRIVATE_NAMESPACE_END From 481f0015be48e7662f6fc55ca8bbb46c51829ccb Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 18:10:12 +0200 Subject: [PATCH 110/149] Complete rewrite of pmux2shiftx Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 284 +++++++++++++++++++++++++++++++++++--- 1 file changed, 261 insertions(+), 23 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 6ffc27a4c..8ea70fe84 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -45,35 +45,273 @@ struct Pmux2ShiftxPass : public Pass { extra_args(args, argidx, design); for (auto module : design->selected_modules()) - for (auto cell : module->selected_cells()) { - if (cell->type != "$pmux") - continue; + SigMap sigmap(module); - // Create a new encoder, out of a $pmux, that takes - // the existing pmux's 'S' input and transforms it - // back into a binary value - RTLIL::SigSpec shiftx_a; - RTLIL::SigSpec pmux_s; + dict> eqdb; - int s_width = cell->getParam("\\S_WIDTH").as_int(); - if (!cell->getPort("\\A").is_fully_undef()) { - ++s_width; - shiftx_a.append(cell->getPort("\\A")); - pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); + for (auto cell : module->selected_cells()) + { + if (cell->type == "$eq") + { + dict bits; + + SigSpec A = sigmap(cell->getPort("\\A")); + SigSpec B = sigmap(cell->getPort("\\B")); + + int a_width = cell->getParam("\\A_WIDTH").as_int(); + int b_width = cell->getParam("\\B_WIDTH").as_int(); + + if (a_width < b_width) { + bool a_signed = cell->getParam("\\A_SIGNED").as_int(); + A.extend_u0(b_width, a_signed); + } + + if (b_width < a_width) { + bool b_signed = cell->getParam("\\B_SIGNED").as_int(); + B.extend_u0(a_width, b_signed); + } + + for (int i = 0; i < GetSize(A); i++) { + SigBit a_bit = A[i], b_bit = B[i]; + if (b_bit.wire && !a_bit.wire) { + std::swap(a_bit, b_bit); + } + if (!a_bit.wire || b_bit.wire) + goto next_cell; + if (bits.count(a_bit)) + goto next_cell; + bits[a_bit] = b_bit.data; + } + + if (GetSize(bits) > 20) + goto next_cell; + + bits.sort(); + pair entry; + + for (auto it : bits) { + entry.first.append_bit(it.first); + entry.second.bits.push_back(it.second); + } + + eqdb[sigmap(cell->getPort("\\Y")[0])] = entry; + goto next_cell; + } + + if (cell->type == "$logic_not") + { + dict bits; + + SigSpec A = sigmap(cell->getPort("\\A")); + + for (int i = 0; i < GetSize(A); i++) + bits[A[i]] = State::S0; + + bits.sort(); + pair entry; + + for (auto it : bits) { + entry.first.append_bit(it.first); + entry.second.bits.push_back(it.second); + } + + eqdb[sigmap(cell->getPort("\\Y")[0])] = entry; + goto next_cell; + } + next_cell:; } - const int clog2width = ceil(log2(s_width)); - RTLIL::SigSpec pmux_b; - for (int i = s_width-1; i >= 0; i--) - pmux_b.append(RTLIL::Const(i, clog2width)); - shiftx_a.append(cell->getPort("\\B")); - pmux_s.append(cell->getPort("\\S")); + for (auto cell : module->selected_cells()) + { + if (cell->type != "$pmux") + continue; - RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); - module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); - module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); - module->remove(cell); + string src = cell->get_src_attribute(); + int width = cell->getParam("\\WIDTH").as_int(); + int width_bits = ceil_log2(width); + int extwidth = width; + + while (extwidth & (extwidth-1)) + extwidth++; + + dict> seldb; + + SigSpec S = sigmap(cell->getPort("\\S")); + for (int i = 0; i < GetSize(S); i++) + { + if (!eqdb.count(S[i])) + continue; + + auto &entry = eqdb.at(S[i]); + seldb[entry.first].insert(i); + } + + if (seldb.empty()) + continue; + + log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); + log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + + SigSpec updated_S = cell->getPort("\\S"); + SigSpec updated_B = cell->getPort("\\B"); + + #if 1 + for (auto &it : seldb) { + string msg = stringf("seldb: %s ->", log_signal(it.first)); + for (int i : it.second) + msg += stringf(" %d(%s)", i, log_signal(eqdb.at(S[i]).second)); + log(" %s\n", msg.c_str()); + } + #endif + + while (!seldb.empty()) + { + // pick the largest entry in seldb + SigSpec sig = seldb.begin()->first; + for (auto &it : seldb) { + if (GetSize(sig) < GetSize(it.first)) + sig = it.first; + else if (GetSize(seldb.at(sig)) < GetSize(it.second)) + sig = it.first; + } + + log(" checking ctrl signal %s\n", log_signal(sig)); + + // find the relevant choices + dict choices; + vector onescnt(GetSize(sig)); + for (int i : seldb.at(sig)) { + Const val = eqdb.at(S[i]).second; + choices[val] = i; + for (int k = 0; k < GetSize(val); k++) + if (val[k] == State::S1) + onescnt[k] |= 1; + else + onescnt[k] |= 2; + } + + // TBD: also find choices that are using signals that are subsets of the bits in "sig" + + // find the best permutation + vector> perm(GetSize(sig)); + for (int i = 0; i < GetSize(onescnt); i++) + perm[i] = make_pair(onescnt[i], i); + // TBD: this is not the best permutation + std::sort(perm.rbegin(), perm.rend()); + + // permutated sig + Const perm_xormask(State::S0, GetSize(sig)); + SigSpec perm_sig(State::S0, GetSize(sig)); + for (int i = 0; i < GetSize(sig); i++) { + if (perm[i].first == 1) + perm_xormask[i] = State::S1; + perm_sig[i] = sig[perm[i].second]; + } + + log(" best permutation: %s\n", log_signal(perm_sig)); + log(" best xor mask: %s\n", log_signal(perm_xormask)); + + // permutated choices + int min_choice = 1 << 30; + int max_choice = -1; + dict perm_choices; + + for (auto &it : choices) + { + Const &old_c = it.first; + Const new_c(State::S0, GetSize(old_c)); + + for (int i = 0; i < GetSize(old_c); i++) + new_c[i] = old_c[perm[i].second]; + + Const new_c_before_xor = new_c; + new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c)); + + perm_choices[new_c] = it.second; + + min_choice = std::min(min_choice, new_c.as_int()); + max_choice = std::max(max_choice, new_c.as_int()); + + log(" %s -> %s -> %s\n", log_signal(old_c), log_signal(new_c_before_xor), log_signal(new_c)); + } + + log(" choices: %d\n", GetSize(choices)); + log(" min choice: %d\n", min_choice); + log(" max choice: %d\n", max_choice); + log(" range density: %d%%\n", 100*GetSize(choices)/(max_choice-min_choice+1)); + log(" absolute density: %d%%\n", 100*GetSize(choices)/(max_choice+1)); + + bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (max_choice+1 == GetSize(choices)); + log(" full case: %s\n", full_case ? "true" : "false"); + + // use arithmetic offset if density is less than 30% + Const offset(State::S0, GetSize(sig)); + if (3*GetSize(choices) < max_choice && 3*GetSize(choices) >= (max_choice-min_choice)) + { + log(" using offset method.\n"); + + offset = Const(min_choice, GetSize(sig)); + min_choice -= offset.as_int(); + max_choice -= offset.as_int(); + + dict new_perm_choices; + for (auto &it : perm_choices) + new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; + perm_choices.swap(new_perm_choices); + } + + // ignore cases with a absolute density of less than 30% + if (3*GetSize(choices) < max_choice) { + log(" insufficient density.\n"); + seldb.erase(sig); + continue; + } + + // creat cmp signal + SigSpec cmp = perm_sig; + if (perm_xormask.as_bool()) + cmp = module->Xor(NEW_ID, cmp, perm_xormask, false, src); + if (offset.as_bool()) + cmp = module->Sub(NEW_ID, cmp, offset, false, src); + + // create enable signal + SigBit en = State::S1; + if (!full_case) { + Const enable_mask(State::S0, max_choice+1); + for (auto &it : perm_choices) + enable_mask[it.first.as_int()] = State::S1; + en = module->addWire(NEW_ID); + module->addShift(NEW_ID, enable_mask, cmp, en, false, src); + } + + // create data signal + SigSpec data(State::Sx, (max_choice+1)*extwidth); + for (auto &it : perm_choices) { + int position = it.first.as_int()*extwidth; + int data_index = it.second; + data.replace(position, cell->getPort("\\B").extract(data_index*width, width)); + updated_S[data_index] = State::S0; + updated_B.replace(data_index*width, SigSpec(State::Sx, width)); + } + + // create shiftx cell + SigSpec shifted_cmp = {cmp, SigSpec(State::S0, width_bits)}; + SigSpec outsig = module->addWire(NEW_ID, width); + Cell *c = module->addShiftx(NEW_ID, data, shifted_cmp, outsig, false, src); + updated_S.append(en); + updated_B.append(outsig); + log(" created $shiftx cell %s.\n", log_id(c)); + + // remove this sig and continue with the next block + seldb.erase(sig); + } + + // update $pmux cell + cell->setPort("\\S", updated_S); + cell->setPort("\\B", updated_B); + cell->setParam("\\S_WIDTH", GetSize(updated_S)); + } } } } Pmux2ShiftxPass; From 177878cbb091f9339ee68a904f57f0283bdcfe10 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 20:20:08 +0200 Subject: [PATCH 111/149] Improve pmux2shift ctrl permutation finder Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 141 ++++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 27 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 8ea70fe84..daa73b0b8 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -29,17 +29,29 @@ struct Pmux2ShiftxPass : public Pass { { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" pmux2shiftx [selection]\n"); + log(" pmux2shiftx [options] [selection]\n"); log("\n"); log("This pass transforms $pmux cells to $shiftx cells.\n"); log("\n"); + log(" -density non_offset_percentage offset_percentage\n"); + log(" specifies the minimum density for non_offset- and for offset-mode\n"); + log(" default values are 30 (non-offset) and 50 (offset)\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { + int non_offset_percentage = 30; + int offset_percentage = 50; + log_header(design, "Executing PMUX2SHIFTX pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-density" && argidx+2 < args.size()) { + non_offset_percentage = atoi(args[++argidx].c_str()); + offset_percentage = atoi(args[++argidx].c_str()); + continue; + } break; } extra_args(args, argidx, design); @@ -180,34 +192,108 @@ struct Pmux2ShiftxPass : public Pass { // find the relevant choices dict choices; - vector onescnt(GetSize(sig)); for (int i : seldb.at(sig)) { Const val = eqdb.at(S[i]).second; choices[val] = i; - for (int k = 0; k < GetSize(val); k++) - if (val[k] == State::S1) - onescnt[k] |= 1; - else - onescnt[k] |= 2; } // TBD: also find choices that are using signals that are subsets of the bits in "sig" // find the best permutation - vector> perm(GetSize(sig)); - for (int i = 0; i < GetSize(onescnt); i++) - perm[i] = make_pair(onescnt[i], i); - // TBD: this is not the best permutation - std::sort(perm.rbegin(), perm.rend()); + vector perm_new_from_old(GetSize(sig)); + Const perm_xormask(State::S0, GetSize(sig)); + { + vector values(GetSize(choices)); + vector used_src_columns(GetSize(sig)); + vector> columns(GetSize(sig), vector(GetSize(values))); + + for (int i = 0; i < GetSize(choices); i++) { + Const val = choices.element(i)->first; + for (int k = 0; k < GetSize(val); k++) + if (val[k] == State::S1) + columns[k][i] = true; + } + + for (int dst_col = GetSize(sig)-1; dst_col >= 0; dst_col--) + { + int best_src_col = -1; + bool best_inv = false; + int best_maxval = 0; + int best_delta = 0; + + // find best src colum for this dst column + for (int src_col = 0; src_col < GetSize(sig); src_col++) + { + if (used_src_columns[src_col]) + continue; + + int this_maxval = 0; + int this_minval = 1 << 30; + + int this_inv_maxval = 0; + int this_inv_minval = 1 << 30; + + for (int i = 0; i < GetSize(values); i++) + { + int val = values[i]; + int inv_val = val; + + if (columns[src_col][i]) + val |= 1 << dst_col; + else + inv_val |= 1 << dst_col; + + this_maxval = std::max(this_maxval, val); + this_minval = std::min(this_minval, val); + + this_inv_maxval = std::max(this_inv_maxval, inv_val); + this_inv_minval = std::min(this_inv_minval, inv_val); + } + + int this_delta = this_maxval - this_minval; + int this_inv_delta = this_maxval - this_minval; + bool this_inv = false; + + if (this_delta != this_inv_delta) + this_inv = this_inv_delta < this_delta; + else if (this_maxval != this_inv_maxval) + this_inv = this_inv_maxval < this_maxval; + + if (this_inv) { + this_delta = this_inv_delta; + this_maxval = this_inv_maxval; + this_minval = this_inv_minval; + } + + bool this_is_better = false; + + if (best_src_col < 0) + this_is_better = true; + else if (this_delta != best_delta) + this_is_better = this_delta < best_delta; + else if (this_maxval != best_maxval) + this_is_better = this_maxval < best_maxval; + else + this_is_better = sig[best_src_col] < sig[src_col]; + + if (this_is_better) { + best_src_col = src_col; + best_inv = this_inv; + best_maxval = this_maxval; + best_delta = this_delta; + } + } + + used_src_columns[best_src_col] = true; + perm_new_from_old[dst_col] = best_src_col; + perm_xormask[dst_col] = best_inv ? State::S1 : State::S0; + } + } // permutated sig - Const perm_xormask(State::S0, GetSize(sig)); SigSpec perm_sig(State::S0, GetSize(sig)); - for (int i = 0; i < GetSize(sig); i++) { - if (perm[i].first == 1) - perm_xormask[i] = State::S1; - perm_sig[i] = sig[perm[i].second]; - } + for (int i = 0; i < GetSize(sig); i++) + perm_sig[i] = sig[perm_new_from_old[i]]; log(" best permutation: %s\n", log_signal(perm_sig)); log(" best xor mask: %s\n", log_signal(perm_xormask)); @@ -223,7 +309,7 @@ struct Pmux2ShiftxPass : public Pass { Const new_c(State::S0, GetSize(old_c)); for (int i = 0; i < GetSize(old_c); i++) - new_c[i] = old_c[perm[i].second]; + new_c[i] = old_c[perm_new_from_old[i]]; Const new_c_before_xor = new_c; new_c = const_xor(new_c, perm_xormask, false, false, GetSize(new_c)); @@ -236,18 +322,21 @@ struct Pmux2ShiftxPass : public Pass { log(" %s -> %s -> %s\n", log_signal(old_c), log_signal(new_c_before_xor), log_signal(new_c)); } + int range_density = 100*GetSize(choices) / (max_choice-min_choice+1); + int absolute_density = 100*GetSize(choices) / (max_choice+1); + log(" choices: %d\n", GetSize(choices)); log(" min choice: %d\n", min_choice); log(" max choice: %d\n", max_choice); - log(" range density: %d%%\n", 100*GetSize(choices)/(max_choice-min_choice+1)); - log(" absolute density: %d%%\n", 100*GetSize(choices)/(max_choice+1)); + log(" range density: %d%%\n", range_density); + log(" absolute density: %d%%\n", absolute_density); bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (max_choice+1 == GetSize(choices)); log(" full case: %s\n", full_case ? "true" : "false"); - // use arithmetic offset if density is less than 30% + // check density percentages Const offset(State::S0, GetSize(sig)); - if (3*GetSize(choices) < max_choice && 3*GetSize(choices) >= (max_choice-min_choice)) + if (absolute_density < non_offset_percentage && range_density >= offset_percentage) { log(" using offset method.\n"); @@ -259,10 +348,8 @@ struct Pmux2ShiftxPass : public Pass { for (auto &it : perm_choices) new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; perm_choices.swap(new_perm_choices); - } - - // ignore cases with a absolute density of less than 30% - if (3*GetSize(choices) < max_choice) { + } else + if (absolute_density < non_offset_percentage) { log(" insufficient density.\n"); seldb.erase(sig); continue; From 4c831d72ef2d3a9f9b91d6fa27e09800ae09e869 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 20:23:09 +0200 Subject: [PATCH 112/149] Add test for pmux2shiftx Signed-off-by: Clifford Wolf --- tests/various/pmux2shiftx.v | 28 ++++++++++++++++++++++++++++ tests/various/pmux2shiftx.ys | 24 ++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/various/pmux2shiftx.v create mode 100644 tests/various/pmux2shiftx.ys diff --git a/tests/various/pmux2shiftx.v b/tests/various/pmux2shiftx.v new file mode 100644 index 000000000..ac61c5c0e --- /dev/null +++ b/tests/various/pmux2shiftx.v @@ -0,0 +1,28 @@ +module pmux2shiftx_test ( + input [2:0] S1, + input [5:0] S2, + input [9:0] A, B, C, D, D, E, F, + input [9:0] G, H, I, J, K, L, M, N, + output reg [9:0] X +); + always @* begin + case (S1) + 3'd0: X = A; + 3'd1: X = B; + 3'd2: X = C; + 3'd3: X = D; + 3'd4: X = E; + 3'd5: X = F; + 3'd6: X = G; + 3'd7: X = H; + endcase + case (S2) + 6'd46: X = I; + 6'd47: X = J; + 6'd48: X = K; + 6'd52: X = L; + 6'd53: X = M; + 6'd54: X = N; + endcase + end +endmodule diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys new file mode 100644 index 000000000..16618ac0a --- /dev/null +++ b/tests/various/pmux2shiftx.ys @@ -0,0 +1,24 @@ +read_verilog pmux2shiftx.v +prep +design -save gold + +pmux2shiftx +opt +# show -width +select -assert-count 1 t:$mux +select -assert-count 1 t:$shift +select -assert-count 2 t:$shiftx +select -assert-count 1 t:$sub +design -stash gate + +design -import gold -as gold +design -import gate -as gate + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -show-ports miter + +design -load gold +stat + +design -load gate +stat From 0070184ea9dea56d1dfd8268035bc01a3e340add Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Fri, 19 Apr 2019 23:37:11 +0200 Subject: [PATCH 113/149] Improvements in pmux2shiftx Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 19 ++++++------------ tests/various/pmux2shiftx.v | 38 +++++++++++++++++++++--------------- tests/various/pmux2shiftx.ys | 12 ++++++++---- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index daa73b0b8..d0f41cb07 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -149,6 +149,7 @@ struct Pmux2ShiftxPass : public Pass { dict> seldb; + SigSpec B = cell->getPort("\\B"); SigSpec S = sigmap(cell->getPort("\\S")); for (int i = 0; i < GetSize(S); i++) { @@ -168,15 +169,6 @@ struct Pmux2ShiftxPass : public Pass { SigSpec updated_S = cell->getPort("\\S"); SigSpec updated_B = cell->getPort("\\B"); - #if 1 - for (auto &it : seldb) { - string msg = stringf("seldb: %s ->", log_signal(it.first)); - for (int i : it.second) - msg += stringf(" %d(%s)", i, log_signal(eqdb.at(S[i]).second)); - log(" %s\n", msg.c_str()); - } - #endif - while (!seldb.empty()) { // pick the largest entry in seldb @@ -319,7 +311,8 @@ struct Pmux2ShiftxPass : public Pass { min_choice = std::min(min_choice, new_c.as_int()); max_choice = std::max(max_choice, new_c.as_int()); - log(" %s -> %s -> %s\n", log_signal(old_c), log_signal(new_c_before_xor), log_signal(new_c)); + log(" %3d: %s -> %s -> %s: %s\n", it.second, log_signal(old_c), log_signal(new_c_before_xor), + log_signal(new_c), log_signal(B.extract(it.second*width, width))); } int range_density = 100*GetSize(choices) / (max_choice-min_choice+1); @@ -338,9 +331,9 @@ struct Pmux2ShiftxPass : public Pass { Const offset(State::S0, GetSize(sig)); if (absolute_density < non_offset_percentage && range_density >= offset_percentage) { - log(" using offset method.\n"); - offset = Const(min_choice, GetSize(sig)); + log(" offset: %s\n", log_signal(offset)); + min_choice -= offset.as_int(); max_choice -= offset.as_int(); @@ -377,7 +370,7 @@ struct Pmux2ShiftxPass : public Pass { for (auto &it : perm_choices) { int position = it.first.as_int()*extwidth; int data_index = it.second; - data.replace(position, cell->getPort("\\B").extract(data_index*width, width)); + data.replace(position, B.extract(data_index*width, width)); updated_S[data_index] = State::S0; updated_B.replace(data_index*width, SigSpec(State::Sx, width)); } diff --git a/tests/various/pmux2shiftx.v b/tests/various/pmux2shiftx.v index ac61c5c0e..fec84187b 100644 --- a/tests/various/pmux2shiftx.v +++ b/tests/various/pmux2shiftx.v @@ -1,28 +1,34 @@ module pmux2shiftx_test ( input [2:0] S1, input [5:0] S2, - input [9:0] A, B, C, D, D, E, F, - input [9:0] G, H, I, J, K, L, M, N, + input [1:0] S3, + input [9:0] A, B, C, D, D, E, F, G, H, + input [9:0] I, J, K, L, M, N, O, P, Q, output reg [9:0] X ); always @* begin case (S1) - 3'd0: X = A; - 3'd1: X = B; - 3'd2: X = C; - 3'd3: X = D; - 3'd4: X = E; - 3'd5: X = F; - 3'd6: X = G; - 3'd7: X = H; + 3'd 0: X = A; + 3'd 1: X = B; + 3'd 2: X = C; + 3'd 3: X = D; + 3'd 4: X = E; + 3'd 5: X = F; + 3'd 6: X = G; + 3'd 7: X = H; endcase case (S2) - 6'd46: X = I; - 6'd47: X = J; - 6'd48: X = K; - 6'd52: X = L; - 6'd53: X = M; - 6'd54: X = N; + 6'd 45: X = I; + 6'd 47: X = J; + 6'd 49: X = K; + 6'd 55: X = L; + 6'd 57: X = M; + 6'd 59: X = N; + endcase + case (S3) + 2'd 1: X = O; + 2'd 2: X = P; + 2'd 3: X = Q; endcase end endmodule diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys index 16618ac0a..f5e83171c 100644 --- a/tests/various/pmux2shiftx.ys +++ b/tests/various/pmux2shiftx.ys @@ -2,13 +2,17 @@ read_verilog pmux2shiftx.v prep design -save gold -pmux2shiftx +pmux2shiftx -density 70 50 + opt + +stat # show -width -select -assert-count 1 t:$mux -select -assert-count 1 t:$shift -select -assert-count 2 t:$shiftx select -assert-count 1 t:$sub +select -assert-count 2 t:$mux +select -assert-count 2 t:$shift +select -assert-count 3 t:$shiftx + design -stash gate design -import gold -as gold From 37728520a6d559a9f9a0082ddb3d596e8a634d97 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 01:15:48 +0200 Subject: [PATCH 114/149] Improvements in "pmux2shiftx" Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 64 +++++++++++++++++++++++++++++------- tests/various/pmux2shiftx.ys | 2 +- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index d0f41cb07..e6a0bd06b 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -33,23 +33,41 @@ struct Pmux2ShiftxPass : public Pass { log("\n"); log("This pass transforms $pmux cells to $shiftx cells.\n"); log("\n"); - log(" -density non_offset_percentage offset_percentage\n"); + log(" -min_density \n"); log(" specifies the minimum density for non_offset- and for offset-mode\n"); log(" default values are 30 (non-offset) and 50 (offset)\n"); log("\n"); + log(" -min_choices \n"); + log(" specified the minimum number of choices for a control signal\n"); + log(" defaukt: 3\n"); + log("\n"); + log(" -allow_onehot\n"); + log(" by default, pmuxes with one-hot encoded control signals are not\n"); + log(" converted. this option disables that check.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - int non_offset_percentage = 30; - int offset_percentage = 50; + int min_non_offset_percentage = 30; + int min_offset_percentage = 50; + int min_choices = 3; + bool allow_onehot = false; log_header(design, "Executing PMUX2SHIFTX pass.\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-density" && argidx+2 < args.size()) { - non_offset_percentage = atoi(args[++argidx].c_str()); - offset_percentage = atoi(args[++argidx].c_str()); + if (args[argidx] == "-min_density" && argidx+2 < args.size()) { + min_non_offset_percentage = atoi(args[++argidx].c_str()); + min_offset_percentage = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-min_choices" && argidx+1 < args.size()) { + min_choices = atoi(args[++argidx].c_str()); + continue; + } + if (args[argidx] == "-allow_onehot") { + allow_onehot = true; continue; } break; @@ -163,8 +181,7 @@ struct Pmux2ShiftxPass : public Pass { if (seldb.empty()) continue; - log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); - log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + bool printed_pmux_header = false; SigSpec updated_S = cell->getPort("\\S"); SigSpec updated_B = cell->getPort("\\B"); @@ -180,17 +197,40 @@ struct Pmux2ShiftxPass : public Pass { sig = it.first; } - log(" checking ctrl signal %s\n", log_signal(sig)); - // find the relevant choices + bool is_onehot = true; dict choices; for (int i : seldb.at(sig)) { Const val = eqdb.at(S[i]).second; + int onebits = 0; + for (auto b : val.bits) + if (b == State::S1) + onebits++; + if (onebits > 1) + is_onehot = false; choices[val] = i; } // TBD: also find choices that are using signals that are subsets of the bits in "sig" + if (is_onehot && !allow_onehot) { + seldb.erase(sig); + continue; + } + + if (GetSize(choices) < min_choices) { + seldb.erase(sig); + continue; + } + + if (!printed_pmux_header) { + printed_pmux_header = true; + log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); + log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + } + + log(" checking ctrl signal %s\n", log_signal(sig)); + // find the best permutation vector perm_new_from_old(GetSize(sig)); Const perm_xormask(State::S0, GetSize(sig)); @@ -329,7 +369,7 @@ struct Pmux2ShiftxPass : public Pass { // check density percentages Const offset(State::S0, GetSize(sig)); - if (absolute_density < non_offset_percentage && range_density >= offset_percentage) + if (absolute_density < min_non_offset_percentage && range_density >= min_offset_percentage) { offset = Const(min_choice, GetSize(sig)); log(" offset: %s\n", log_signal(offset)); @@ -342,7 +382,7 @@ struct Pmux2ShiftxPass : public Pass { new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; perm_choices.swap(new_perm_choices); } else - if (absolute_density < non_offset_percentage) { + if (absolute_density < min_non_offset_percentage) { log(" insufficient density.\n"); seldb.erase(sig); continue; diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys index f5e83171c..f84ae3869 100644 --- a/tests/various/pmux2shiftx.ys +++ b/tests/various/pmux2shiftx.ys @@ -2,7 +2,7 @@ read_verilog pmux2shiftx.v prep design -save gold -pmux2shiftx -density 70 50 +pmux2shiftx -min_density 70 50 opt From e06d158e8a3ae3626fbf82b3a8c6764f05111513 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 01:18:07 +0200 Subject: [PATCH 115/149] Fix some typos Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index e6a0bd06b..dbcdff3d8 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -39,7 +39,7 @@ struct Pmux2ShiftxPass : public Pass { log("\n"); log(" -min_choices \n"); log(" specified the minimum number of choices for a control signal\n"); - log(" defaukt: 3\n"); + log(" default: 3\n"); log("\n"); log(" -allow_onehot\n"); log(" by default, pmuxes with one-hot encoded control signals are not\n"); @@ -253,7 +253,7 @@ struct Pmux2ShiftxPass : public Pass { int best_maxval = 0; int best_delta = 0; - // find best src colum for this dst column + // find best src column for this dst column for (int src_col = 0; src_col < GetSize(sig); src_col++) { if (used_src_columns[src_col]) From b3a3e08e389c8d10fbd8e0dc8b48e1e559dedf5d Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 02:03:44 +0200 Subject: [PATCH 116/149] Improve "pmux2shiftx" Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 18 ++++++++---------- tests/various/pmux2shiftx.ys | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index dbcdff3d8..4cd061c68 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -33,9 +33,9 @@ struct Pmux2ShiftxPass : public Pass { log("\n"); log("This pass transforms $pmux cells to $shiftx cells.\n"); log("\n"); - log(" -min_density \n"); - log(" specifies the minimum density for non_offset- and for offset-mode\n"); - log(" default values are 30 (non-offset) and 50 (offset)\n"); + log(" -min_density \n"); + log(" specifies the minimum density for the shifter\n"); + log(" default: 50\n"); log("\n"); log(" -min_choices \n"); log(" specified the minimum number of choices for a control signal\n"); @@ -48,8 +48,7 @@ struct Pmux2ShiftxPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE { - int min_non_offset_percentage = 30; - int min_offset_percentage = 50; + int min_density = 50; int min_choices = 3; bool allow_onehot = false; @@ -57,9 +56,8 @@ struct Pmux2ShiftxPass : public Pass { size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - if (args[argidx] == "-min_density" && argidx+2 < args.size()) { - min_non_offset_percentage = atoi(args[++argidx].c_str()); - min_offset_percentage = atoi(args[++argidx].c_str()); + if (args[argidx] == "-min_density" && argidx+1 < args.size()) { + min_density = atoi(args[++argidx].c_str()); continue; } if (args[argidx] == "-min_choices" && argidx+1 < args.size()) { @@ -369,7 +367,7 @@ struct Pmux2ShiftxPass : public Pass { // check density percentages Const offset(State::S0, GetSize(sig)); - if (absolute_density < min_non_offset_percentage && range_density >= min_offset_percentage) + if (absolute_density < min_density && range_density >= min_density) { offset = Const(min_choice, GetSize(sig)); log(" offset: %s\n", log_signal(offset)); @@ -382,7 +380,7 @@ struct Pmux2ShiftxPass : public Pass { new_perm_choices[const_sub(it.first, offset, false, false, GetSize(sig))] = it.second; perm_choices.swap(new_perm_choices); } else - if (absolute_density < min_non_offset_percentage) { + if (absolute_density < min_density) { log(" insufficient density.\n"); seldb.erase(sig); continue; diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys index f84ae3869..6bb9626eb 100644 --- a/tests/various/pmux2shiftx.ys +++ b/tests/various/pmux2shiftx.ys @@ -2,7 +2,7 @@ read_verilog pmux2shiftx.v prep design -save gold -pmux2shiftx -min_density 70 50 +pmux2shiftx -min_density 70 opt From 5b915f01539c993466e83593ee8ae69b45360b81 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 11:04:46 +0200 Subject: [PATCH 117/149] Add "wbflip" command Signed-off-by: Clifford Wolf --- kernel/rtlil.cc | 7 +++++-- kernel/rtlil.h | 2 +- passes/cmds/setattr.cc | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 2f8715755..f6f08bb9e 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -207,9 +207,12 @@ bool RTLIL::Const::is_fully_undef() const return true; } -void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id) +void RTLIL::AttrObject::set_bool_attribute(RTLIL::IdString id, bool value) { - attributes[id] = RTLIL::Const(1); + if (value) + attributes[id] = RTLIL::Const(1); + else if (attributes.count(id)) + attributes.erase(id); } bool RTLIL::AttrObject::get_bool_attribute(RTLIL::IdString id) const diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 9e396d6f6..330a81c3b 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -566,7 +566,7 @@ struct RTLIL::AttrObject { dict attributes; - void set_bool_attribute(RTLIL::IdString id); + void set_bool_attribute(RTLIL::IdString id, bool value=true); bool get_bool_attribute(RTLIL::IdString id) const; bool get_blackbox_attribute(bool ignore_wb=false) const { diff --git a/passes/cmds/setattr.cc b/passes/cmds/setattr.cc index d38a6b3da..b9fcc3e7a 100644 --- a/passes/cmds/setattr.cc +++ b/passes/cmds/setattr.cc @@ -128,6 +128,45 @@ struct SetattrPass : public Pass { } } SetattrPass; +struct WbflipPass : public Pass { + WbflipPass() : Pass("wbflip", "flip the whitebox attribute") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" wbflip [selection]\n"); + log("\n"); + log("Flip the whitebox attribute on selected cells. I.e. if it's set, unset it, and\n"); + log("vice-versa. Blackbox cells are not effected by this command.\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + std::string arg = args[argidx]; + // if (arg == "-mod") { + // flag_mod = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (Module *module : design->modules()) + { + if (!design->selected(module)) + continue; + + if (module->get_bool_attribute("\\blackbox")) + continue; + + module->set_bool_attribute("\\whitebox", !module->get_bool_attribute("\\whitebox")); + } + } +} WbflipPass; + struct SetparamPass : public Pass { SetparamPass() : Pass("setparam", "set/unset parameters on objects") { } void help() YS_OVERRIDE From b7445ef3871b38360440d5c83dbac45c96b67277 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 11:10:05 +0200 Subject: [PATCH 118/149] Check blackbox attribute in techmap/simplemap Signed-off-by: Clifford Wolf --- passes/techmap/simplemap.cc | 2 +- passes/techmap/techmap.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/passes/techmap/simplemap.cc b/passes/techmap/simplemap.cc index 660b60601..f3da80c66 100644 --- a/passes/techmap/simplemap.cc +++ b/passes/techmap/simplemap.cc @@ -599,7 +599,7 @@ struct SimplemapPass : public Pass { simplemap_get_mappers(mappers); for (auto mod : design->modules()) { - if (!design->selected(mod)) + if (!design->selected(mod) || mod->get_blackbox_attribute()) continue; std::vector cells = mod->cells(); for (auto cell : cells) { diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 82c815e2e..416bf4f1c 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -385,7 +385,7 @@ struct TechmapWorker { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; - if (!design->selected(module)) + if (!design->selected(module) || module->get_blackbox_attribute()) return false; bool log_continue = false; From f3ad8d680a3195ab9525b0a8b3f8dbff9d5e6e24 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 11:23:24 +0200 Subject: [PATCH 119/149] Add "techmap -wb", use in formal flows Signed-off-by: Clifford Wolf --- passes/equiv/equiv_opt.cc | 2 +- passes/sat/miter.cc | 8 ++++---- passes/techmap/techmap.cc | 9 ++++++++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index 86550a69b..e5dda9c24 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -134,7 +134,7 @@ struct EquivOptPass:public ScriptPass opts = " -map ..."; else opts = techmap_opts; - run("techmap -D EQUIV -autoproc" + opts); + run("techmap -wb -D EQUIV -autoproc" + opts); } if (check_label("prove")) { diff --git a/passes/sat/miter.cc b/passes/sat/miter.cc index d37f1b126..1a886af70 100644 --- a/passes/sat/miter.cc +++ b/passes/sat/miter.cc @@ -254,7 +254,7 @@ void create_miter_equiv(struct Pass *that, std::vector args, RTLIL: if (flag_flatten) { log_push(); - Pass::call_on_module(design, miter_module, "flatten; opt_expr -keepdc -undriven;;"); + Pass::call_on_module(design, miter_module, "flatten -wb; opt_expr -keepdc -undriven;;"); log_pop(); } } @@ -308,7 +308,7 @@ void create_miter_assert(struct Pass *that, std::vector args, RTLIL if (flag_flatten) { log_push(); - Pass::call_on_module(design, module, "flatten;;"); + Pass::call_on_module(design, module, "flatten -wb;;"); log_pop(); } @@ -385,7 +385,7 @@ struct MiterPass : public Pass { log(" also create an 'assert' cell that checks if trigger is always low.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); log("\n"); log(" miter -assert [options] module [miter_name]\n"); @@ -399,7 +399,7 @@ struct MiterPass : public Pass { log(" keep module output ports.\n"); log("\n"); log(" -flatten\n"); - log(" call 'flatten; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); + log(" call 'flatten -wb; opt_expr -keepdc -undriven;;' on the miter circuit.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 416bf4f1c..ee319b6e6 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -385,7 +385,7 @@ struct TechmapWorker { std::string mapmsg_prefix = in_recursion ? "Recursively mapping" : "Mapping"; - if (!design->selected(module) || module->get_blackbox_attribute()) + if (!design->selected(module) || module->get_blackbox_attribute(ignore_wb)) return false; bool log_continue = false; @@ -927,6 +927,9 @@ struct TechmapPass : public Pass { log(" -autoproc\n"); log(" Automatically call \"proc\" on implementations that contain processes.\n"); log("\n"); + log(" -wb\n"); + log(" Ignore the 'whitebox' attribute on cell implementations.\n"); + log("\n"); log(" -assert\n"); log(" this option will cause techmap to exit with an error if it can't map\n"); log(" a selected cell. only cell types that end on an underscore are accepted\n"); @@ -1070,6 +1073,10 @@ struct TechmapPass : public Pass { worker.autoproc_mode = true; continue; } + if (args[argidx] == "-wb") { + worker.ignore_wb = true; + continue; + } break; } extra_args(args, argidx, design); From 97e9caa4fa1f874b693a9d948f48418f22babb6c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 17:52:16 +0200 Subject: [PATCH 120/149] Add "onehot" pass, improve "pmux2shiftx" onehot handling Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 417 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 404 insertions(+), 13 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 4cd061c68..5fd49a571 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -23,6 +23,172 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +struct OnehotDatabase +{ + Module *module; + const SigMap &sigmap; + bool verbose = false; + + pool init_ones; + dict> sig_sources_db; + dict sig_onehot_cache; + pool recursion_guard; + + OnehotDatabase(Module *module, const SigMap &sigmap) : module(module), sigmap(sigmap) + { + } + + void initialize() + { + for (auto wire : module->wires()) + { + auto it = wire->attributes.find("\\init"); + if (it == wire->attributes.end()) + continue; + + auto &val = it->second; + int width = std::max(GetSize(wire), GetSize(val)); + + for (int i = 0; i < width; i++) + if (val[i] == State::S1) + init_ones.insert(sigmap(SigBit(wire, i))); + } + + for (auto cell : module->cells()) + { + vector inputs; + SigSpec output; + + if (cell->type.in("$adff", "$dff", "$dffe", "$dlatch", "$ff")) + { + output = cell->getPort("\\Q"); + if (cell->type == "$adff") + inputs.push_back(cell->getParam("\\ARST_VALUE")); + inputs.push_back(cell->getPort("\\D")); + } + + if (cell->type.in("$mux", "$pmux")) + { + output = cell->getPort("\\Y"); + inputs.push_back(cell->getPort("\\A")); + SigSpec B = cell->getPort("\\B"); + for (int i = 0; i < GetSize(B); i += GetSize(output)) + inputs.push_back(B.extract(i, GetSize(output))); + } + + if (!output.empty()) + { + output = sigmap(output); + auto &srcs = sig_sources_db[output]; + for (auto src : inputs) { + while (!src.empty() && src[GetSize(src)-1] == State::S0) + src.remove(GetSize(src)-1); + srcs.insert(sigmap(src)); + } + } + } + } + + void query_worker(const SigSpec &sig, bool &retval, bool &cache, int indent) + { + if (verbose) + log("%*s %s\n", indent, "", log_signal(sig)); + log_assert(retval); + + if (recursion_guard.count(sig)) { + if (verbose) + log("%*s - recursion\n", indent, ""); + cache = false; + return; + } + + auto it = sig_onehot_cache.find(sig); + if (it != sig_onehot_cache.end()) { + if (verbose) + log("%*s - cached (%s)\n", indent, "", it->second ? "true" : "false"); + if (!it->second) + retval = false; + return; + } + + bool found_init_ones = false; + for (auto bit : sig) { + if (init_ones.count(bit)) { + if (found_init_ones) { + if (verbose) + log("%*s - non-onehot init value\n", indent, ""); + retval = false; + break; + } + found_init_ones = true; + } + } + + if (retval) + { + if (sig.is_fully_const()) + { + bool found_ones = false; + for (auto bit : sig) { + if (bit == State::S1) { + if (found_ones) { + if (verbose) + log("%*s - non-onehot constant\n", indent, ""); + retval = false; + break; + } + found_ones = true; + } + } + } + else + { + auto srcs = sig_sources_db.find(sig); + if (srcs == sig_sources_db.end()) { + if (verbose) + log("%*s - no sources for non-const signal\n", indent, ""); + retval = false; + } else { + for (auto &src : srcs->second) { + bool child_cache = true; + recursion_guard.insert(sig); + query_worker(src, retval, child_cache, indent+4); + recursion_guard.erase(sig); + if (!child_cache) + cache = false; + if (!retval) + break; + } + } + } + } + + // it is always safe to cache a negative result + if (cache || !retval) + sig_onehot_cache[sig] = retval; + } + + bool query(const SigSpec &sig) + { + bool retval = true; + bool cache = true; + + if (verbose) + log("** ONEHOT QUERY START (%s)\n", log_signal(sig)); + + query_worker(sig, retval, cache, 3); + + if (verbose) + log("** ONEHOT QUERY RESULT = %s\n", retval ? "true" : "false"); + + // it is always safe to cache the root result of a query + if (!cache) + sig_onehot_cache[sig] = retval; + + return retval; + } +}; + struct Pmux2ShiftxPass : public Pass { Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } void help() YS_OVERRIDE @@ -33,6 +199,9 @@ struct Pmux2ShiftxPass : public Pass { log("\n"); log("This pass transforms $pmux cells to $shiftx cells.\n"); log("\n"); + log(" -v, -vv\n"); + log(" verbose output\n"); + log("\n"); log(" -min_density \n"); log(" specifies the minimum density for the shifter\n"); log(" default: 50\n"); @@ -41,9 +210,9 @@ struct Pmux2ShiftxPass : public Pass { log(" specified the minimum number of choices for a control signal\n"); log(" default: 3\n"); log("\n"); - log(" -allow_onehot\n"); - log(" by default, pmuxes with one-hot encoded control signals are not\n"); - log(" converted. this option disables that check.\n"); + log(" -onehot ignore|pmux|shiftx\n"); + log(" select strategy for one-hot encoded control signals\n"); + log(" default: pmux\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE @@ -51,6 +220,9 @@ struct Pmux2ShiftxPass : public Pass { int min_density = 50; int min_choices = 3; bool allow_onehot = false; + bool optimize_onehot = true; + bool verbose = false; + bool verbose_onehot = false; log_header(design, "Executing PMUX2SHIFTX pass.\n"); @@ -64,8 +236,31 @@ struct Pmux2ShiftxPass : public Pass { min_choices = atoi(args[++argidx].c_str()); continue; } - if (args[argidx] == "-allow_onehot") { + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "ignore") { + argidx++; + allow_onehot = false; + optimize_onehot = false; + continue; + } + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "pmux") { + argidx++; + allow_onehot = false; + optimize_onehot = true; + continue; + } + if (args[argidx] == "-onehot" && argidx+1 < args.size() && args[argidx+1] == "shiftx") { + argidx++; allow_onehot = true; + optimize_onehot = false; + continue; + } + if (args[argidx] == "-v") { + verbose = true; + continue; + } + if (args[argidx] == "-vv") { + verbose = true; + verbose_onehot = true; continue; } break; @@ -75,10 +270,15 @@ struct Pmux2ShiftxPass : public Pass { for (auto module : design->selected_modules()) { SigMap sigmap(module); + OnehotDatabase onehot_db(module, sigmap); + onehot_db.verbose = verbose_onehot; + + if (optimize_onehot) + onehot_db.initialize(); dict> eqdb; - for (auto cell : module->selected_cells()) + for (auto cell : module->cells()) { if (cell->type == "$eq") { @@ -181,6 +381,12 @@ struct Pmux2ShiftxPass : public Pass { bool printed_pmux_header = false; + if (verbose) { + printed_pmux_header = true; + log("Inspecting $pmux cell %s/%s.\n", log_id(module), log_id(cell)); + log(" data width: %d (next power-of-2 = %d, log2 = %d)\n", width, extwidth, width_bits); + } + SigSpec updated_S = cell->getPort("\\S"); SigSpec updated_B = cell->getPort("\\B"); @@ -196,7 +402,7 @@ struct Pmux2ShiftxPass : public Pass { } // find the relevant choices - bool is_onehot = true; + bool is_onehot = GetSize(sig) > 2; dict choices; for (int i : seldb.at(sig)) { Const val = eqdb.at(S[i]).second; @@ -211,14 +417,17 @@ struct Pmux2ShiftxPass : public Pass { // TBD: also find choices that are using signals that are subsets of the bits in "sig" - if (is_onehot && !allow_onehot) { - seldb.erase(sig); - continue; - } + if (!verbose) + { + if (is_onehot && !allow_onehot && !optimize_onehot) { + seldb.erase(sig); + continue; + } - if (GetSize(choices) < min_choices) { - seldb.erase(sig); - continue; + if (GetSize(choices) < min_choices) { + seldb.erase(sig); + continue; + } } if (!printed_pmux_header) { @@ -229,6 +438,65 @@ struct Pmux2ShiftxPass : public Pass { log(" checking ctrl signal %s\n", log_signal(sig)); + auto print_choices = [&]() { + log(" table of choices:\n"); + for (auto &it : choices) + log(" %3d: %s: %s\n", it.second, log_signal(it.first), + log_signal(B.extract(it.second*width, width))); + }; + + if (verbose) + { + if (is_onehot && !allow_onehot && !optimize_onehot) { + print_choices(); + log(" ignoring one-hot encoding.\n"); + seldb.erase(sig); + continue; + } + + if (GetSize(choices) < min_choices) { + print_choices(); + log(" insufficient choices.\n"); + seldb.erase(sig); + continue; + } + } + + if (is_onehot && optimize_onehot) + { + print_choices(); + if (!onehot_db.query(sig)) + { + log(" failed to detect onehot driver. do not optimize.\n"); + } + else + { + log(" optimizing one-hot encoding.\n"); + for (auto &it : choices) + { + const Const &val = it.first; + int index = -1; + + for (int i = 0; i < GetSize(val); i++) + if (val[i] == State::S1) { + log_assert(index < 0); + index = i; + } + + if (index < 0) { + log(" %3d: zero encoding.\n", it.second); + continue; + } + + SigBit new_ctrl = sig[index]; + log(" %3d: new crtl signal is %s.\n", it.second, log_signal(new_ctrl)); + updated_S[it.second] = new_ctrl; + } + } + seldb.erase(sig); + continue; + } + // find the best permutation vector perm_new_from_old(GetSize(sig)); Const perm_xormask(State::S0, GetSize(sig)); @@ -434,4 +702,127 @@ struct Pmux2ShiftxPass : public Pass { } } Pmux2ShiftxPass; +struct OnehotPass : public Pass { + OnehotPass() : Pass("onehot", "optimize $eq cells for onehot signals") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" onehot [options] [selection]\n"); + log("\n"); + log("This pass optimizes $eq cells that compare one-hot signals against constants\n"); + log("\n"); + log(" -v, -vv\n"); + log(" verbose output\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + bool verbose = false; + bool verbose_onehot = false; + + log_header(design, "Executing ONEHOT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-v") { + verbose = true; + continue; + } + if (args[argidx] == "-vv") { + verbose = true; + verbose_onehot = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + OnehotDatabase onehot_db(module, sigmap); + onehot_db.verbose = verbose_onehot; + onehot_db.initialize(); + + for (auto cell : module->selected_cells()) + { + if (cell->type != "$eq") + continue; + + SigSpec A = sigmap(cell->getPort("\\A")); + SigSpec B = sigmap(cell->getPort("\\B")); + + int a_width = cell->getParam("\\A_WIDTH").as_int(); + int b_width = cell->getParam("\\B_WIDTH").as_int(); + + if (a_width < b_width) { + bool a_signed = cell->getParam("\\A_SIGNED").as_int(); + A.extend_u0(b_width, a_signed); + } + + if (b_width < a_width) { + bool b_signed = cell->getParam("\\B_SIGNED").as_int(); + B.extend_u0(a_width, b_signed); + } + + if (A.is_fully_const()) + std::swap(A, B); + + if (!B.is_fully_const()) + continue; + + if (verbose) + log("Checking $eq(%s, %s) cell %s/%s.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); + + if (!onehot_db.query(A)) { + if (verbose) + log(" onehot driver test on %s failed.\n", log_signal(A)); + continue; + } + + int index = -1; + bool not_onehot = false; + + for (int i = 0; i < GetSize(B); i++) { + if (B[i] != State::S1) + continue; + if (index >= 0) + not_onehot = true; + index = i; + } + + if (index < 0) { + if (verbose) + log(" not optimizing the zero pattern.\n"); + continue; + } + + SigSpec Y = cell->getPort("\\Y"); + + if (not_onehot) + { + if (verbose) + log(" replacing with constant 0 driver.\n"); + else + log("Replacing one-hot $eq(%s, %s) cell %s/%s with constant 0 driver.\n", log_signal(A), log_signal(B), log_id(module), log_id(cell)); + module->connect(Y, SigSpec(1, GetSize(Y))); + } + else + { + SigSpec sig = A[index]; + if (verbose) + log(" replacing with signal %s.\n", log_signal(sig)); + else + log("Replacing one-hot $eq(%s, %s) cell %s/%s with signal %s.\n",log_signal(A), log_signal(B), log_id(module), log_id(cell), log_signal(sig)); + sig.extend_u0(GetSize(Y)); + module->connect(Y, sig); + } + + module->remove(cell); + } + } + } +} OnehotPass; + PRIVATE_NAMESPACE_END From fc23af170768926e645b6c94c54b4c2e6e8d0808 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 18:13:37 +0200 Subject: [PATCH 121/149] Auto-initialize OnehotDatabase on-demand in pmux2shiftx.cc Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 5fd49a571..5f897b131 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -28,6 +28,7 @@ struct OnehotDatabase Module *module; const SigMap &sigmap; bool verbose = false; + bool initialized = false; pool init_ones; dict> sig_sources_db; @@ -40,6 +41,9 @@ struct OnehotDatabase void initialize() { + log_assert(!initialized); + initialized = true; + for (auto wire : module->wires()) { auto it = wire->attributes.find("\\init"); @@ -176,6 +180,9 @@ struct OnehotDatabase if (verbose) log("** ONEHOT QUERY START (%s)\n", log_signal(sig)); + if (!initialized) + initialize(); + query_worker(sig, retval, cache, 3); if (verbose) @@ -273,9 +280,6 @@ struct Pmux2ShiftxPass : public Pass { OnehotDatabase onehot_db(module, sigmap); onehot_db.verbose = verbose_onehot; - if (optimize_onehot) - onehot_db.initialize(); - dict> eqdb; for (auto cell : module->cells()) @@ -743,7 +747,6 @@ struct OnehotPass : public Pass { SigMap sigmap(module); OnehotDatabase onehot_db(module, sigmap); onehot_db.verbose = verbose_onehot; - onehot_db.initialize(); for (auto cell : module->selected_cells()) { From fb7f02be5561ccfd5bee5f3235fbbae5ef618f36 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sat, 20 Apr 2019 22:24:50 +0200 Subject: [PATCH 122/149] New behavior for front-end handling of whiteboxes Signed-off-by: Clifford Wolf --- README.md | 3 + frontends/ast/ast.cc | 84 ++++++++++++++++++++++----- frontends/ast/ast.h | 4 +- frontends/verilog/verilog_frontend.cc | 29 ++++++--- frontends/verilog/verilog_frontend.h | 7 ++- frontends/verilog/verilog_parser.y | 10 ++-- 6 files changed, 103 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 5c94c34e5..7f90cb3c2 100644 --- a/README.md +++ b/README.md @@ -316,6 +316,9 @@ Verilog Attributes and non-standard features ``blackbox``, but is for whitebox modules, i.e. library modules that contain a behavioral model of the cell type. +- The ``lib_whitebox`` attribute overwrites ``whitebox`` when ``read_verilog`` + is run in `-lib` mode. Otherwise it's automatically removed. + - The ``dynports`` attribute is used by the Verilog front-end to mark modules that have ports with a width that depends on a parameter. diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 720b3f3d1..e4f18a2ac 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -46,7 +46,7 @@ namespace AST { // instantiate global variables (private API) namespace AST_INTERNAL { bool flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit; - bool flag_nomem2reg, flag_mem2reg, flag_lib, flag_wb, flag_noopt, flag_icells, flag_autowire; + bool flag_nomem2reg, flag_mem2reg, flag_noblackbox, flag_lib, flag_nowb, flag_noopt, flag_icells, flag_autowire; AstNode *current_ast, *current_ast_mod; std::map current_scope; const dict *genRTLIL_subst_ptr = NULL; @@ -956,18 +956,67 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast log("--- END OF AST DUMP ---\n"); } - if (flag_wb) { - if (!ast->attributes.count("\\whitebox")) - goto blackbox_module; + if (flag_nowb && ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + + if (ast->attributes.count("\\lib_whitebox")) { + if (!flag_lib || flag_nowb) { + delete ast->attributes.at("\\lib_whitebox"); + ast->attributes.erase("\\lib_whitebox"); + } else { + if (ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + AstNode *n = ast->attributes.at("\\lib_whitebox"); + ast->attributes["\\whitebox"] = n; + ast->attributes.erase("\\lib_whitebox"); + } + } + + bool blackbox_module = flag_lib; + + if (!blackbox_module && ast->attributes.count("\\blackbox")) { + AstNode *n = ast->attributes.at("\\blackbox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Blackbox attribute with non-constant value!\n"); + blackbox_module = n->asBool(); + } + + if (!blackbox_module && !flag_noblackbox) + { + for (auto child : ast->children) { + if (child->type == AST_WIRE && (child->is_input || child->is_output)) + continue; + if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) + continue; + goto noblackbox; + } + blackbox_module = 1; + } + + noblackbox: + if (blackbox_module && ast->attributes.count("\\whitebox")) { AstNode *n = ast->attributes.at("\\whitebox"); if (n->type != AST_CONSTANT) log_file_error(ast->filename, ast->linenum, "Whitebox attribute with non-constant value!\n"); - if (!n->asBool()) - goto blackbox_module; + blackbox_module = !n->asBool(); } - if (flag_lib) { - blackbox_module: + if (blackbox_module) + { + if (ast->attributes.count("\\whitebox")) { + delete ast->attributes.at("\\whitebox"); + ast->attributes.erase("\\whitebox"); + } + + if (ast->attributes.count("\\lib_whitebox")) { + delete ast->attributes.at("\\lib_whitebox"); + ast->attributes.erase("\\lib_whitebox"); + } + std::vector new_children; for (auto child : ast->children) { if (child->type == AST_WIRE && (child->is_input || child->is_output)) { @@ -980,12 +1029,12 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast delete child; } } + ast->children.swap(new_children); - if (ast->attributes.count("\\whitebox")) { - delete ast->attributes.at("\\whitebox"); - ast->attributes.erase("\\whitebox"); + + if (ast->attributes.count("\\blackbox") == 0) { + ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); } - ast->attributes["\\blackbox"] = AstNode::mkconst_int(1, false); } ignoreThisSignalsInInitial = RTLIL::SigSpec(); @@ -1024,8 +1073,9 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast current_module->nomeminit = flag_nomeminit; current_module->nomem2reg = flag_nomem2reg; current_module->mem2reg = flag_mem2reg; + current_module->noblackbox = flag_noblackbox; current_module->lib = flag_lib; - current_module->wb = flag_wb; + current_module->nowb = flag_nowb; current_module->noopt = flag_noopt; current_module->icells = flag_icells; current_module->autowire = flag_autowire; @@ -1042,7 +1092,7 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast // create AstModule instances for all modules in the AST tree and add them to 'design' void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump_ast2, bool no_dump_ptr, bool dump_vlog1, bool dump_vlog2, bool dump_rtlil, - bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool lib, bool wb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) + bool nolatches, bool nomeminit, bool nomem2reg, bool mem2reg, bool noblackbox, bool lib, bool nowb, bool noopt, bool icells, bool nooverwrite, bool overwrite, bool defer, bool autowire) { current_ast = ast; flag_dump_ast1 = dump_ast1; @@ -1055,8 +1105,9 @@ void AST::process(RTLIL::Design *design, AstNode *ast, bool dump_ast1, bool dump flag_nomeminit = nomeminit; flag_nomem2reg = nomem2reg; flag_mem2reg = mem2reg; + flag_noblackbox = noblackbox; flag_lib = lib; - flag_wb = wb; + flag_nowb = nowb; flag_noopt = noopt; flag_icells = icells; flag_autowire = autowire; @@ -1390,8 +1441,9 @@ std::string AstModule::derive_common(RTLIL::Design *design, dict parameters, bool mayfail) YS_OVERRIDE; RTLIL::IdString derive(RTLIL::Design *design, dict parameters, dict interfaces, dict modports, bool mayfail) YS_OVERRIDE; diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 4e2c5abb5..ed6ce2ecb 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -145,12 +145,18 @@ struct VerilogFrontend : public Frontend { log(" -nodpi\n"); log(" disable DPI-C support\n"); log("\n"); + log(" -noblackbox\n"); + log(" do not automatically add a (* blackbox *) attribute to an\n"); + log(" empty module.\n"); + log("\n"); log(" -lib\n"); log(" only create empty blackbox modules. This implies -DBLACKBOX.\n"); + log(" modules with the (* whitebox *) attribute will be preserved.\n"); + log(" (* lib_whitebox *) will be treated like (* whitebox *).\n"); log("\n"); - log(" -wb\n"); - log(" like -lib, except do not touch modules with the whitebox\n"); - log(" attribute set. This also implies -DBLACKBOX.\n"); + log(" -nowb\n"); + log(" delete (* whitebox *) and (* lib_whitebox *) attributes from\n"); + log(" all modules.\n"); log("\n"); log(" -noopt\n"); log(" don't perform basic optimizations (such as const folding) in the\n"); @@ -231,8 +237,9 @@ struct VerilogFrontend : public Frontend { formal_mode = false; norestrict_mode = false; assume_asserts_mode = false; + noblackbox_mode = false; lib_mode = false; - wb_mode = false; + nowb_mode = false; default_nettype_wire = true; log_header(design, "Executing Verilog-2005 frontend.\n"); @@ -334,14 +341,17 @@ struct VerilogFrontend : public Frontend { flag_nodpi = true; continue; } - if (arg == "-lib" && !wb_mode) { + if (arg == "-noblackbox") { + noblackbox_mode = true; + continue; + } + if (arg == "-lib") { lib_mode = true; defines_map["BLACKBOX"] = string(); continue; } - if (arg == "-wb" && !lib_mode) { - wb_mode = true; - defines_map["BLACKBOX"] = string(); + if (arg == "-nowb") { + nowb_mode = true; continue; } if (arg == "-noopt") { @@ -439,7 +449,8 @@ struct VerilogFrontend : public Frontend { if (flag_nodpi) error_on_dpi_function(current_ast); - AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, flag_nomeminit, flag_nomem2reg, flag_mem2reg, lib_mode, wb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); + AST::process(design, current_ast, flag_dump_ast1, flag_dump_ast2, flag_no_dump_ptr, flag_dump_vlog1, flag_dump_vlog2, flag_dump_rtlil, flag_nolatches, + flag_nomeminit, flag_nomem2reg, flag_mem2reg, noblackbox_mode, lib_mode, nowb_mode, flag_noopt, flag_icells, flag_nooverwrite, flag_overwrite, flag_defer, default_nettype_wire); if (!flag_nopp) delete lexin; diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index b5cf70c57..ca40946cb 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -69,11 +69,14 @@ namespace VERILOG_FRONTEND // running in -assert-assumes mode extern bool assert_assumes_mode; + // running in -noblackbox mode + extern bool noblackbox_mode; + // running in -lib mode extern bool lib_mode; - // running in -wb mode - extern bool wb_mode; + // running in -nowb mode + extern bool nowb_mode; // lexer input stream extern std::istream *lexin; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 122eb1230..40968d17a 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -59,7 +59,7 @@ namespace VERILOG_FRONTEND { std::vector case_type_stack; bool do_not_require_port_stubs; bool default_nettype_wire; - bool sv_mode, formal_mode, lib_mode, wb_mode; + bool sv_mode, formal_mode, noblackbox_mode, lib_mode, nowb_mode; bool noassert_mode, noassume_mode, norestrict_mode; bool assume_asserts_mode, assert_assumes_mode; bool current_wire_rand, current_wire_const; @@ -1906,7 +1906,7 @@ basic_expr: if ($4->substr(0, 1) != "'") frontend_verilog_yyerror("Cast operation must be applied on sized constants e.g. () , while %s is not a sized constant.", $4->c_str()); AstNode *bits = $2; - AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); + AstNode *val = const2ast(*$4, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $4->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1917,7 +1917,7 @@ basic_expr: frontend_verilog_yyerror("Cast operation must be applied on sized constants, e.g. \'d0, while %s is not a sized constant.", $2->c_str()); AstNode *bits = new AstNode(AST_IDENTIFIER); bits->str = *$1; - AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); + AstNode *val = const2ast(*$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if (val == NULL) log_error("Value conversion failed: `%s'\n", $2->c_str()); $$ = new AstNode(AST_TO_BITS, bits, val); @@ -1925,14 +1925,14 @@ basic_expr: delete $2; } | TOK_CONSTVAL TOK_CONSTVAL { - $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); + $$ = const2ast(*$1 + *$2, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL || (*$2)[0] != '\'') log_error("Value conversion failed: `%s%s'\n", $1->c_str(), $2->c_str()); delete $1; delete $2; } | TOK_CONSTVAL { - $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode && !wb_mode); + $$ = const2ast(*$1, case_type_stack.size() == 0 ? 0 : case_type_stack.back(), !lib_mode); if ($$ == NULL) log_error("Value conversion failed: `%s'\n", $1->c_str()); delete $1; From 5b7fea5245671882dabe2ec319353fa4f2fb8f91 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 21 Apr 2019 11:40:09 +0200 Subject: [PATCH 123/149] Add "noblackbox" attribute Signed-off-by: Clifford Wolf --- README.md | 7 ++++++- frontends/ast/ast.cc | 44 +++++++++++++++++++++++++++----------------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 7f90cb3c2..fd45b5470 100644 --- a/README.md +++ b/README.md @@ -310,7 +310,12 @@ Verilog Attributes and non-standard features that have the same ports as the real thing but do not contain information on the internal configuration. This modules are only used by the synthesis passes to identify input and output ports of cells. The Verilog backend - also does not output blackbox modules on default. + also does not output blackbox modules on default. ``read_verilog``, unless + called with ``-noblackbox`` will automatically set the blackbox attribute + on any empty module it reads. + +- The ``noblackbox`` attribute set on an empty module prevents ``read_verilog`` + from automatically setting the blackbox attribute on the module. - The ``whitebox`` attribute on modules triggers the same behavior as ``blackbox``, but is for whitebox modules, i.e. library modules that diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index e4f18a2ac..9f88b08c1 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -942,6 +942,20 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast if (!defer) { + bool blackbox_module = flag_lib; + + if (!blackbox_module && !flag_noblackbox) { + blackbox_module = true; + for (auto child : ast->children) { + if (child->type == AST_WIRE && (child->is_input || child->is_output)) + continue; + if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) + continue; + blackbox_module = false; + break; + } + } + while (ast->simplify(!flag_noopt, false, false, 0, -1, false, false)) { } if (flag_dump_ast2) { @@ -976,35 +990,31 @@ static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast } } - bool blackbox_module = flag_lib; - if (!blackbox_module && ast->attributes.count("\\blackbox")) { AstNode *n = ast->attributes.at("\\blackbox"); if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Blackbox attribute with non-constant value!\n"); + log_file_error(ast->filename, ast->linenum, "Got blackbox attribute with non-constant value!\n"); blackbox_module = n->asBool(); } - if (!blackbox_module && !flag_noblackbox) - { - for (auto child : ast->children) { - if (child->type == AST_WIRE && (child->is_input || child->is_output)) - continue; - if (child->type == AST_PARAMETER || child->type == AST_LOCALPARAM) - continue; - goto noblackbox; - } - blackbox_module = 1; - } - - noblackbox: if (blackbox_module && ast->attributes.count("\\whitebox")) { AstNode *n = ast->attributes.at("\\whitebox"); if (n->type != AST_CONSTANT) - log_file_error(ast->filename, ast->linenum, "Whitebox attribute with non-constant value!\n"); + log_file_error(ast->filename, ast->linenum, "Got whitebox attribute with non-constant value!\n"); blackbox_module = !n->asBool(); } + if (ast->attributes.count("\\noblackbox")) { + if (blackbox_module) { + AstNode *n = ast->attributes.at("\\noblackbox"); + if (n->type != AST_CONSTANT) + log_file_error(ast->filename, ast->linenum, "Got noblackbox attribute with non-constant value!\n"); + blackbox_module = !n->asBool(); + } + delete ast->attributes.at("\\noblackbox"); + ast->attributes.erase("\\noblackbox"); + } + if (blackbox_module) { if (ast->attributes.count("\\whitebox")) { From d38f0c1a96c036df4ef67ad2f945dd229e1c3b8e Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Sun, 21 Apr 2019 11:40:20 +0200 Subject: [PATCH 124/149] Fix tests Signed-off-by: Clifford Wolf --- tests/tools/autotest.sh | 4 ++-- tests/various/hierarchy.sh | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index f3dac504e..bb9c3bfb5 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -7,7 +7,7 @@ use_modelsim=false verbose=false keeprunning=false makejmode=false -frontend="verilog" +frontend="verilog -noblackbox" backend_opts="-noattr -noexpr -siminit" autotb_opts="" include_opts="" @@ -137,7 +137,7 @@ do egrep -v '^\s*`timescale' ../$fn > ${bn}_ref.${ext} else "$toolsdir"/../../yosys -f "$frontend $include_opts" -b "verilog" -o ${bn}_ref.v ../${fn} - frontend="verilog" + frontend="verilog -noblackbox" fi if [ ! -f ../${bn}_tb.v ]; then diff --git a/tests/various/hierarchy.sh b/tests/various/hierarchy.sh index d33a247be..9dbd1c89f 100644 --- a/tests/various/hierarchy.sh +++ b/tests/various/hierarchy.sh @@ -53,6 +53,7 @@ echo -n " no explicit top - " module noTop(a, y); input a; output [31:0] y; + assign y = a; endmodule EOV hierarchy -auto-top From 71da8363008159fed399ec74318d83e34642d1f2 Mon Sep 17 00:00:00 2001 From: Luke Wren Date: Wed, 17 Apr 2019 22:56:41 +0100 Subject: [PATCH 125/149] ice40 cells_sim.v: SB_IO: update clock enable behaviour based on hardware experiments --- techlibs/ice40/cells_sim.v | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 62a28364b..00843b97c 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -27,18 +27,27 @@ module SB_IO ( reg dout_q_0, dout_q_1; reg outena_q; + // IO tile generates a constant 1'b1 internally if global_cen is not connected + wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz; + reg clken_pulled_ri; + reg clken_pulled_ro; + generate if (!NEG_TRIGGER) begin - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(posedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(posedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(negedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(posedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(posedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(posedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end else begin - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(negedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(negedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(posedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(negedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(negedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(negedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end endgenerate always @* begin From d99422411f568d6d8d7de7d11346718e70012df4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 21 Apr 2019 14:16:34 -0700 Subject: [PATCH 126/149] Use new pmux2shiftx from #944, remove my old attempt --- passes/techmap/Makefile.inc | 1 - passes/techmap/pmux2shiftx.cc | 81 --------------------------------- passes/techmap/shregmap.cc | 52 --------------------- techlibs/xilinx/synth_xilinx.cc | 11 +++-- 4 files changed, 8 insertions(+), 137 deletions(-) delete mode 100644 passes/techmap/pmux2shiftx.cc diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 81df499da..cf9e198ad 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -37,7 +37,6 @@ OBJS += passes/techmap/attrmap.o OBJS += passes/techmap/zinit.o OBJS += passes/techmap/dff2dffs.o OBJS += passes/techmap/flowmap.o -OBJS += passes/techmap/pmux2shiftx.o endif GENFILES += passes/techmap/techmap.inc diff --git a/passes/techmap/pmux2shiftx.cc b/passes/techmap/pmux2shiftx.cc deleted file mode 100644 index 6ffc27a4c..000000000 --- a/passes/techmap/pmux2shiftx.cc +++ /dev/null @@ -1,81 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2012 Clifford Wolf - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#include "kernel/yosys.h" -#include "kernel/sigtools.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct Pmux2ShiftxPass : public Pass { - Pmux2ShiftxPass() : Pass("pmux2shiftx", "transform $pmux cells to $shiftx cells") { } - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" pmux2shiftx [selection]\n"); - log("\n"); - log("This pass transforms $pmux cells to $shiftx cells.\n"); - log("\n"); - } - void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE - { - log_header(design, "Executing PMUX2SHIFTX pass.\n"); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) { - break; - } - extra_args(args, argidx, design); - - for (auto module : design->selected_modules()) - for (auto cell : module->selected_cells()) - { - if (cell->type != "$pmux") - continue; - - // Create a new encoder, out of a $pmux, that takes - // the existing pmux's 'S' input and transforms it - // back into a binary value - RTLIL::SigSpec shiftx_a; - RTLIL::SigSpec pmux_s; - - int s_width = cell->getParam("\\S_WIDTH").as_int(); - if (!cell->getPort("\\A").is_fully_undef()) { - ++s_width; - shiftx_a.append(cell->getPort("\\A")); - pmux_s.append(module->Not(NEW_ID, module->ReduceOr(NEW_ID, cell->getPort("\\S")))); - } - const int clog2width = ceil(log2(s_width)); - - RTLIL::SigSpec pmux_b; - for (int i = s_width-1; i >= 0; i--) - pmux_b.append(RTLIL::Const(i, clog2width)); - shiftx_a.append(cell->getPort("\\B")); - pmux_s.append(cell->getPort("\\S")); - - RTLIL::SigSpec pmux_y = module->addWire(NEW_ID, clog2width); - module->addPmux(NEW_ID, RTLIL::Const(RTLIL::Sx, clog2width), pmux_b, pmux_s, pmux_y); - module->addShiftx(NEW_ID, shiftx_a, pmux_y, cell->getPort("\\Y")); - module->remove(cell); - } - } -} Pmux2ShiftxPass; - -PRIVATE_NAMESPACE_END diff --git a/passes/techmap/shregmap.cc b/passes/techmap/shregmap.cc index ec43b5654..a541b33be 100644 --- a/passes/techmap/shregmap.cc +++ b/passes/techmap/shregmap.cc @@ -96,7 +96,6 @@ struct ShregmapTechGreenpak4 : ShregmapTech struct ShregmapTechXilinx7 : ShregmapTech { dict> sigbit_to_shiftx_offset; - dict sigbit_to_eq_input; const ShregmapOptions &opts; ShregmapTechXilinx7(const ShregmapOptions &opts) : opts(opts) {} @@ -120,32 +119,6 @@ struct ShregmapTechXilinx7 : ShregmapTech for (auto bit : sigmap(cell->getPort("\\B"))) sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 1, j++); } - else if (cell->type == "$pmux") { - if (!cell->get_bool_attribute("\\shiftx_compatible")) continue; - int width = cell->getParam("\\WIDTH").as_int(); - int j = 0; - for (auto bit : sigmap(cell->getPort("\\A"))) - sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, 0, j++); - j = cell->getParam("\\S_WIDTH").as_int(); - int k = 0; - for (auto bit : sigmap(cell->getPort("\\B"))) { - sigbit_to_shiftx_offset[bit] = std::make_tuple(cell, j, k++); - if (k == width) { - k = 0; - --j; - } - } - log_assert(j == 0); - } - else if (cell->type == "$eq") { - auto b_wire = cell->getPort("\\B"); - // Keep track of $eq cells that compare against the value 1 - // in anticipation that they drive the select (S) port of a $pmux - if (b_wire.is_fully_const() && b_wire.as_int() == 1) { - auto y_wire = sigmap(cell->getPort("\\Y").as_bit()); - sigbit_to_eq_input[y_wire] = cell->getPort("\\A"); - } - } } } @@ -157,8 +130,6 @@ struct ShregmapTechXilinx7 : ShregmapTech if (cell) { if (cell->type == "$shiftx" && port == "\\A") return; - if (cell->type == "$pmux" && (port == "\\A" || port == "\\B")) - return; if (cell->type == "$mux" && (port == "\\A" || port == "\\B")) return; } @@ -210,10 +181,6 @@ struct ShregmapTechXilinx7 : ShregmapTech if (GetSize(taps) != shiftx->getParam("\\A_WIDTH").as_int()) return false; } - else if (shiftx->type == "$pmux") { - if (GetSize(taps) != shiftx->getParam("\\S_WIDTH").as_int() + 1) - return false; - } else if (shiftx->type == "$mux") { if (GetSize(taps) != 2) return false; @@ -250,25 +217,6 @@ struct ShregmapTechXilinx7 : ShregmapTech q_wire = shiftx->getPort("\\Y"); shiftx->setPort("\\Y", cell->module->addWire(NEW_ID)); } - else if (shiftx->type == "$pmux") { - // If the 'A' port is fully undef, then opt_expr -mux_undef - // has not been applied, so find the second-to-last bit of - // the 'S' port (corresponding to $eq cell comparing for 1) - // otherwise use the last bit of 'S' - const auto& s_wire_bits = shiftx->getPort("\\S").bits(); - SigBit s1; - if (shiftx->getPort("\\A").is_fully_undef()) - s1 = s_wire_bits[s_wire_bits.size() - 2]; - else - s1 = s_wire_bits[s_wire_bits.size() - 1]; - RTLIL::SigSpec y_wire = shiftx->getPort("\\Y"); - l_wire = sigbit_to_eq_input.at(s1); - log_assert(l_wire.size() == ceil(log2(taps.size()))); - int group = std::get<2>(it->second); - q_wire = y_wire[group]; - y_wire[group] = cell->module->addWire(NEW_ID); - shiftx->setPort("\\Y", y_wire); - } else if (shiftx->type == "$mux") { l_wire = shiftx->getPort("\\S"); q_wire = shiftx->getPort("\\Y"); diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 57bde998f..4f02a47ea 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -112,9 +112,11 @@ struct SynthXilinxPass : public Pass log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); - log(" opt -full\n"); log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); + log(" pmux2shiftx (without '-nosrl' only)\n"); + log(" opt_expr -mux_undef (without '-nosrl' only)\n"); log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); + log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); log("\n"); @@ -261,17 +263,20 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "fine")) { - Pass::call(design, "opt -fast -full"); + Pass::call(design, "opt -fast"); Pass::call(design, "memory_map"); Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); - Pass::call(design, "opt -full"); if (!nosrl) { Pass::call(design, "simplemap t:$dff t:$dffe"); + Pass::call(design, "pmux2shiftx"); + Pass::call(design, "opt_expr -mux_undef"); Pass::call(design, "shregmap -tech xilinx -minlen 3"); } + Pass::call(design, "opt -full"); + if (vpr) { Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); } else { From ae95aba60a573bf34034d6a70931bd55490d3f14 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 21 Apr 2019 14:16:59 -0700 Subject: [PATCH 127/149] Add comments --- techlibs/xilinx/synth_xilinx.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 4f02a47ea..f59c0c622 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -269,8 +269,15 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dff2dffe"); if (!nosrl) { + // shregmap operates on bit-level flops, not word-level, + // so break those down here Pass::call(design, "simplemap t:$dff t:$dffe"); + // shregmap -tech xilinx can cope with $shiftx and $mux + // cells for identifiying variable-length shift registers, + // so attempt to convert $pmux-es to the former Pass::call(design, "pmux2shiftx"); + // pmux2shiftx can leave behind a $pmux with a single entry + // -- need this to clean that up Pass::call(design, "opt_expr -mux_undef"); Pass::call(design, "shregmap -tech xilinx -minlen 3"); } From d342b5b135a85da0df5df0fa2acc25dec5605760 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 21 Apr 2019 15:33:03 -0700 Subject: [PATCH 128/149] Tidy up, fix for -nosrl --- techlibs/xilinx/ff_map.v | 13 +++++++++---- techlibs/xilinx/synth_xilinx.cc | 15 +++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v index 3d5f78770..c61fd7070 100644 --- a/techlibs/xilinx/ff_map.v +++ b/techlibs/xilinx/ff_map.v @@ -22,21 +22,26 @@ `ifndef _NO_FFS +`ifndef _NO_POS_SR module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule +`endif + +module \$_DFF_NN0_ (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); \$_DFF_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +`endif `endif diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index a9e50329c..e84a6714b 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -116,8 +116,7 @@ struct SynthXilinxPass : public Pass log(" pmux2shiftx (without '-nosrl' only)\n"); log(" opt_expr -mux_undef (without '-nosrl' only)\n"); log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); - log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); + log(" techmap -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_cells:\n"); @@ -125,7 +124,8 @@ struct SynthXilinxPass : public Pass log(" clean\n"); log("\n"); log(" map_luts:\n"); - log(" techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?\n"); + log(" opt -full\n"); + log(" techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v\n"); log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); log(" clean\n"); log(" shregmap -minlen 3 -init -params -enpol any_or_none (without '-nosrl' only)\n"); @@ -282,12 +282,10 @@ struct SynthXilinxPass : public Pass Pass::call(design, "shregmap -tech xilinx -minlen 3"); } - Pass::call(design, "opt -full"); - if (vpr) { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); + Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); } else { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + Pass::call(design, "techmap -map +/xilinx/arith_map.v"); } Pass::call(design, "hierarchy -check"); @@ -302,7 +300,8 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_luts")) { - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/ff_map.v t:$_DFF_?N?"); + Pass::call(design, "opt -full"); + Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); if (!nosrl) From 7b35d5759289f7a3139c6eaa525ef737b8d5d82b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 02:07:36 +0200 Subject: [PATCH 129/149] Disable blackbox detection in techmap files Signed-off-by: Clifford Wolf --- passes/techmap/techmap.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index ee319b6e6..1a4318460 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -1036,7 +1036,7 @@ struct TechmapPass : public Pass { simplemap_get_mappers(worker.simplemap_mappers); std::vector map_files; - std::string verilog_frontend = "verilog -nooverwrite"; + std::string verilog_frontend = "verilog -nooverwrite -noblackbox"; int max_iter = -1; size_t argidx; From cf1ba46fa029468869fb3af468d18ad72c8a9c4a Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 09:03:11 +0200 Subject: [PATCH 130/149] Re-added clean after techmap in synth_xilinx Signed-off-by: Clifford Wolf --- techlibs/xilinx/synth_xilinx.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index da6c0a4b2..d66722195 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -124,6 +124,7 @@ struct SynthXilinxPass : public Pass log(" techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT \\\n"); log(" -ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT\n"); + log(" clean\n"); log("\n"); log(" check:\n"); log(" hierarchy -check\n"); @@ -280,6 +281,7 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v"); Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); + Pass::call(design, "clean"); } if (check_label(active, run_from, run_to, "check")) From 93f32b5dec8fdb116971ca0ddb17cdc993e7036c Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 14:49:17 +0200 Subject: [PATCH 131/149] Set ENABLE_PYOSYS=0 by default Signed-off-by: Clifford Wolf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ff64a2541..adf996c0d 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ ENABLE_LIBYOSYS := 1 ENABLE_PROTOBUF := 0 # python wrappers -ENABLE_PYOSYS := 1 +ENABLE_PYOSYS := 0 PYTHON_VERSION_TESTCODE := "import sys;t='{v[0]}.{v[1]}'.format(v=list(sys.version_info[:2]));print(t)" PYTHON_EXECUTABLE := $(shell if python3 -c ""; then echo "python3"; else echo "python"; fi) PYTHON_VERSION := $(shell $(PYTHON_EXECUTABLE) -c ""$(PYTHON_VERSION_TESTCODE)"") From c0f9a74b121dd19e359038b6f6f76be0ffe3cc38 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 14:59:30 +0200 Subject: [PATCH 132/149] Set ENABLE_LIBYOSYS=0 by default Signed-off-by: Clifford Wolf --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index adf996c0d..249c1d0ee 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ ENABLE_READLINE := 1 ENABLE_EDITLINE := 0 ENABLE_VERIFIC := 0 ENABLE_COVER := 1 -ENABLE_LIBYOSYS := 1 +ENABLE_LIBYOSYS := 0 ENABLE_PROTOBUF := 0 # python wrappers From 0f0ada13f46fdc00a6f55f649647c177b4a150ff Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 15:26:20 +0200 Subject: [PATCH 133/149] Add full_pmux feature to pmux2shiftx Signed-off-by: Clifford Wolf --- passes/opt/pmux2shiftx.cc | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/passes/opt/pmux2shiftx.cc b/passes/opt/pmux2shiftx.cc index 5f897b131..29870f510 100644 --- a/passes/opt/pmux2shiftx.cc +++ b/passes/opt/pmux2shiftx.cc @@ -369,6 +369,7 @@ struct Pmux2ShiftxPass : public Pass { dict> seldb; + SigSpec A = cell->getPort("\\A"); SigSpec B = cell->getPort("\\B"); SigSpec S = sigmap(cell->getPort("\\S")); for (int i = 0; i < GetSize(S); i++) @@ -419,6 +420,8 @@ struct Pmux2ShiftxPass : public Pass { choices[val] = i; } + bool full_pmux = GetSize(choices) == GetSize(S); + // TBD: also find choices that are using signals that are subsets of the bits in "sig" if (!verbose) @@ -634,7 +637,21 @@ struct Pmux2ShiftxPass : public Pass { log(" range density: %d%%\n", range_density); log(" absolute density: %d%%\n", absolute_density); - bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (max_choice+1 == GetSize(choices)); + if (full_pmux) { + int full_density = 100*GetSize(choices) / (1 << GetSize(sig)); + log(" full density: %d%%\n", full_density); + if (full_density < min_density) { + full_pmux = false; + } else { + min_choice = 0; + max_choice = (1 << GetSize(sig))-1; + log(" update to full case.\n"); + log(" new min choice: %d\n", min_choice); + log(" new max choice: %d\n", max_choice); + } + } + + bool full_case = (min_choice == 0) && (max_choice == (1 << GetSize(sig))-1) && (full_pmux || max_choice+1 == GetSize(choices)); log(" full case: %s\n", full_case ? "true" : "false"); // check density percentages @@ -677,6 +694,10 @@ struct Pmux2ShiftxPass : public Pass { // create data signal SigSpec data(State::Sx, (max_choice+1)*extwidth); + if (full_pmux) { + for (int i = 0; i <= max_choice; i++) + data.replace(i*extwidth, A); + } for (auto &it : perm_choices) { int position = it.first.as_int()*extwidth; int data_index = it.second; From a80e74dc2057b175a99d5cbc2926b712f0323010 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 16:17:43 +0200 Subject: [PATCH 134/149] Updaye pmux2shiftx test Signed-off-by: Clifford Wolf --- tests/various/pmux2shiftx.ys | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/various/pmux2shiftx.ys b/tests/various/pmux2shiftx.ys index 6bb9626eb..deb134083 100644 --- a/tests/various/pmux2shiftx.ys +++ b/tests/various/pmux2shiftx.ys @@ -9,8 +9,8 @@ opt stat # show -width select -assert-count 1 t:$sub -select -assert-count 2 t:$mux -select -assert-count 2 t:$shift +select -assert-count 1 t:$mux +select -assert-count 1 t:$shift select -assert-count 3 t:$shiftx design -stash gate From aeeefc32d8603b138f24824d01b29d28cb0f85cf Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 22 Apr 2019 14:18:15 +0000 Subject: [PATCH 135/149] attrmap: extend -remove to allow removing attributes with any value. Currently, `-remove foo` would only remove an attribute `foo = ""`, which doesn't work on an attribute like `src` that may have any value. Extend `-remove` to handle both cases. `-remove foo=""` has the old behavior, and `-remove foo` will remove the attribute with whatever value it may have, which is still compatible with the old behavior. --- passes/techmap/attrmap.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/passes/techmap/attrmap.cc b/passes/techmap/attrmap.cc index 0b5576b06..aa48e1125 100644 --- a/passes/techmap/attrmap.cc +++ b/passes/techmap/attrmap.cc @@ -111,9 +111,10 @@ struct AttrmapMap : AttrmapAction { }; struct AttrmapRemove : AttrmapAction { + bool has_value; string name, value; bool apply(IdString &id, Const &val) YS_OVERRIDE { - return !(match_name(name, id) && match_value(value, val)); + return !(match_name(name, id) && (!has_value || match_value(value, val))); } }; @@ -235,6 +236,7 @@ struct AttrmapPass : public Pass { } auto action = new AttrmapRemove; action->name = arg1; + action->has_value = (p != string::npos); action->value = val1; actions.push_back(std::unique_ptr(action)); continue; From e158ea20979165c1bac4c5c4027cf53255e57baa Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 17:25:52 +0200 Subject: [PATCH 136/149] Add log_debug() framework Signed-off-by: Clifford Wolf --- frontends/aiger/aigerparse.cc | 2 - kernel/driver.cc | 8 +++- kernel/log.cc | 7 ++++ kernel/log.h | 43 +++++++++++++++++++ kernel/register.cc | 1 + passes/cmds/trace.cc | 34 +++++++++++++++ passes/opt/opt_clean.cc | 11 ++--- passes/opt/opt_expr.cc | 79 ++++++++++++++++++++--------------- passes/opt/opt_merge.cc | 8 ++-- passes/opt/opt_muxtree.cc | 6 +-- passes/techmap/techmap.cc | 37 +++++++++++++--- 11 files changed, 183 insertions(+), 53 deletions(-) diff --git a/frontends/aiger/aigerparse.cc b/frontends/aiger/aigerparse.cc index cf7950c85..2e4774dfd 100644 --- a/frontends/aiger/aigerparse.cc +++ b/frontends/aiger/aigerparse.cc @@ -33,8 +33,6 @@ YOSYS_NAMESPACE_BEGIN -#define log_debug log - AigerReader::AigerReader(RTLIL::Design *design, std::istream &f, RTLIL::IdString module_name, RTLIL::IdString clk_name) : design(design), f(f), clk_name(clk_name) { diff --git a/kernel/driver.cc b/kernel/driver.cc index c539ba569..1bc7a5935 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -295,6 +295,9 @@ int main(int argc, char **argv) printf(" -E \n"); printf(" write a Makefile dependencies file with in- and output file names\n"); printf("\n"); + printf(" -g\n"); + printf(" globally enable debug log messages\n"); + printf("\n"); printf(" -V\n"); printf(" print version information and exit\n"); printf("\n"); @@ -315,7 +318,7 @@ int main(int argc, char **argv) } int opt; - while ((opt = getopt(argc, argv, "MXAQTVSm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) + while ((opt = getopt(argc, argv, "MXAQTVSgm:f:Hh:b:o:p:l:L:qv:tds:c:W:w:e:D:P:E:")) != -1) { switch (opt) { @@ -340,6 +343,9 @@ int main(int argc, char **argv) case 'S': passes_commands.push_back("synth"); break; + case 'g': + log_force_debug++; + break; case 'm': plugin_filenames.push_back(optarg); break; diff --git a/kernel/log.cc b/kernel/log.cc index 400a549dd..9a9104e26 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -56,6 +56,10 @@ int log_verbose_level; string log_last_error; void (*log_error_atexit)() = NULL; +int log_make_debug = 0; +int log_force_debug = 0; +int log_debug_suppressed = 0; + vector header_count; pool log_id_cache; vector string_buf; @@ -92,6 +96,9 @@ void logv(const char *format, va_list ap) format++; } + if (log_make_debug && !ys_debug(1)) + return; + std::string str = vstringf(format, ap); if (str.empty()) diff --git a/kernel/log.h b/kernel/log.h index 759939025..e6afae716 100644 --- a/kernel/log.h +++ b/kernel/log.h @@ -64,6 +64,10 @@ extern int log_verbose_level; extern string log_last_error; extern void (*log_error_atexit)(); +extern int log_make_debug; +extern int log_force_debug; +extern int log_debug_suppressed; + void logv(const char *format, va_list ap); void logv_header(RTLIL::Design *design, const char *format, va_list ap); void logv_warning(const char *format, va_list ap); @@ -82,6 +86,45 @@ YS_NORETURN void log_error(const char *format, ...) YS_ATTRIBUTE(format(printf, void log_file_error(const string &filename, int lineno, const char *format, ...) YS_ATTRIBUTE(format(printf, 3, 4), noreturn); YS_NORETURN void log_cmd_error(const char *format, ...) YS_ATTRIBUTE(format(printf, 1, 2), noreturn); +#ifndef NDEBUG +static inline bool ys_debug(int n = 0) { if (log_force_debug) return true; log_debug_suppressed += n; return false; } +# define log_debug(...) do { if (ys_debug(1)) log(__VA_ARGS__); } while (0) +#else +static inline bool ys_debug(int n = 0) { return false; } +# define log_debug(_fmt, ...) do { } while (0) +#endif + +static inline void log_suppressed() { + if (log_debug_suppressed && !log_make_debug) { + log("\n", log_debug_suppressed); + log_debug_suppressed = 0; + } +} + +struct LogMakeDebugHdl { + bool status = false; + LogMakeDebugHdl(bool start_on = false) { + if (start_on) + on(); + } + ~LogMakeDebugHdl() { + off(); + } + void on() { + if (status) return; + status=true; + log_make_debug++; + } + void off_silent() { + if (!status) return; + status=false; + log_make_debug--; + } + void off() { + off_silent(); + } +}; + void log_spacer(); void log_push(); void log_pop(); diff --git a/kernel/register.cc b/kernel/register.cc index 64956401f..71eb6b187 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -87,6 +87,7 @@ Pass::pre_post_exec_state_t Pass::pre_execute() void Pass::post_execute(Pass::pre_post_exec_state_t state) { IdString::checkpoint(); + log_suppressed(); int64_t time_ns = PerformanceTimer::query() - state.begin_ns; runtime_ns += time_ns; diff --git a/passes/cmds/trace.cc b/passes/cmds/trace.cc index f5305cde9..cf3e46ace 100644 --- a/passes/cmds/trace.cc +++ b/passes/cmds/trace.cc @@ -94,4 +94,38 @@ struct TracePass : public Pass { } } TracePass; +struct DebugPass : public Pass { + DebugPass() : Pass("debug", "run command with debug log messages enabled") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" debug cmd\n"); + log("\n"); + log("Execute the specified command with debug log messages enabled\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) YS_OVERRIDE + { + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // .. parse options .. + break; + } + + log_force_debug++; + + try { + std::vector new_args(args.begin() + argidx, args.end()); + Pass::call(design, new_args); + } catch (...) { + log_force_debug--; + throw; + } + + log_force_debug--; + } +} DebugPass; + PRIVATE_NAMESPACE_END diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index c3b13acaf..c38e9df5e 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -137,7 +137,7 @@ void rmunused_module_cells(Module *module, bool verbose) for (auto cell : unused) { if (verbose) - log(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); + log_debug(" removing unused `%s' cell `%s'.\n", cell->type.c_str(), cell->name.c_str()); module->design->scratchpad_set_bool("opt.did_something", true); module->remove(cell); count_rm_cells++; @@ -326,7 +326,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos for (auto wire : maybe_del_wires) if (!used_signals.check_any(RTLIL::SigSpec(wire))) { if (check_public_name(wire->name) && verbose) { - log(" removing unused non-port wire %s.\n", wire->name.c_str()); + log_debug(" removing unused non-port wire %s.\n", wire->name.c_str()); } del_wires.insert(wire); del_wires_count++; @@ -336,7 +336,7 @@ void rmunused_module_signals(RTLIL::Module *module, bool purge_mode, bool verbos count_rm_wires += del_wires.size(); if (verbose && del_wires_count > 0) - log(" removed %d unused temporary wires.\n", del_wires_count); + log_debug(" removed %d unused temporary wires.\n", del_wires_count); } bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) @@ -399,7 +399,7 @@ bool rmunused_module_init(RTLIL::Module *module, bool purge_mode, bool verbose) } if (verbose) - log(" removing redundant init attribute on %s.\n", log_id(wire)); + log_debug(" removing redundant init attribute on %s.\n", log_id(wire)); wire->attributes.erase("\\init"); did_something = true; @@ -426,7 +426,7 @@ void rmunused_module(RTLIL::Module *module, bool purge_mode, bool verbose, bool } for (auto cell : delcells) { if (verbose) - log(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), + log_debug(" removing buffer cell `%s': %s = %s\n", cell->name.c_str(), log_signal(cell->getPort("\\Y")), log_signal(cell->getPort("\\A"))); module->remove(cell); } @@ -551,6 +551,7 @@ struct CleanPass : public Pass { rmunused_module(module, purge_mode, false, false); } + log_suppressed(); if (count_rm_cells > 0 || count_rm_wires > 0) log("Removed %d unused cells and %d unused wires.\n", count_rm_cells, count_rm_wires); diff --git a/passes/opt/opt_expr.cc b/passes/opt/opt_expr.cc index a05db2a4f..af6d352af 100644 --- a/passes/opt/opt_expr.cc +++ b/passes/opt/opt_expr.cc @@ -67,7 +67,7 @@ void replace_undriven(RTLIL::Design *design, RTLIL::Module *module) if (sig.size() == 0) continue; - log("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); + log_debug("Setting undriven signal in %s to undef: %s\n", RTLIL::id2cstr(module->name), log_signal(c)); module->connect(RTLIL::SigSig(c, RTLIL::SigSpec(RTLIL::State::Sx, c.width))); did_something = true; } @@ -78,7 +78,7 @@ void replace_cell(SigMap &assign_map, RTLIL::Module *module, RTLIL::Cell *cell, RTLIL::SigSpec Y = cell->getPort(out_port); out_val.extend_u0(Y.size(), false); - log("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", + log_debug("Replacing %s cell `%s' (%s) in module `%s' with constant driver `%s = %s'.\n", cell->type.c_str(), cell->name.c_str(), info.c_str(), module->name.c_str(), log_signal(Y), log_signal(out_val)); // log_cell(cell); @@ -134,7 +134,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ if (GetSize(grouped_bits[i]) == GetSize(bits_y)) return false; - log("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", + log_debug("Replacing %s cell `%s' in module `%s' with cells using grouped bits:\n", log_id(cell->type), log_id(cell), log_id(module)); for (int i = 0; i < GRP_N; i++) @@ -156,7 +156,7 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ } if (cell->type.in("$and", "$or") && i == GRP_CONST_A) { - log(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); + log_debug(" Direct Connection: %s (%s with %s)\n", log_signal(new_b), log_id(cell->type), log_signal(new_a)); module->connect(new_y, new_b); module->connect(new_conn); continue; @@ -180,10 +180,10 @@ bool group_cell_inputs(RTLIL::Module *module, RTLIL::Cell *cell, bool commutativ module->connect(new_conn); - log(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); + log_debug(" New cell `%s': A=%s", log_id(c), log_signal(new_a)); if (b_name == "\\B") - log(", B=%s", log_signal(new_b)); - log("\n"); + log_debug(", B=%s", log_signal(new_b)); + log_debug("\n"); } cover_list("opt.opt_expr.fine.group", "$not", "$pos", "$and", "$or", "$xor", "$xnor", cell->type.str()); @@ -197,7 +197,7 @@ void handle_polarity_inv(Cell *cell, IdString port, IdString param, const SigMap { SigSpec sig = assign_map(cell->getPort(port)); if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_signal(sig), log_signal(invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig))); @@ -226,7 +226,7 @@ void handle_clkpol_celltype_swap(Cell *cell, string type1, string type2, IdStrin if (cell->type.in(type1, type2)) { SigSpec sig = assign_map(cell->getPort(port)); if (invert_map.count(sig)) { - log("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", + log_debug("Inverting %s of %s cell `%s' in module `%s': %s -> %s\n", log_id(port), log_id(cell->type), log_id(cell), log_id(cell->module), log_signal(sig), log_signal(invert_map.at(sig))); cell->setPort(port, (invert_map.at(sig))); @@ -455,9 +455,10 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { if (cell->type == "$reduce_xnor") { cover("opt.opt_expr.reduce_xnor_not"); - log("Replacing %s cell `%s' in module `%s' with $not cell.\n", + log_debug("Replacing %s cell `%s' in module `%s' with $not cell.\n", log_id(cell->type), log_id(cell->name), log_id(module)); cell->type = "$not"; + did_something = true; } else { cover("opt.opt_expr.unary_buffer"); replace_cell(assign_map, module, cell, "unary_buffer", "\\Y", cell->getPort("\\A")); @@ -488,7 +489,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (GetSize(new_sig_a) < GetSize(sig_a)) { cover_list("opt.opt_expr.fine.neutral_A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_and", "$reduce_bool", cell->type.str()); - log("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_sig_a)); cell->setPort("\\A", new_sig_a); cell->parameters.at("\\A_WIDTH") = GetSize(new_sig_a); @@ -511,7 +512,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (GetSize(new_sig_b) < GetSize(sig_b)) { cover_list("opt.opt_expr.fine.neutral_B", "$logic_and", "$logic_or", cell->type.str()); - log("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", + log_debug("Replacing port B of %s cell `%s' in module `%s' with shorter expression: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_sig_b)); cell->setPort("\\B", new_sig_b); cell->parameters.at("\\B_WIDTH") = GetSize(new_sig_b); @@ -537,7 +538,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { cover("opt.opt_expr.fine.$reduce_and"); - log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort("\\A", sig_a = new_a); cell->parameters.at("\\A_WIDTH") = 1; @@ -563,7 +564,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_a != RTLIL::State::Sm && RTLIL::SigSpec(new_a) != sig_a) { cover_list("opt.opt_expr.fine.A", "$logic_not", "$logic_and", "$logic_or", "$reduce_or", "$reduce_bool", cell->type.str()); - log("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port A of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_a), log_signal(new_a)); cell->setPort("\\A", sig_a = new_a); cell->parameters.at("\\A_WIDTH") = 1; @@ -589,7 +590,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (new_b != RTLIL::State::Sm && RTLIL::SigSpec(new_b) != sig_b) { cover_list("opt.opt_expr.fine.B", "$logic_and", "$logic_or", cell->type.str()); - log("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", + log_debug("Replacing port B of %s cell `%s' in module `%s' with constant driver: %s -> %s\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), log_signal(sig_b), log_signal(new_b)); cell->setPort("\\B", sig_b = new_b); cell->parameters.at("\\B_WIDTH") = 1; @@ -640,7 +641,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if ((cell->type == "$_MUX_" || cell->type == "$mux") && invert_map.count(assign_map(cell->getPort("\\S"))) != 0) { cover_list("opt.opt_expr.invert.muxsel", "$_MUX_", "$mux", cell->type.str()); - log("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); + log_debug("Optimizing away select inverter for %s cell `%s' in module `%s'.\n", log_id(cell->type), log_id(cell), log_id(module)); RTLIL::SigSpec tmp = cell->getPort("\\A"); cell->setPort("\\A", cell->getPort("\\B")); cell->setPort("\\B", tmp); @@ -750,7 +751,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons ACTION_DO("\\Y", cell->getPort("\\A")); if (input == State::S0 && !a.is_fully_undef()) { cover("opt.opt_expr.action_" S__LINE__); - log("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", + log_debug("Replacing data input of %s cell `%s' in module `%s' with constant undef.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); cell->setPort("\\A", SigSpec(State::Sx, GetSize(a))); did_something = true; @@ -822,7 +823,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons ACTION_DO("\\Y", cell->getPort("\\A")); } else { cover_list("opt.opt_expr.eqneq.isnot", "$eq", "$ne", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); + log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->type = "$not"; cell->parameters.erase("\\B_WIDTH"); cell->parameters.erase("\\B_SIGNED"); @@ -837,7 +838,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons (assign_map(cell->getPort("\\A")).is_fully_zero() || assign_map(cell->getPort("\\B")).is_fully_zero())) { cover_list("opt.opt_expr.eqneq.cmpzero", "$eq", "$ne", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), + log_debug("Replacing %s cell `%s' in module `%s' with %s.\n", log_id(cell->type), log_id(cell), log_id(module), "$eq" ? "$logic_not" : "$reduce_bool"); cell->type = cell->type == "$eq" ? "$logic_not" : "$reduce_bool"; if (assign_map(cell->getPort("\\A")).is_fully_zero()) { @@ -876,7 +877,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons cover_list("opt.opt_expr.constshift", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", cell->type.str()); - log("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", + log_debug("Replacing %s cell `%s' (B=%s, SHR=%d) in module `%s' with fixed wiring: %s\n", log_id(cell->type), log_id(cell), log_signal(assign_map(cell->getPort("\\B"))), shift_bits, log_id(module), log_signal(sig_y)); module->connect(cell->getPort("\\Y"), sig_y); @@ -939,7 +940,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (identity_wrt_b) cover_list("opt.opt_expr.identwrt.b", "$add", "$sub", "$or", "$xor", "$shl", "$shr", "$sshl", "$sshr", "$shift", "$shiftx", "$mul", "$div", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", + log_debug("Replacing %s cell `%s' in module `%s' with identity for port %c.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str(), identity_wrt_a ? 'A' : 'B'); if (!identity_wrt_a) { @@ -969,7 +970,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(1, 1) && cell->getPort("\\B") == RTLIL::SigSpec(0, 1)) { cover_list("opt.opt_expr.mux_invert", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); + log_debug("Replacing %s cell `%s' in module `%s' with inverter.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", cell->getPort("\\S")); cell->unsetPort("\\B"); cell->unsetPort("\\S"); @@ -988,7 +989,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\A") == RTLIL::SigSpec(0, 1)) { cover_list("opt.opt_expr.mux_and", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + log_debug("Replacing %s cell `%s' in module `%s' with and-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", cell->getPort("\\S")); cell->unsetPort("\\S"); if (cell->type == "$mux") { @@ -1008,7 +1009,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (consume_x && mux_bool && (cell->type == "$mux" || cell->type == "$_MUX_") && cell->getPort("\\B") == RTLIL::SigSpec(1, 1)) { cover_list("opt.opt_expr.mux_or", "$mux", "$_MUX_", cell->type.str()); - log("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); + log_debug("Replacing %s cell `%s' in module `%s' with or-gate.\n", log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\B", cell->getPort("\\S")); cell->unsetPort("\\S"); if (cell->type == "$mux") { @@ -1061,7 +1062,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons } if (cell->getPort("\\S").size() != new_s.size()) { cover_list("opt.opt_expr.mux_reduce", "$mux", "$pmux", cell->type.str()); - log("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", + log_debug("Optimized away %d select inputs of %s cell `%s' in module `%s'.\n", GetSize(cell->getPort("\\S")) - GetSize(new_s), log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", new_a); cell->setPort("\\B", new_b); @@ -1179,7 +1180,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.mul_shift.zero"); - log("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", + log_debug("Replacing multiply-by-zero cell `%s' in module `%s' with zero-driver.\n", cell->name.c_str(), module->name.c_str()); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(0, sig_y.size()))); @@ -1197,7 +1198,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons else cover("opt.opt_expr.mul_shift.unswapped"); - log("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + log_debug("Replacing multiply-by-%d cell `%s' in module `%s' with shift-by-%d.\n", a_val, cell->name.c_str(), module->name.c_str(), i); if (!swapped_ab) { @@ -1237,7 +1238,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.divmod_zero"); - log("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", + log_debug("Replacing divide-by-zero cell `%s' in module `%s' with undef-driver.\n", cell->name.c_str(), module->name.c_str()); module->connect(RTLIL::SigSig(sig_y, RTLIL::SigSpec(State::Sx, sig_y.size()))); @@ -1254,7 +1255,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.div_shift"); - log("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", + log_debug("Replacing divide-by-%d cell `%s' in module `%s' with shift-by-%d.\n", b_val, cell->name.c_str(), module->name.c_str(), i); std::vector new_b = RTLIL::SigSpec(i, 6); @@ -1272,7 +1273,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons { cover("opt.opt_expr.mod_mask"); - log("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", + log_debug("Replacing modulo-by-%d cell `%s' in module `%s' with bitmask.\n", b_val, cell->name.c_str(), module->name.c_str()); std::vector new_b = RTLIL::SigSpec(State::S1, i); @@ -1342,7 +1343,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons SigSpec y_sig = cell->getPort("\\Y"); Const y_value(cell->type.in("$eq", "$eqx") ? 0 : 1, GetSize(y_sig)); - log("Replacing cell `%s' in module `%s' with constant driver %s.\n", + log_debug("Replacing cell `%s' in module `%s' with constant driver %s.\n", log_id(cell), log_id(module), log_signal(y_value)); module->connect(y_sig, y_value); @@ -1354,7 +1355,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (redundant_bits) { - log("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", + log_debug("Removed %d redundant input bits from %s cell `%s' in module `%s'.\n", redundant_bits, log_id(cell->type), log_id(cell), log_id(module)); cell->setPort("\\A", sig_a); @@ -1493,7 +1494,7 @@ void replace_const_cells(RTLIL::Design *design, RTLIL::Module *module, bool cons if (replace || remove) { - log("Replacing %s cell `%s' (implementing %s) with %s.\n", + log_debug("Replacing %s cell `%s' (implementing %s) with %s.\n", log_id(cell->type), log_id(cell), condition.c_str(), replacement.c_str()); if (replace) module->connect(cell->getPort("\\Y"), replace_sig); @@ -1599,8 +1600,14 @@ struct OptExprPass : public Pass { for (auto module : design->selected_modules()) { - if (undriven) + log("Optimizing module %s.\n", log_id(module)); + + if (undriven) { + did_something = false; replace_undriven(design, module); + if (did_something) + design->scratchpad_set_bool("opt.did_something", true); + } do { do { @@ -1610,7 +1617,11 @@ struct OptExprPass : public Pass { design->scratchpad_set_bool("opt.did_something", true); } while (did_something); replace_const_cells(design, module, true, mux_undef, mux_bool, do_fine, keepdc, clkinv); + if (did_something) + design->scratchpad_set_bool("opt.did_something", true); } while (did_something); + + log_suppressed(); } log_pop(); diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index eedf88904..7567d4657 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -315,17 +315,17 @@ struct OptMergeWorker { if (sharemap.count(cell) > 0) { did_something = true; - log(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); + log_debug(" Cell `%s' is identical to cell `%s'.\n", cell->name.c_str(), sharemap[cell]->name.c_str()); for (auto &it : cell->connections()) { if (cell->output(it.first)) { RTLIL::SigSpec other_sig = sharemap[cell]->getPort(it.first); - log(" Redirecting output %s: %s = %s\n", it.first.c_str(), + log_debug(" Redirecting output %s: %s = %s\n", it.first.c_str(), log_signal(it.second), log_signal(other_sig)); module->connect(RTLIL::SigSig(it.second, other_sig)); assign_map.add(it.second, other_sig); } } - log(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); + log_debug(" Removing %s cell `%s' from module `%s'.\n", cell->type.c_str(), cell->name.c_str(), module->name.c_str()); #ifdef USE_CELL_HASH_CACHE cell_hash_cache.erase(cell); #endif @@ -336,6 +336,8 @@ struct OptMergeWorker } } } + + log_suppressed(); } }; diff --git a/passes/opt/opt_muxtree.cc b/passes/opt/opt_muxtree.cc index 375697dc8..dbebf21e0 100644 --- a/passes/opt/opt_muxtree.cc +++ b/passes/opt/opt_muxtree.cc @@ -181,14 +181,14 @@ struct OptMuxtreeWorker for (int mux_idx = 0; mux_idx < GetSize(root_muxes); mux_idx++) if (root_muxes.at(mux_idx)) { - log(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); + log_debug(" Root of a mux tree: %s%s\n", log_id(mux2info[mux_idx].cell), root_enable_muxes.at(mux_idx) ? " (pure)" : ""); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); } while (!root_mux_rerun.empty()) { int mux_idx = *root_mux_rerun.begin(); - log(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); + log_debug(" Root of a mux tree: %s (rerun as non-pure)\n", log_id(mux2info[mux_idx].cell)); log_assert(root_enable_muxes.at(mux_idx)); root_mux_rerun.erase(mux_idx); eval_root_mux(mux_idx); @@ -326,7 +326,7 @@ struct OptMuxtreeWorker if (abort_count == 0) { root_mux_rerun.insert(m); root_enable_muxes.at(m) = true; - log(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); + log_debug(" Removing pure flag from root mux %s.\n", log_id(mux2info[m].cell)); } else eval_mux(knowledge, m, false, do_enable_ports, abort_count - 1); } else diff --git a/passes/techmap/techmap.cc b/passes/techmap/techmap.cc index 1a4318460..ab0bd3b54 100644 --- a/passes/techmap/techmap.cc +++ b/passes/techmap/techmap.cc @@ -72,6 +72,8 @@ struct TechmapWorker pool flatten_done_list; pool flatten_keep_list; + pool log_msg_cache; + struct TechmapWireData { RTLIL::Wire *wire; RTLIL::SigSpec value; @@ -390,6 +392,7 @@ struct TechmapWorker bool log_continue = false; bool did_something = false; + LogMakeDebugHdl mkdebug; SigMap sigmap(module); @@ -547,6 +550,7 @@ struct TechmapWorker if (extmapper_name == "wrap") { std::string cmd_string = tpl->attributes.at("\\techmap_wrap").decode_string(); log("Running \"%s\" on wrapper %s.\n", cmd_string.c_str(), log_id(extmapper_module)); + mkdebug.on(); Pass::call_on_module(extmapper_design, extmapper_module, cmd_string); log_continue = true; } @@ -560,11 +564,21 @@ struct TechmapWorker goto use_wrapper_tpl; } - log("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); + auto msg = stringf("Using extmapper %s for cells of type %s.", log_id(extmapper_module), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) to %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(extmapper_module)); } else { - log("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); + auto msg = stringf("Using extmapper %s for cells of type %s.", extmapper_name.c_str(), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) with %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), extmapper_name.c_str()); if (extmapper_name == "simplemap") { if (simplemap_mappers.count(cell->type) == 0) @@ -662,6 +676,7 @@ struct TechmapWorker tpl = techmap_cache[key]; } else { if (parameters.size() != 0) { + mkdebug.on(); derived_name = tpl->derive(map, dict(parameters.begin(), parameters.end())); tpl = map->module(derived_name); log_continue = true; @@ -831,6 +846,7 @@ struct TechmapWorker if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } while (techmap_module(map, tpl, map, handled_cells, celltypeMap, true)) { } } @@ -842,6 +858,7 @@ struct TechmapWorker if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } if (extern_mode && !in_recursion) @@ -861,13 +878,18 @@ struct TechmapWorker module_queue.insert(m); } - log("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); + log_debug("%s %s.%s to imported %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(m_name)); cell->type = m_name; cell->parameters.clear(); } else { - log("%s %s.%s using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(tpl)); + auto msg = stringf("Using template %s for cells of type %s.", log_id(tpl), log_id(cell->type)); + if (!log_msg_cache.count(msg)) { + log_msg_cache.insert(msg); + log("%s\n", msg.c_str()); + } + log_debug("%s %s.%s (%s) using %s.\n", mapmsg_prefix.c_str(), log_id(module), log_id(cell), log_id(cell->type), log_id(tpl)); techmap_module_worker(design, module, cell, tpl); cell = NULL; } @@ -885,6 +907,7 @@ struct TechmapWorker if (log_continue) { log_header(design, "Continuing TECHMAP pass.\n"); log_continue = false; + mkdebug.off(); } return did_something; @@ -1085,7 +1108,7 @@ struct TechmapPass : public Pass { if (map_files.empty()) { std::istringstream f(stdcells_code); Frontend::frontend_call(map, &f, "", verilog_frontend); - } else + } else { for (auto &fn : map_files) if (fn.substr(0, 1) == "%") { if (!saved_designs.count(fn.substr(1))) { @@ -1104,6 +1127,9 @@ struct TechmapPass : public Pass { log_cmd_error("Can't open map file `%s'\n", fn.c_str()); Frontend::frontend_call(map, &f, fn, (fn.size() > 3 && fn.substr(fn.size()-3) == ".il") ? "ilang" : verilog_frontend); } + } + + log_header(design, "Continuing TECHMAP pass.\n"); std::map> celltypeMap; for (auto &it : map->modules_) { @@ -1211,6 +1237,7 @@ struct FlattenPass : public Pass { } } + log_suppressed(); log("No more expansions possible.\n"); if (top_mod != NULL) From 4ad0ea5c3c325dc639829f6c6836353044585af5 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 18:19:02 +0200 Subject: [PATCH 137/149] Determine correct signedness and expression width in for loop unrolling, fixes #370 Signed-off-by: Clifford Wolf --- frontends/ast/simplify.cc | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 76da5a97c..3e453bd7f 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -1085,7 +1085,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // eval 1st expression AstNode *varbuf = init_ast->children[1]->clone(); - while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + varbuf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (varbuf->simplify(true, false, false, stage, 32, true, false)) { } + } if (varbuf->type != AST_CONSTANT) log_file_error(filename, linenum, "Right hand side of 1st expression of generate for-loop is not constant!\n"); @@ -1107,7 +1112,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, { // eval 2nd expression AstNode *buf = while_ast->clone(); - while (buf->simplify(true, false, false, stage, width_hint, sign_hint, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + buf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, false)) { } + } if (buf->type != AST_CONSTANT) log_file_error(filename, linenum, "2nd expression of generate for-loop is not constant!\n"); @@ -1148,7 +1158,12 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // eval 3rd expression buf = next_ast->children[1]->clone(); - while (buf->simplify(true, false, false, stage, 32, true, false)) { } + { + int expr_width_hint = -1; + bool expr_sign_hint = true; + buf->detectSignWidth(expr_width_hint, expr_sign_hint); + while (buf->simplify(true, false, false, stage, expr_width_hint, expr_sign_hint, true)) { } + } if (buf->type != AST_CONSTANT) log_file_error(filename, linenum, "Right hand side of 3rd expression of generate for-loop is not constant!\n"); From 0e0c80fac883a6f512a94aecdc3c915b8cacb562 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 22 Apr 2019 19:44:10 +0200 Subject: [PATCH 138/149] Add support for zero-width signals to Verilog back-end, fixes #948 Signed-off-by: Clifford Wolf --- backends/verilog/verilog_backend.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 855409d0b..9967482d6 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -187,6 +187,10 @@ void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int o { if (width < 0) width = data.bits.size() - offset; + if (width == 0) { + f << "\"\""; + return; + } if (nostr) goto dump_hex; if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) { @@ -340,6 +344,10 @@ void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decima void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig) { + if (GetSize(sig) == 0) { + f << "\"\""; + return; + } if (sig.is_chunk()) { dump_sigchunk(f, sig.as_chunk()); } else { From 0e76718720895a4985a7fad24052a61550acdeda Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Apr 2019 10:45:39 -0700 Subject: [PATCH 139/149] Move 'shregmap -tech xilinx' into map_cells --- techlibs/xilinx/synth_xilinx.cc | 39 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1449e792f..d6e7c2623 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -112,14 +112,14 @@ struct SynthXilinxPass : public Pass log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); - log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); - log(" pmux2shiftx (without '-nosrl' only)\n"); - log(" opt_expr -mux_undef (without '-nosrl' only)\n"); - log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" techmap -map +/xilinx/arith_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_cells:\n"); + log(" simplemap t:$dff t:$dffe (without '-nosrl' only)\n"); + log(" pmux2shiftx (without '-nosrl' only)\n"); + log(" opt_expr -mux_undef (without '-nosrl' only)\n"); + log(" shregmap -tech xilinx -minlen 3 (without '-nosrl' only)\n"); log(" techmap -map +/xilinx/cells_map.v\n"); log(" clean\n"); log("\n"); @@ -269,20 +269,6 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); - if (!nosrl) { - // shregmap operates on bit-level flops, not word-level, - // so break those down here - Pass::call(design, "simplemap t:$dff t:$dffe"); - // shregmap -tech xilinx can cope with $shiftx and $mux - // cells for identifiying variable-length shift registers, - // so attempt to convert $pmux-es to the former - Pass::call(design, "pmux2shiftx"); - // pmux2shiftx can leave behind a $pmux with a single entry - // -- need this to clean that up - Pass::call(design, "opt_expr -mux_undef"); - Pass::call(design, "shregmap -tech xilinx -minlen 3"); - } - if (vpr) { Pass::call(design, "techmap -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); } else { @@ -295,6 +281,21 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "map_cells")) { + if (!nosrl) { + // shregmap operates on bit-level flops, not word-level, + // so break those down here + Pass::call(design, "simplemap t:$dff t:$dffe"); + // shregmap -tech xilinx can cope with $shiftx and $mux + // cells for identifiying variable-length shift registers, + // so attempt to convert $pmux-es to the former + Pass::call(design, "pmux2shiftx"); + // pmux2shiftx can leave behind a $pmux with a single entry + // -- need this to clean that up before shregmap + Pass::call(design, "opt_expr -mux_undef"); + // shregmap with '-tech xilinx' infers variable length shift regs + Pass::call(design, "shregmap -tech xilinx -minlen 3"); + } + Pass::call(design, "techmap -map +/xilinx/cells_map.v"); Pass::call(design, "clean"); } @@ -305,6 +306,8 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/techmap.v -D _NO_POS_SR -map +/xilinx/ff_map.v"); Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); + // This shregmap call infers fixed length shift registers after abc + // has performed any necessary retiming if (!nosrl) Pass::call(design, "shregmap -minlen 3 -init -params -enpol any_or_none"); Pass::call(design, "techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); From ec88129a5cf510afc39ea12efa6059bed3eadfc3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 22 Apr 2019 11:38:23 -0700 Subject: [PATCH 140/149] Update help message --- techlibs/xilinx/synth_xilinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index d6e7c2623..53eee7962 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -108,7 +108,7 @@ struct SynthXilinxPass : public Pass log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); log(" fine:\n"); - log(" opt -fast -full\n"); + log(" opt -fast\n"); log(" memory_map\n"); log(" dffsr2dff\n"); log(" dff2dffe\n"); From c84cdc711c6f78175c3ef236c3aa7640d7485b79 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Tue, 23 Apr 2019 17:55:41 +0200 Subject: [PATCH 141/149] Remove some left-over log_dump() Signed-off-by: Clifford Wolf --- passes/opt/wreduce.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 52245ce3e..68e077cf9 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -462,12 +462,10 @@ struct WreduceWorker SigSpec initsig = init_attr_sigmap(w); int width = std::min(GetSize(initval), GetSize(initsig)); for (int i = 0; i < width; i++) { - log_dump(initsig[i], remove_init_bits.count(initsig[i])); if (!remove_init_bits.count(initsig[i])) new_initval[i] = initval[i]; } w->attributes.at("\\init") = new_initval; - log_dump(w->name, initval, new_initval); } } } From f66792c43afeacdcceedde83785471e51ee12593 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Apr 2019 08:58:34 -0700 Subject: [PATCH 142/149] Fix spelling --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 46bed4242..7b4477053 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,7 @@ Verilog Attributes and non-standard features - When defining a macro with `define, all text between triple double quotes is interpreted as macro body, even if it contains unescaped newlines. The - tipple double quotes are removed from the macro body. For example: + triple double quotes are removed from the macro body. For example: `define MY_MACRO(a, b) """ assign a = 23; From c6156f3118f327986d801fb48e50b94b7ea9e4b6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 23 Apr 2019 09:01:10 -0700 Subject: [PATCH 143/149] Format some names using inline code --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b4477053..913777f2e 100644 --- a/README.md +++ b/README.md @@ -457,7 +457,7 @@ Non-standard or SystemVerilog features for formal verification supported in any clocked block. - The syntax ``@($global_clock)`` can be used to create FFs that have no - explicit clock input ($ff cells). The same can be achieved by using + explicit clock input (``$ff`` cells). The same can be achieved by using ``@(posedge )`` or ``@(negedge )`` when ```` is marked with the ``(* gclk *)`` Verilog attribute. @@ -470,7 +470,7 @@ from SystemVerilog: - The ``assert`` statement from SystemVerilog is supported in its most basic form. In module context: ``assert property ();`` and within an - always block: ``assert();``. It is transformed to a $assert cell. + always block: ``assert();``. It is transformed to an ``$assert`` cell. - The ``assume``, ``restrict``, and ``cover`` statements from SystemVerilog are also supported. The same limitations as with the ``assert`` statement apply. From 742c2f245dbe9db1cb89257b296b71b1cb9ac771 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 23 Apr 2019 17:54:00 +0100 Subject: [PATCH 144/149] Fixes for OAI4 cell implementation Fixes #955 and the underlying issue in #954 Signed-off-by: David Shah --- kernel/cellaigs.cc | 2 +- kernel/celltypes.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 5fd76afe5..26c625f89 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -453,7 +453,7 @@ Aig::Aig(Cell *cell) int B = mk.inport("\\B"); int C = mk.inport("\\C"); int D = mk.inport("\\D"); - int Y = mk.nand_gate(mk.nor_gate(A, B), mk.nor_gate(C, D)); + int Y = mk.nand_gate(mk.or_gate(A, B), mk.or_gate(C, D)); mk.outport(Y, "\\Y"); goto optimize; } diff --git a/kernel/celltypes.h b/kernel/celltypes.h index ae88f4aaf..0da78c313 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -464,7 +464,7 @@ struct CellTypes if (cell->type == "$_AOI4_") return eval_not(const_or(const_and(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); if (cell->type == "$_OAI4_") - return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_and(arg3, arg4, false, false, 1), false, false, 1)); + return eval_not(const_and(const_or(arg1, arg2, false, false, 1), const_or(arg3, arg4, false, false, 1), false, false, 1)); log_assert(arg4.bits.size() == 0); return eval(cell, arg1, arg2, arg3, errp); From 408161ea3af78c747b9d45cd6482f2e4d9170085 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 25 Apr 2019 16:46:13 -0700 Subject: [PATCH 145/149] Misspelling --- passes/pmgen/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index 7a46558b1..320e95a77 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -220,5 +220,5 @@ But in some cases it is more natural to utilize the implicit branch statement: portAB = \B; endcode -There is an implicit `code..endcode` block at the end of each `.pgm` file +There is an implicit `code..endcode` block at the end of each `.pmg` file that just accepts everything that gets all the way there. From 159e7cc2983e3d026fa8c5187252bb890a04b96f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Apr 2019 11:14:33 -0700 Subject: [PATCH 146/149] Add -undef option to equiv_opt, passed to equiv_induct --- passes/equiv/equiv_opt.cc | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/passes/equiv/equiv_opt.cc b/passes/equiv/equiv_opt.cc index e5dda9c24..3596dfd7b 100644 --- a/passes/equiv/equiv_opt.cc +++ b/passes/equiv/equiv_opt.cc @@ -44,7 +44,10 @@ struct EquivOptPass:public ScriptPass log(" useful for handling architecture-specific primitives.\n"); log("\n"); log(" -assert\n"); - log(" produce an error if the circuits are not equivalent\n"); + log(" produce an error if the circuits are not equivalent.\n"); + log("\n"); + log(" -undef\n"); + log(" enable modelling of undef states during equiv_induct.\n"); log("\n"); log("The following commands are executed by this verification command:\n"); help_script(); @@ -52,13 +55,14 @@ struct EquivOptPass:public ScriptPass } std::string command, techmap_opts; - bool assert; + bool assert, undef; void clear_flags() YS_OVERRIDE { command = ""; techmap_opts = ""; assert = false; + undef = false; } void execute(std::vector < std::string > args, RTLIL::Design * design) YS_OVERRIDE @@ -84,6 +88,10 @@ struct EquivOptPass:public ScriptPass assert = true; continue; } + if (args[argidx] == "-undef") { + undef = true; + continue; + } break; } @@ -139,7 +147,12 @@ struct EquivOptPass:public ScriptPass if (check_label("prove")) { run("equiv_make gold gate equiv"); - run("equiv_induct equiv"); + if (help_mode) + run("equiv_induct [-undef] equiv"); + else if (undef) + run("equiv_induct -undef equiv"); + else + run("equiv_induct equiv"); if (help_mode) run("equiv_status [-assert] equiv"); else if (assert) From ea0e0722bb42254ac8c63eb41664d9dfb7973aec Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 26 Apr 2019 15:35:34 -0700 Subject: [PATCH 147/149] Where did this check come from!?! --- techlibs/xilinx/synth_xilinx.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 53eee7962..58dd928a0 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -275,7 +275,6 @@ struct SynthXilinxPass : public Pass Pass::call(design, "techmap -map +/xilinx/arith_map.v"); } - Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); } From e531fb203aedeb3863ebf8add0bbd8251183d27a Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Mon, 29 Apr 2019 16:13:34 +0900 Subject: [PATCH 148/149] escape spaces with backslash when writing dep file filenames are sparated by spaces in the dep file. if a filename in the dep file contains spaces they must be escaped, otherwise the tool that reads the dep file will see multiple wrong filenames. --- kernel/driver.cc | 4 ++-- kernel/yosys.cc | 14 ++++++++++++++ kernel/yosys.h | 1 + 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 1bc7a5935..8c56d059b 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -529,13 +529,13 @@ int main(int argc, char **argv) log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); bool first = true; for (auto fn : yosys_output_files) { - fprintf(f, "%s%s", first ? "" : " ", fn.c_str()); + fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces (fn).c_str()); first = false; } fprintf(f, ":"); for (auto fn : yosys_input_files) { if (yosys_output_files.count(fn) == 0) - fprintf(f, " %s", fn.c_str()); + fprintf(f, " %s", escape_filename_spaces (fn).c_str()); } fprintf(f, "\n"); } diff --git a/kernel/yosys.cc b/kernel/yosys.cc index a12355f1d..267a7d01c 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -482,6 +482,20 @@ void remove_directory(std::string dirname) #endif } +std::string escape_filename_spaces (const std::string& filename) +{ + std::string out; + out.reserve (filename.size ()); + for (auto c : filename) + { + if (c == ' ') + out += "\\ "; + else + out.push_back (c); + } + return out; +} + int GetSize(RTLIL::Wire *wire) { return wire->width; diff --git a/kernel/yosys.h b/kernel/yosys.h index 2cf6188b4..d64904151 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -257,6 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); +std::string escape_filename_spaces (const std::string& filename); template int GetSize(const T &obj) { return obj.size(); } int GetSize(RTLIL::Wire *wire); From 4f15e7f00fa2b073d6df39d4af7171f2a3f07bc9 Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Mon, 29 Apr 2019 19:20:33 +0900 Subject: [PATCH 149/149] fix codestyle formatting --- kernel/driver.cc | 4 ++-- kernel/yosys.cc | 22 +++++++++++----------- kernel/yosys.h | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/kernel/driver.cc b/kernel/driver.cc index 8c56d059b..f273057dd 100644 --- a/kernel/driver.cc +++ b/kernel/driver.cc @@ -529,13 +529,13 @@ int main(int argc, char **argv) log_error("Can't open dependencies file for writing: %s\n", strerror(errno)); bool first = true; for (auto fn : yosys_output_files) { - fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces (fn).c_str()); + fprintf(f, "%s%s", first ? "" : " ", escape_filename_spaces(fn).c_str()); first = false; } fprintf(f, ":"); for (auto fn : yosys_input_files) { if (yosys_output_files.count(fn) == 0) - fprintf(f, " %s", escape_filename_spaces (fn).c_str()); + fprintf(f, " %s", escape_filename_spaces(fn).c_str()); } fprintf(f, "\n"); } diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 267a7d01c..20d972150 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -482,18 +482,18 @@ void remove_directory(std::string dirname) #endif } -std::string escape_filename_spaces (const std::string& filename) +std::string escape_filename_spaces(const std::string& filename) { - std::string out; - out.reserve (filename.size ()); - for (auto c : filename) - { - if (c == ' ') - out += "\\ "; - else - out.push_back (c); - } - return out; + std::string out; + out.reserve(filename.size()); + for (auto c : filename) + { + if (c == ' ') + out += "\\ "; + else + out.push_back(c); + } + return out; } int GetSize(RTLIL::Wire *wire) diff --git a/kernel/yosys.h b/kernel/yosys.h index d64904151..82eb069ab 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -257,7 +257,7 @@ std::string make_temp_dir(std::string template_str = "/tmp/yosys_XXXXXX"); bool check_file_exists(std::string filename, bool is_exec = false); bool is_absolute_path(std::string filename); void remove_directory(std::string dirname); -std::string escape_filename_spaces (const std::string& filename); +std::string escape_filename_spaces(const std::string& filename); template int GetSize(const T &obj) { return obj.size(); } int GetSize(RTLIL::Wire *wire);