aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/xilinx
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/xilinx')
-rw-r--r--techlibs/xilinx/Makefile.inc7
-rw-r--r--techlibs/xilinx/abc9_map.v119
-rw-r--r--techlibs/xilinx/abc9_model.v7
-rw-r--r--techlibs/xilinx/abc9_xc7.box61
-rw-r--r--techlibs/xilinx/arith_map.v262
-rw-r--r--techlibs/xilinx/cells_sim.v625
-rw-r--r--techlibs/xilinx/cells_xtra.py42
-rw-r--r--techlibs/xilinx/cells_xtra.v59
-rw-r--r--techlibs/xilinx/lut4_lutrams.txt19
-rw-r--r--techlibs/xilinx/lut6_lutrams.txt (renamed from techlibs/xilinx/lutrams.txt)28
-rw-r--r--techlibs/xilinx/lut_map.v109
-rw-r--r--techlibs/xilinx/synth_xilinx.cc135
-rw-r--r--techlibs/xilinx/tests/.gitignore3
-rw-r--r--techlibs/xilinx/tests/test_dsp48_model.sh14
-rw-r--r--techlibs/xilinx/tests/test_dsp48_model.v287
-rw-r--r--techlibs/xilinx/xc2v_brams.txt31
-rw-r--r--techlibs/xilinx/xc2v_brams_map.v266
-rw-r--r--techlibs/xilinx/xc3sa_brams.txt51
-rw-r--r--techlibs/xilinx/xc3sda_brams.txt33
-rw-r--r--techlibs/xilinx/xc6s_brams.txt1
-rw-r--r--techlibs/xilinx/xc6s_brams_map.v3
-rw-r--r--techlibs/xilinx/xc7_brams_map.v2
-rw-r--r--techlibs/xilinx/xc7_xcu_brams.txt2
-rw-r--r--techlibs/xilinx/xcu_brams_map.v2
24 files changed, 1633 insertions, 535 deletions
diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc
index 3f2fbcc85..d07bae12a 100644
--- a/techlibs/xilinx/Makefile.inc
+++ b/techlibs/xilinx/Makefile.inc
@@ -27,6 +27,10 @@ techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc2v_brams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc2v_brams_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3sa_brams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3sda_brams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_xcu_brams.txt))
@@ -34,7 +38,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_brams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut4_lutrams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut6_lutrams.txt))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_ff_map.v))
diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v
index 0652064cb..f2c401d66 100644
--- a/techlibs/xilinx/abc9_map.v
+++ b/techlibs/xilinx/abc9_map.v
@@ -68,13 +68,14 @@
// (c) a special abc9_ff.clock wire to capture its clock domain and polarity
// (indicated to `abc9' so that it only performs sequential synthesis
// (with reachability analysis) correctly on one domain at a time)
-// (d) a special abc9_ff.init wire to encode the flop's initial state
-// NOTE: in order to perform sequential synthesis, `abc9' also requires
-// that the initial value of all flops be zero
+// (d) an (* abc9_init *) attribute on the $__ABC9_FF_ cell capturing its
+// initial state
+// NOTE: in order to perform sequential synthesis, `abc9' requires that
+// the initial value of all flops be zero
// (e) a special _TECHMAP_REPLACE_.abc9_ff.Q wire that will be used for feedback
// into the (combinatorial) FD* cell to facilitate clock-enable behaviour
-module FDRE (output Q, input C, CE, D, R);
+module FDRE (output Q, (* techmap_autopurge *) input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -103,14 +104,14 @@ module FDRE (output Q, input C, CE, D, R);
);
end
endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDRE_1 (output Q, input C, CE, D, R);
+module FDRE_1 (output Q, (* techmap_autopurge *) input C, CE, D, R);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
@@ -130,15 +131,15 @@ module FDRE_1 (output Q, input C, CE, D, R);
);
end
endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDSE (output Q, input C, CE, D, S);
+module FDSE (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -166,14 +167,14 @@ module FDSE (output Q, input C, CE, D, S);
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDSE_1 (output Q, input C, CE, D, S);
+module FDSE_1 (output Q, (* techmap_autopurge *) input C, CE, D, S);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q;
generate if (INIT == 1'b1) begin
@@ -192,15 +193,15 @@ module FDSE_1 (output Q, input C, CE, D, S);
.D(D), .Q($Q), .C(C), .CE(CE), .S(S)
);
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q(QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = QQ;
endmodule
-module FDCE (output Q, input C, CE, D, CLR);
+module FDCE (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -215,11 +216,11 @@ module FDCE (output Q, input C, CE, D, CLR);
.IS_PRE_INVERTED(IS_CLR_INVERTED)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC1 below
);
// Since this is an async flop, async behaviour is dealt with here
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
@@ -233,23 +234,23 @@ module FDCE (output Q, input C, CE, D, CLR);
.IS_CLR_INVERTED(IS_CLR_INVERTED)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC0 below
);
// Since this is an async flop, async behaviour is dealt with here
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR ^ IS_CLR_INVERTED), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDCE_1 (output Q, input C, CE, D, CLR);
+module FDCE_1 (output Q, (* techmap_autopurge *) input C, CE, D, CLR);
parameter [0:0] INIT = 1'b0;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
@@ -258,11 +259,11 @@ module FDCE_1 (output Q, input C, CE, D, CLR);
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .PRE(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(CLR), .Y(QQ));
end
@@ -272,23 +273,23 @@ module FDCE_1 (output Q, input C, CE, D, CLR);
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .CLR(CLR)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(CLR), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDPE (output Q, input C, CE, D, PRE);
+module FDPE (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
parameter [0:0] IS_C_INVERTED = 1'b0;
parameter [0:0] IS_D_INVERTED = 1'b0;
@@ -303,11 +304,11 @@ module FDPE (output Q, input C, CE, D, PRE);
.IS_CLR_INVERTED(IS_PRE_INVERTED),
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end
@@ -320,22 +321,22 @@ module FDPE (output Q, input C, CE, D, PRE);
.IS_PRE_INVERTED(IS_PRE_INVERTED),
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE ^ IS_PRE_INVERTED), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, IS_C_INVERTED};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
-module FDPE_1 (output Q, input C, CE, D, PRE);
+module FDPE_1 (output Q, (* techmap_autopurge *) input C, CE, D, PRE);
parameter [0:0] INIT = 1'b1;
wire QQ, $Q, $QQ;
generate if (INIT == 1'b1) begin
@@ -344,11 +345,11 @@ module FDPE_1 (output Q, input C, CE, D, PRE);
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(~D), .Q($Q), .C(C), .CE(CE), .CLR(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC0 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC0 below
);
$__ABC9_ASYNC0 abc_async (.A($QQ), .S(PRE), .Y(QQ));
end
@@ -358,19 +359,19 @@ module FDPE_1 (output Q, input C, CE, D, PRE);
.INIT(1'b0)
) _TECHMAP_REPLACE_ (
.D(D), .Q($Q), .C(C), .CE(CE), .PRE(PRE)
- // ^^^ Note that async
- // control is not directly
- // supported by abc9 but its
- // behaviour is captured by
- // $__ABC9_ASYNC1 below
+ // ^^^ Note that async
+ // control is not directly
+ // supported by abc9 but its
+ // behaviour is captured by
+ // $__ABC9_ASYNC1 below
);
$__ABC9_ASYNC1 abc_async (.A($QQ), .S(PRE), .Y(QQ));
end endgenerate
+ (* abc9_init = 1'b0 *)
$__ABC9_FF_ abc9_ff (.D($Q), .Q($QQ));
// Special signals
wire [1:0] abc9_ff.clock = {C, 1'b1 /* IS_C_INVERTED */};
- wire [0:0] abc9_ff.init = 1'b0;
wire [0:0] _TECHMAP_REPLACE_.abc9_ff.Q = $QQ;
endmodule
`endif
diff --git a/techlibs/xilinx/abc9_model.v b/techlibs/xilinx/abc9_model.v
index 204fa883f..782c53ab6 100644
--- a/techlibs/xilinx/abc9_model.v
+++ b/techlibs/xilinx/abc9_model.v
@@ -33,6 +33,11 @@ endmodule
module \$__ABC9_FF_ (input D, output Q);
endmodule
+(* abc9_box_id = (9000+DELAY) *)
+module \$__ABC9_DELAY (input I, output O);
+ parameter DELAY = 0;
+endmodule
+
// Box to emulate async behaviour of FDC*
(* abc9_box_id = 1000, lib_whitebox *)
module \$__ABC9_ASYNC0 (input A, S, output Y);
@@ -42,7 +47,7 @@ endmodule
// Box to emulate async behaviour of FDP*
(* abc9_box_id = 1001, lib_whitebox *)
module \$__ABC9_ASYNC1 (input A, S, output Y);
- assign Y = S ? 1'b0 : A;
+ assign Y = S ? 1'b1 : A;
endmodule
// Box to emulate comb/seq behaviour of RAM{32,64} and SRL{16,32}
diff --git a/techlibs/xilinx/abc9_xc7.box b/techlibs/xilinx/abc9_xc7.box
index 13f4f0e61..48d492801 100644
--- a/techlibs/xilinx/abc9_xc7.box
+++ b/techlibs/xilinx/abc9_xc7.box
@@ -62,67 +62,6 @@ $__ABC9_ASYNC1 1001 1 2 1
#A S
0 764 # Y
-# Flop boxes:
-# * Max delays from https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L237-L251
-# https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/slicel.sdf#L265-L277
-# * Exception: $abc9_currQ is a special input (located last) necessary for clock-enable functionality
-
-# Box 1100 : FDRE
-# name ID w/b ins outs
-FDRE 1100 1 5 1
-#C CE D R $abc9_currQ
-#0 109 -46 404 0
-0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1101 : FDRE_1
-# name ID w/b ins outs
-FDRE_1 1101 1 5 1
-#C CE D R $abc9_currQ
-#0 109 -46 404 0
-0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1102 : FDSE
-# name ID w/b ins outs
-FDSE 1102 1 5 1
-#C CE D R $abc9_currQ
-#0 109 -46 404 0
-0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1103 : FDSE_1
-# name ID w/b ins outs
-FDSE_1 1103 1 5 1
-#C CE D R $abc9_currQ
-#0 109 -46 404 0
-0 109 0 404 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1104 : FDCE
-# name ID w/b ins outs
-FDCE 1104 1 5 1
-#C CE CLR D $abc9_currQ
-#0 109 764 -46 0
-0 109 764 0 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1105 : FDCE_1
-# name ID w/b ins outs
-FDCE_1 1105 1 5 1
-#C CE CLR D $abc9_currQ
-#0 109 764 -46 0
-0 109 764 0 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1106 : FDPE
-# name ID w/b ins outs
-FDPE 1106 1 5 1
-#C CE D PRE $abc9_currQ
-#0 109 -46 764 0
-0 109 0 764 0 # Q (-46ps Tsu clamped to 0)
-
-# Box 1107 : FDPE_1
-# name ID w/b ins outs
-FDPE_1 1107 1 5 1
-#C CE D PRE $abc9_currQ
-#0 109 -46 764 0
-0 109 0 764 0 # Q (-46ps Tsu clamped to 0)
-
# Box 2000 : $__ABC9_LUT6
# (private cell to emulate async behaviour of LUTRAMs)
# SLICEM/A6LUT
diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v
index 5c848d4e6..2b8b0dcc1 100644
--- a/techlibs/xilinx/arith_map.v
+++ b/techlibs/xilinx/arith_map.v
@@ -33,72 +33,13 @@ module _80_xilinx_lcu (P, G, CI, CO);
genvar i;
-`ifdef _CLB_CARRY
-
- localparam CARRY4_COUNT = (WIDTH + 3) / 4;
- localparam MAX_WIDTH = CARRY4_COUNT * 4;
- localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
-
- wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
- wire [MAX_WIDTH-1:0] C = CO;
-
- generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
-
- // Partially occupied CARRY4
- if ((i+1)*4 > WIDTH) begin
-
- // First one
- if (i == 0) begin
- CARRY4 carry4_1st_part
- (
- .CYINIT(CI),
- .CI (1'd0),
- .DI (G [(Y_WIDTH - 1):i*4]),
- .S (S [(Y_WIDTH - 1):i*4]),
- .CO (CO[(Y_WIDTH - 1):i*4]),
- );
- // Another one
- end else begin
- CARRY4 carry4_part
- (
- .CYINIT(1'd0),
- .CI (C [i*4 - 1]),
- .DI (G [(Y_WIDTH - 1):i*4]),
- .S (S [(Y_WIDTH - 1):i*4]),
- .CO (CO[(Y_WIDTH - 1):i*4]),
- );
- end
-
- // Fully occupied CARRY4
- end else begin
-
- // First one
- if (i == 0) begin
- CARRY4 carry4_1st_full
- (
- .CYINIT(CI),
- .CI (1'd0),
- .DI (G [((i+1)*4 - 1):i*4]),
- .S (S [((i+1)*4 - 1):i*4]),
- .CO (CO[((i+1)*4 - 1):i*4]),
- );
- // Another one
- end else begin
- CARRY4 carry4_full
- (
- .CYINIT(1'd0),
- .CI (C [i*4 - 1]),
- .DI (G [((i+1)*4 - 1):i*4]),
- .S (S [((i+1)*4 - 1):i*4]),
- .CO (CO[((i+1)*4 - 1):i*4]),
- );
- end
-
- end
-
- end endgenerate
+`ifdef _EXPLICIT_CARRY
+ localparam EXPLICIT_CARRY = 1'b1;
+`else
+ localparam EXPLICIT_CARRY = 1'b0;
+`endif
-`elsif _EXPLICIT_CARRY
+generate if (EXPLICIT_CARRY || `LUT_SIZE == 4) begin
wire [WIDTH-1:0] C = {CO, CI};
wire [WIDTH-1:0] S = P & ~G;
@@ -112,20 +53,39 @@ module _80_xilinx_lcu (P, G, CI, CO);
);
end endgenerate
-`else
+end else begin
- wire [WIDTH-1:0] C = {CO, CI};
- wire [WIDTH-1:0] S = P & ~G;
+ localparam CARRY4_COUNT = (WIDTH + 3) / 4;
+ localparam MAX_WIDTH = CARRY4_COUNT * 4;
+ localparam PAD_WIDTH = MAX_WIDTH - WIDTH;
- generate for (i = 0; i < WIDTH; i = i + 1) begin:slice
- MUXCY muxcy (
- .CI(C[i]),
- .DI(G[i]),
- .S(S[i]),
- .O(CO[i])
- );
+ wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G};
+ wire [MAX_WIDTH-1:0] GG = {{PAD_WIDTH{1'b0}}, G};
+ wire [MAX_WIDTH-1:0] C;
+ assign CO = C;
+
+ generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
+ if (i == 0) begin
+ CARRY4 carry4
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (GG[i*4 +: 4]),
+ .S (S [i*4 +: 4]),
+ .CO (C [i*4 +: 4]),
+ );
+ end else begin
+ CARRY4 carry4
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (GG[i*4 +: 4]),
+ .S (S [i*4 +: 4]),
+ .CO (C [i*4 +: 4]),
+ );
+ end
end endgenerate
-`endif
+end endgenerate
endmodule
@@ -161,82 +121,35 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
genvar i;
-`ifdef _CLB_CARRY
-
- localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
- localparam MAX_WIDTH = CARRY4_COUNT * 4;
- localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
+`ifdef _EXPLICIT_CARRY
+ localparam EXPLICIT_CARRY = 1'b1;
+`else
+ localparam EXPLICIT_CARRY = 1'b0;
+`endif
- wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
- wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB};
+generate if (`LUT_SIZE == 4) begin
- wire [MAX_WIDTH-1:0] C = CO;
+ wire [Y_WIDTH-1:0] C = {CO, CI};
+ wire [Y_WIDTH-1:0] S = {AA ^ BB};
genvar i;
- generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
-
- // Partially occupied CARRY4
- if ((i+1)*4 > Y_WIDTH) begin
-
- // First one
- if (i == 0) begin
- CARRY4 carry4_1st_part
- (
- .CYINIT(CI),
- .CI (1'd0),
- .DI (DI[(Y_WIDTH - 1):i*4]),
- .S (S [(Y_WIDTH - 1):i*4]),
- .O (Y [(Y_WIDTH - 1):i*4]),
- .CO (CO[(Y_WIDTH - 1):i*4])
- );
- // Another one
- end else begin
- CARRY4 carry4_part
- (
- .CYINIT(1'd0),
- .CI (C [i*4 - 1]),
- .DI (DI[(Y_WIDTH - 1):i*4]),
- .S (S [(Y_WIDTH - 1):i*4]),
- .O (Y [(Y_WIDTH - 1):i*4]),
- .CO (CO[(Y_WIDTH - 1):i*4])
- );
- end
-
- // Fully occupied CARRY4
- end else begin
-
- // First one
- if (i == 0) begin
- CARRY4 carry4_1st_full
- (
- .CYINIT(CI),
- .CI (1'd0),
- .DI (DI[((i+1)*4 - 1):i*4]),
- .S (S [((i+1)*4 - 1):i*4]),
- .O (Y [((i+1)*4 - 1):i*4]),
- .CO (CO[((i+1)*4 - 1):i*4])
- );
- // Another one
- end else begin
- CARRY4 carry4_full
- (
- .CYINIT(1'd0),
- .CI (C [i*4 - 1]),
- .DI (DI[((i+1)*4 - 1):i*4]),
- .S (S [((i+1)*4 - 1):i*4]),
- .O (Y [((i+1)*4 - 1):i*4]),
- .CO (CO[((i+1)*4 - 1):i*4])
- );
- end
-
- end
-
+ generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
+ MUXCY muxcy (
+ .CI(C[i]),
+ .DI(AA[i]),
+ .S(S[i]),
+ .O(CO[i])
+ );
+ XORCY xorcy (
+ .CI(C[i]),
+ .LI(S[i]),
+ .O(Y[i])
+ );
end endgenerate
-`elsif _EXPLICIT_CARRY
+end else if (EXPLICIT_CARRY) begin
wire [Y_WIDTH-1:0] S = AA ^ BB;
- wire [Y_WIDTH-1:0] DI = AA & BB;
wire CINIT;
// Carry chain.
@@ -256,7 +169,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
generate for (i = 0; i < 1; i = i + 1) begin:slice
CARRY0 #(.CYINIT_FABRIC(1)) carry(
.CI_INIT(CI),
- .DI(DI[0]),
+ .DI(AA[0]),
.S(S[0]),
.CO_CHAIN(CO_CHAIN[0]),
.CO_FABRIC(CO[0]),
@@ -268,7 +181,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
if(i % 4 == 0) begin
CARRY0 carry (
.CI(C[i]),
- .DI(DI[i]),
+ .DI(AA[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.CO_FABRIC(CO[i]),
@@ -279,7 +192,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
begin
CARRY carry (
.CI(C[i]),
- .DI(DI[i]),
+ .DI(AA[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.CO_FABRIC(CO[i]),
@@ -292,7 +205,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
if(i % 4 == 0) begin
CARRY0 top_of_carry (
.CI(C[i]),
- .DI(DI[i]),
+ .DI(AA[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.O(Y[i])
@@ -302,7 +215,7 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
begin
CARRY top_of_carry (
.CI(C[i]),
- .DI(DI[i]),
+ .DI(AA[i]),
.S(S[i]),
.CO_CHAIN(CO_CHAIN[i]),
.O(Y[i])
@@ -331,28 +244,45 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO);
end
end endgenerate
-`else
+end else begin
- wire [Y_WIDTH-1:0] S = AA ^ BB;
- wire [Y_WIDTH-1:0] DI = AA & BB;
+ localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4;
+ localparam MAX_WIDTH = CARRY4_COUNT * 4;
+ localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH;
- wire [Y_WIDTH-1:0] C = {CO, CI};
+ wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB};
+ wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA};
- generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice
- MUXCY muxcy (
- .CI(C[i]),
- .DI(DI[i]),
- .S(S[i]),
- .O(CO[i])
- );
- XORCY xorcy (
- .CI(C[i]),
- .LI(S[i]),
- .O(Y[i])
- );
+ wire [MAX_WIDTH-1:0] O;
+ wire [MAX_WIDTH-1:0] C;
+ assign Y = O, CO = C;
+
+ genvar i;
+ generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice
+ if (i == 0) begin
+ CARRY4 carry4
+ (
+ .CYINIT(CI),
+ .CI (1'd0),
+ .DI (DI[i*4 +: 4]),
+ .S (S [i*4 +: 4]),
+ .O (O [i*4 +: 4]),
+ .CO (C [i*4 +: 4])
+ );
+ end else begin
+ CARRY4 carry4
+ (
+ .CYINIT(1'd0),
+ .CI (C [i*4 - 1]),
+ .DI (DI[i*4 +: 4]),
+ .S (S [i*4 +: 4]),
+ .O (O [i*4 +: 4]),
+ .CO (C [i*4 +: 4])
+ );
+ end
end endgenerate
-`endif
+end endgenerate
assign X = S;
endmodule
diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v
index 22dca3c47..4692eba33 100644
--- a/techlibs/xilinx/cells_sim.v
+++ b/techlibs/xilinx/cells_sim.v
@@ -325,17 +325,20 @@ endmodule
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250
-(* abc9_box_id=1100, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDRE (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
+ (* abc9_required=109 *)
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
+ //(* abc9_required=-46 *) // Negative required times not currently supported
input D,
(* invertible_pin = "IS_R_INVERTED" *)
+ (* abc9_required=404 *)
input R
);
parameter [0:0] INIT = 1'b0;
@@ -349,30 +352,38 @@ module FDRE (
endcase endgenerate
endmodule
-(* abc9_box_id=1101, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDRE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
- input CE, D, R
+ (* abc9_required=109 *)
+ input CE,
+ //(* abc9_required=-46 *) // Negative required times not currently supported
+ input D,
+ (* abc9_required=404 *)
+ input R
);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C) if (R) Q <= 1'b0; else if (CE) Q <= D;
endmodule
-(* abc9_box_id=1102, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDSE (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
+ (* abc9_required=109 *)
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
+ //(* abc9_required=-46 *) // Negative required times not currently supported
input D,
(* invertible_pin = "IS_S_INVERTED" *)
+ (* abc9_required=404 *)
input S
);
parameter [0:0] INIT = 1'b1;
@@ -386,13 +397,18 @@ module FDSE (
endcase endgenerate
endmodule
-(* abc9_box_id=1103, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDSE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
- input CE, D, S
+ (* abc9_required=109 *)
+ input CE,
+ //(* abc9_required=-46 *) // Negative required times not currently supported
+ input D,
+ (* abc9_required=404 *)
+ input S
);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
@@ -405,6 +421,7 @@ module FDRSE (
(* invertible_pin = "IS_C_INVERTED" *)
input C,
(* invertible_pin = "IS_CE_INVERTED" *)
+ (* abc9_required=109 *)
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
input D,
@@ -434,17 +451,20 @@ module FDRSE (
Q <= d;
endmodule
-(* abc9_box_id=1104, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDCE (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
+ (* abc9_required=109 *)
input CE,
(* invertible_pin = "IS_CLR_INVERTED" *)
+ (* abc9_required=764 *)
input CLR,
(* invertible_pin = "IS_D_INVERTED" *)
+ //(* abc9_required=-46 *) // Negative required times not currently supported
input D
);
parameter [0:0] INIT = 1'b0;
@@ -460,30 +480,38 @@ module FDCE (
endcase endgenerate
endmodule
-(* abc9_box_id=1105, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDCE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
- input CE, D, CLR
+ (* abc9_required=109 *)
+ input CE,
+ (* abc9_required=764 *)
+ input CLR,
+ //(* abc9_required=-46 *) // Negative required times not currently supported
+ input D
);
parameter [0:0] INIT = 1'b0;
initial Q <= INIT;
always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D;
endmodule
-(* abc9_box_id=1106, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDPE (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
(* invertible_pin = "IS_C_INVERTED" *)
input C,
+ (* abc9_required=109 *)
input CE,
(* invertible_pin = "IS_D_INVERTED" *)
+ //(* abc9_required=-46 *) // Negative required times not currently supported
input D,
(* invertible_pin = "IS_PRE_INVERTED" *)
+ (* abc9_required=764 *)
input PRE
);
parameter [0:0] INIT = 1'b1;
@@ -499,13 +527,18 @@ module FDPE (
endcase endgenerate
endmodule
-(* abc9_box_id=1107, lib_whitebox, abc9_flop *)
+(* abc9_flop, lib_whitebox *)
module FDPE_1 (
(* abc9_arrival=303 *)
output reg Q,
(* clkbuf_sink *)
input C,
- input CE, D, PRE
+ (* abc9_required=109 *)
+ input CE,
+ //(* abc9_required=-46 *) // Negative required times not currently supported
+ input D,
+ (* abc9_required=764 *)
+ input PRE
);
parameter [0:0] INIT = 1'b1;
initial Q <= INIT;
@@ -1120,15 +1153,33 @@ module RAM16X1D_1 (
endmodule
module RAM32X1D (
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
- (* abc9_arrival=1188 *)
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+ (* abc9_arrival=1153 *)
output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+ (* abc9_required=453 *)
input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
input WE,
- input A0, A1, A2, A3, A4,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
+ (* abc9_required=245 *)
+ input A0,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
+ (* abc9_required=208 *)
+ input A1,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
+ (* abc9_required=147 *)
+ input A2,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
+ (* abc9_required=68 *)
+ input A3,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
+ (* abc9_required=66 *)
+ input A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
parameter INIT = 32'h0;
@@ -1143,15 +1194,33 @@ module RAM32X1D (
endmodule
module RAM32X1D_1 (
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
- (* abc9_arrival=1188 *)
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+ (* abc9_arrival=1153 *)
output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+ (* abc9_required=453 *)
input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
input WE,
- input A0, A1, A2, A3, A4,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L800
+ (* abc9_required=245 *)
+ input A0,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/clBLM_R.sdf#L798
+ (* abc9_required=208 *)
+ input A1,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L796
+ (* abc9_required=147 *)
+ input A2,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L794
+ (* abc9_required=68 *)
+ input A3,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792
+ (* abc9_required=66 *)
+ input A4,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4
);
parameter INIT = 32'h0;
@@ -1166,15 +1235,36 @@ module RAM32X1D_1 (
endmodule
module RAM64X1D (
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
(* abc9_arrival=1153 *)
output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+ (* abc9_required=453 *)
input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
input WE,
- input A0, A1, A2, A3, A4, A5,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
+ (* abc9_required=362 *)
+ input A0,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
+ (* abc9_required=245 *)
+ input A1,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
+ (* abc9_required=208 *)
+ input A2,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
+ (* abc9_required=147 *)
+ input A3,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
+ (* abc9_required=68 *)
+ input A4,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
+ (* abc9_required=66 *)
+ input A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
parameter INIT = 64'h0;
@@ -1189,15 +1279,36 @@ module RAM64X1D (
endmodule
module RAM64X1D_1 (
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
(* abc9_arrival=1153 *)
output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+ (* abc9_required=453 *)
input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
input WE,
- input A0, A1, A2, A3, A4, A5,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L828
+ (* abc9_required=362 *)
+ input A0,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L826
+ (* abc9_required=245 *)
+ input A1,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L824
+ (* abc9_required=208 *)
+ input A2,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L822
+ (* abc9_required=147 *)
+ input A3,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L820
+ (* abc9_required=68 *)
+ input A4,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818
+ (* abc9_required=66 *)
+ input A5,
input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5
);
parameter INIT = 64'h0;
@@ -1212,16 +1323,23 @@ module RAM64X1D_1 (
endmodule
module RAM128X1D (
- // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
- // plus 204ps to cross MUXF7
- (* abc9_arrival=1357 *)
- output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L981
+ // plus 208ps to cross MUXF7
+ (* abc9_arrival=1359 *)
+ output DPO, SPO,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986
+ (* abc9_required=453 *)
input D,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
input WE,
- input [6:0] A, DPRA
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-830
+ (* abc9_required="616 362 245 208 147 68 66" *)
+ input [6:0] A,
+ input [6:0] DPRA
);
parameter INIT = 128'h0;
parameter IS_WCLK_INVERTED = 1'b0;
@@ -1253,24 +1371,44 @@ endmodule
// Multi port.
module RAM32M (
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857
- (* abc9_arrival=1188 *)
+ (* abc9_arrival="1153 1188" *)
output [1:0] DOA,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925
- (* abc9_arrival=1187 *)
+ (* abc9_arrival="1161 1187" *)
output [1:0] DOB,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993
- (* abc9_arrival=1180 *)
+ (* abc9_arrival="1158 1180" *)
output [1:0] DOC,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061
- (* abc9_arrival=1190 *)
+ (* abc9_arrival="1163 1190" *)
output [1:0] DOD,
- input [4:0] ADDRA, ADDRB, ADDRC, ADDRD,
- input [1:0] DIA, DIB, DIC, DID,
+ input [4:0] ADDRA, ADDRB, ADDRC,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L792-L802
+ (* abc9_required="245 208 147 68 66" *)
+ input [4:0] ADDRD,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+ (* abc9_required="453 384" *)
+ input [1:0] DIA,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+ (* abc9_required="461 354" *)
+ input [1:0] DIB,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+ (* abc9_required="457 375" *)
+ input [1:0] DIC,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+ (* abc9_required="310 334" *)
+ input [1:0] DID,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
- input WCLK,
- input WE
+ input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
+ input WE
);
parameter [63:0] INIT_A = 64'h0000000000000000;
parameter [63:0] INIT_B = 64'h0000000000000000;
@@ -1367,22 +1505,38 @@ endmodule
module RAM64M (
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L889
(* abc9_arrival=1153 *)
- output DOA,
+ output DOA,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957
(* abc9_arrival=1161 *)
- output DOB,
+ output DOB,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025
(* abc9_arrival=1158 *)
- output DOC,
+ output DOC,
// Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1093
(* abc9_arrival=1163 *)
- output DOD,
- input [5:0] ADDRA, ADDRB, ADDRC, ADDRD,
- input DIA, DIB, DIC, DID,
+ output DOD,
+ input [5:0] ADDRA, ADDRB, ADDRC,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L818-L830
+ (* abc9_required="362 245 208 147 68 66" *)
+ input [5:0] ADDRD,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L986-L988
+ (* abc9_required=384 *)
+ input DIA,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1054-L1056
+ (* abc9_required=354 *)
+ input DIB,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1122-L1124
+ (* abc9_required=375 *)
+ input DIC,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L1190-L1192
+ (* abc9_required=310 *)
+ input DID,
(* clkbuf_sink *)
(* invertible_pin = "IS_WCLK_INVERTED" *)
- input WCLK,
- input WE
+ input WCLK,
+ // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/31f51ac5ec7448dd6f79a8267f147123e4413c21/artix7/timings/CLBLM_R.sdf#L834
+ (* abc9_required=654 *)
+ input WE
);
parameter [63:0] INIT_A = 64'h0000000000000000;
parameter [63:0] INIT_B = 64'h0000000000000000;
@@ -2155,7 +2309,235 @@ assign PCOUT = P;
endmodule
-// TODO: DSP48 (Virtex 4).
+module DSP48 (
+ input signed [17:0] A,
+ input signed [17:0] B,
+ input signed [47:0] C,
+ input signed [17:0] BCIN,
+ input signed [47:0] PCIN,
+ input CARRYIN,
+ input [6:0] OPMODE,
+ input SUBTRACT,
+ input [1:0] CARRYINSEL,
+ output signed [47:0] P,
+ output signed [17:0] BCOUT,
+ output signed [47:0] PCOUT,
+ (* clkbuf_sink *)
+ input CLK,
+ input CEA,
+ input CEB,
+ input CEC,
+ input CEM,
+ input CECARRYIN,
+ input CECINSUB,
+ input CECTRL,
+ input CEP,
+ input RSTA,
+ input RSTB,
+ input RSTC,
+ input RSTM,
+ input RSTCARRYIN,
+ input RSTCTRL,
+ input RSTP
+);
+
+parameter integer AREG = 1;
+parameter integer BREG = 1;
+parameter integer CREG = 1;
+parameter integer MREG = 1;
+parameter integer PREG = 1;
+parameter integer CARRYINREG = 1;
+parameter integer CARRYINSELREG = 1;
+parameter integer OPMODEREG = 1;
+parameter integer SUBTRACTREG = 1;
+parameter B_INPUT = "DIRECT";
+parameter LEGACY_MODE = "MULT18X18S";
+
+wire signed [17:0] A_OUT;
+wire signed [17:0] B_OUT;
+wire signed [47:0] C_OUT;
+wire signed [35:0] M_MULT;
+wire signed [35:0] M_OUT;
+wire signed [47:0] P_IN;
+wire [6:0] OPMODE_OUT;
+wire [1:0] CARRYINSEL_OUT;
+wire CARRYIN_OUT;
+wire SUBTRACT_OUT;
+reg INT_CARRYIN_XY;
+reg INT_CARRYIN_Z;
+reg signed [47:0] XMUX;
+reg signed [47:0] YMUX;
+wire signed [47:0] XYMUX;
+reg signed [47:0] ZMUX;
+reg CIN;
+
+// The B input multiplexer.
+wire signed [17:0] B_MUX;
+assign B_MUX = (B_INPUT == "DIRECT") ? B : BCIN;
+
+// The cascade output.
+assign BCOUT = B_OUT;
+assign PCOUT = P;
+
+// The registers.
+reg signed [17:0] A0_REG;
+reg signed [17:0] A1_REG;
+reg signed [17:0] B0_REG;
+reg signed [17:0] B1_REG;
+reg signed [47:0] C_REG;
+reg signed [35:0] M_REG;
+reg signed [47:0] P_REG;
+reg [6:0] OPMODE_REG;
+reg [1:0] CARRYINSEL_REG;
+reg SUBTRACT_REG;
+reg CARRYIN_REG;
+reg INT_CARRYIN_XY_REG;
+
+initial begin
+ A0_REG = 0;
+ A1_REG = 0;
+ B0_REG = 0;
+ B1_REG = 0;
+ C_REG = 0;
+ M_REG = 0;
+ P_REG = 0;
+ OPMODE_REG = 0;
+ CARRYINSEL_REG = 0;
+ SUBTRACT_REG = 0;
+ CARRYIN_REG = 0;
+ INT_CARRYIN_XY_REG = 0;
+end
+
+always @(posedge CLK) begin
+ if (RSTA) begin
+ A0_REG <= 0;
+ A1_REG <= 0;
+ end else if (CEA) begin
+ A0_REG <= A;
+ A1_REG <= A0_REG;
+ end
+ if (RSTB) begin
+ B0_REG <= 0;
+ B1_REG <= 0;
+ end else if (CEB) begin
+ B0_REG <= B_MUX;
+ B1_REG <= B0_REG;
+ end
+ if (RSTC) begin
+ C_REG <= 0;
+ end else if (CEC) begin
+ C_REG <= C;
+ end
+ if (RSTM) begin
+ M_REG <= 0;
+ end else if (CEM) begin
+ M_REG <= M_MULT;
+ end
+ if (RSTP) begin
+ P_REG <= 0;
+ end else if (CEP) begin
+ P_REG <= P_IN;
+ end
+ if (RSTCTRL) begin
+ OPMODE_REG <= 0;
+ CARRYINSEL_REG <= 0;
+ SUBTRACT_REG <= 0;
+ end else begin
+ if (CECTRL) begin
+ OPMODE_REG <= OPMODE;
+ CARRYINSEL_REG <= CARRYINSEL;
+ end
+ if (CECINSUB)
+ SUBTRACT_REG <= SUBTRACT;
+ end
+ if (RSTCARRYIN) begin
+ CARRYIN_REG <= 0;
+ INT_CARRYIN_XY_REG <= 0;
+ end else begin
+ if (CECINSUB)
+ CARRYIN_REG <= CARRYIN;
+ if (CECARRYIN)
+ INT_CARRYIN_XY_REG <= INT_CARRYIN_XY;
+ end
+end
+
+// The register enables.
+assign A_OUT = (AREG == 2) ? A1_REG : (AREG == 1) ? A0_REG : A;
+assign B_OUT = (BREG == 2) ? B1_REG : (BREG == 1) ? B0_REG : B_MUX;
+assign C_OUT = (CREG == 1) ? C_REG : C;
+assign M_OUT = (MREG == 1) ? M_REG : M_MULT;
+assign P = (PREG == 1) ? P_REG : P_IN;
+assign OPMODE_OUT = (OPMODEREG == 1) ? OPMODE_REG : OPMODE;
+assign SUBTRACT_OUT = (SUBTRACTREG == 1) ? SUBTRACT_REG : SUBTRACT;
+assign CARRYINSEL_OUT = (CARRYINSELREG == 1) ? CARRYINSEL_REG : CARRYINSEL;
+assign CARRYIN_OUT = (CARRYINREG == 1) ? CARRYIN_REG : CARRYIN;
+
+// The multiplier.
+assign M_MULT = A_OUT * B_OUT;
+
+// The post-adder inputs.
+always @* begin
+ case (OPMODE_OUT[1:0])
+ 2'b00: XMUX <= 0;
+ 2'b10: XMUX <= P;
+ 2'b11: XMUX <= {{12{A_OUT[17]}}, A_OUT, B_OUT};
+ default: XMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+ case (OPMODE_OUT[1:0])
+ 2'b01: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
+ 2'b11: INT_CARRYIN_XY <= ~A_OUT[17];
+ // TODO: not tested in hardware.
+ default: INT_CARRYIN_XY <= A_OUT[17] ~^ B_OUT[17];
+ endcase
+end
+
+always @* begin
+ case (OPMODE_OUT[3:2])
+ 2'b00: YMUX <= 0;
+ 2'b11: YMUX <= C_OUT;
+ default: YMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+end
+
+assign XYMUX = (OPMODE_OUT[3:0] == 4'b0101) ? M_OUT : (XMUX + YMUX);
+
+always @* begin
+ case (OPMODE_OUT[6:4])
+ 3'b000: ZMUX <= 0;
+ 3'b001: ZMUX <= PCIN;
+ 3'b010: ZMUX <= P;
+ 3'b011: ZMUX <= C_OUT;
+ 3'b101: ZMUX <= {{17{PCIN[47]}}, PCIN[47:17]};
+ 3'b110: ZMUX <= {{17{P[47]}}, P[47:17]};
+ default: ZMUX <= 48'hxxxxxxxxxxxx;
+ endcase
+ // TODO: check how all this works on actual hw.
+ if (OPMODE_OUT[1:0] == 2'b10)
+ INT_CARRYIN_Z <= ~P[47];
+ else
+ case (OPMODE_OUT[6:4])
+ 3'b001: INT_CARRYIN_Z <= ~PCIN[47];
+ 3'b010: INT_CARRYIN_Z <= ~P[47];
+ 3'b101: INT_CARRYIN_Z <= ~PCIN[47];
+ 3'b110: INT_CARRYIN_Z <= ~P[47];
+ default: INT_CARRYIN_Z <= 1'bx;
+ endcase
+end
+
+always @* begin
+ case (CARRYINSEL_OUT)
+ 2'b00: CIN <= CARRYIN_OUT;
+ 2'b01: CIN <= INT_CARRYIN_Z;
+ 2'b10: CIN <= INT_CARRYIN_XY;
+ 2'b11: CIN <= INT_CARRYIN_XY_REG;
+ default: CIN <= 1'bx;
+ endcase
+end
+
+// The post-adder.
+assign P_IN = SUBTRACT_OUT ? (ZMUX - (XYMUX + CIN)) : (ZMUX + XYMUX + CIN);
+
+endmodule
// TODO: DSP48E (Virtex 5).
@@ -2169,21 +2551,30 @@ module DSP48E1 (
output reg MULTSIGNOUT,
output OVERFLOW,
`ifdef YOSYS
- (* abc9_arrival = \DSP48E1.P_arrival () *)
+ (* abc9_arrival = \P.abc9_arrival () *)
`endif
output reg signed [47:0] P,
output reg PATTERNBDETECT,
output reg PATTERNDETECT,
`ifdef YOSYS
- (* abc9_arrival = \DSP48E1.PCOUT_arrival () *)
+ (* abc9_arrival = \PCOUT.abc9_arrival () *)
`endif
output [47:0] PCOUT,
output UNDERFLOW,
+`ifdef YOSYS
+ (* abc9_required = \A.abc9_required () *)
+`endif
input signed [29:0] A,
input [29:0] ACIN,
input [3:0] ALUMODE,
+`ifdef YOSYS
+ (* abc9_required = \B.abc9_required () *)
+`endif
input signed [17:0] B,
input [17:0] BCIN,
+`ifdef YOSYS
+ (* abc9_required = \C.abc9_required () *)
+`endif
input [47:0] C,
input CARRYCASCIN,
input CARRYIN,
@@ -2202,10 +2593,16 @@ module DSP48E1 (
input CEM,
input CEP,
(* clkbuf_sink *) input CLK,
+`ifdef YOSYS
+ (* abc9_required = \D.abc9_required () *)
+`endif
input [24:0] D,
input [4:0] INMODE,
input MULTSIGNIN,
input [6:0] OPMODE,
+`ifdef YOSYS
+ (* abc9_required = \PCIN.abc9_required () *)
+`endif
input [47:0] PCIN,
input RSTA,
input RSTALLCARRYIN,
@@ -2250,69 +2647,133 @@ module DSP48E1 (
parameter [6:0] IS_OPMODE_INVERTED = 7'b0;
`ifdef YOSYS
- function integer \DSP48E1.P_arrival ;
+ function integer \A.abc9_required ;
+ begin
+ \A.abc9_required = 0;
+ if (AREG != 0) \A.abc9_required = 254;
+ else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
+ if (MREG != 0) \A.abc9_required = 1416;
+ else if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3030 : 2739) ;
+ end
+ else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
+ // Worst-case from ADREG and MREG
+ if (MREG != 0) \A.abc9_required = 2400;
+ else if (ADREG != 0) \A.abc9_required = 1283;
+ else if (PREG != 0) \A.abc9_required = 3723;
+ else if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 4014 : 3723) ;
+ end
+ else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
+ if (PREG != 0) \A.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1730 : 1441) ;
+ end
+ end
+ endfunction
+ function integer \B.abc9_required ;
+ begin
+ \B.abc9_required = 0;
+ if (BREG != 0) \B.abc9_required = 324;
+ else if (MREG != 0) \B.abc9_required = 1285;
+ else if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
+ if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ;
+ end
+ else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
+ if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 2898 : 2608) ;
+ end
+ else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
+ if (PREG != 0) \B.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1718 : 1428) ;
+ end
+ end
+ endfunction
+ function integer \C.abc9_required ;
+ begin
+ \C.abc9_required = 0;
+ if (CREG != 0) \C.abc9_required = 168;
+ else if (PREG != 0) \C.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1534 : 1244) ;
+ end
+ endfunction
+ function integer \D.abc9_required ;
+ begin
+ \D.abc9_required = 0;
+ if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
+ end
+ else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
+ if (DREG != 0) \D.abc9_required = 248;
+ else if (ADREG != 0) \D.abc9_required = 1195;
+ else if (MREG != 0) \D.abc9_required = 2310;
+ else if (PREG != 0) \D.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 3925 : 3635) ;
+ end
+ else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
+ end
+ end
+ endfunction
+ function integer \PCIN.abc9_required ;
+ begin
+ \PCIN.abc9_required = 0;
+ if (PREG != 0) \PCIN.abc9_required = (USE_PATTERN_DETECT != "NO_PATDET" ? 1315 : 1025) ;
+ end
+ endfunction
+ function integer \P.abc9_arrival ;
begin
- \DSP48E1.P_arrival = 0;
+ \P.abc9_arrival = 0;
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
- if (PREG != 0) \DSP48E1.P_arrival = 329;
+ if (PREG != 0) \P.abc9_arrival = 329;
// Worst-case from CREG and MREG
- else if (CREG != 0) \DSP48E1.P_arrival = 1687;
- else if (MREG != 0) \DSP48E1.P_arrival = 1671;
+ else if (CREG != 0) \P.abc9_arrival = 1687;
+ else if (MREG != 0) \P.abc9_arrival = 1671;
// Worst-case from AREG and BREG
- else if (AREG != 0) \DSP48E1.P_arrival = 2952;
- else if (BREG != 0) \DSP48E1.P_arrival = 2813;
+ else if (AREG != 0) \P.abc9_arrival = 2952;
+ else if (BREG != 0) \P.abc9_arrival = 2813;
end
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
- if (PREG != 0) \DSP48E1.P_arrival = 329;
+ if (PREG != 0) \P.abc9_arrival = 329;
// Worst-case from CREG and MREG
- else if (CREG != 0) \DSP48E1.P_arrival = 1687;
- else if (MREG != 0) \DSP48E1.P_arrival = 1671;
+ else if (CREG != 0) \P.abc9_arrival = 1687;
+ else if (MREG != 0) \P.abc9_arrival = 1671;
// Worst-case from AREG, ADREG, BREG, DREG
- else if (AREG != 0) \DSP48E1.P_arrival = 3935;
- else if (DREG != 0) \DSP48E1.P_arrival = 3908;
- else if (ADREG != 0) \DSP48E1.P_arrival = 2958;
- else if (BREG != 0) \DSP48E1.P_arrival = 2813;
+ else if (AREG != 0) \P.abc9_arrival = 3935;
+ else if (DREG != 0) \P.abc9_arrival = 3908;
+ else if (ADREG != 0) \P.abc9_arrival = 2958;
+ else if (BREG != 0) \P.abc9_arrival = 2813;
end
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
- if (PREG != 0) \DSP48E1.P_arrival = 329;
+ if (PREG != 0) \P.abc9_arrival = 329;
// Worst-case from AREG, BREG, CREG
- else if (CREG != 0) \DSP48E1.P_arrival = 1687;
- else if (AREG != 0) \DSP48E1.P_arrival = 1632;
- else if (BREG != 0) \DSP48E1.P_arrival = 1616;
+ else if (CREG != 0) \P.abc9_arrival = 1687;
+ else if (AREG != 0) \P.abc9_arrival = 1632;
+ else if (BREG != 0) \P.abc9_arrival = 1616;
end
//else
// $error("Invalid DSP48E1 configuration");
end
endfunction
- function integer \DSP48E1.PCOUT_arrival ;
+ function integer \PCOUT.abc9_arrival ;
begin
- \DSP48E1.PCOUT_arrival = 0;
+ \PCOUT.abc9_arrival = 0;
if (USE_MULT == "MULTIPLY" && USE_DPORT == "FALSE") begin
- if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
+ if (PREG != 0) \PCOUT.abc9_arrival = 435;
// Worst-case from CREG and MREG
- else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
- else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819;
+ else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
+ else if (MREG != 0) \PCOUT.abc9_arrival = 1819;
// Worst-case from AREG and BREG
- else if (AREG != 0) \DSP48E1.PCOUT_arrival = 3098;
- else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960;
+ else if (AREG != 0) \PCOUT.abc9_arrival = 3098;
+ else if (BREG != 0) \PCOUT.abc9_arrival = 2960;
end
else if (USE_MULT == "MULTIPLY" && USE_DPORT == "TRUE") begin
- if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
+ if (PREG != 0) \PCOUT.abc9_arrival = 435;
// Worst-case from CREG and MREG
- else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
- else if (MREG != 0) \DSP48E1.PCOUT_arrival = 1819;
+ else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
+ else if (MREG != 0) \PCOUT.abc9_arrival = 1819;
// Worst-case from AREG, ADREG, BREG, DREG
- else if (AREG != 0) \DSP48E1.PCOUT_arrival = 4083;
- else if (DREG != 0) \DSP48E1.PCOUT_arrival = 4056;
- else if (BREG != 0) \DSP48E1.PCOUT_arrival = 2960;
- else if (ADREG != 0) \DSP48E1.PCOUT_arrival = 2859;
+ else if (AREG != 0) \PCOUT.abc9_arrival = 4083;
+ else if (DREG != 0) \PCOUT.abc9_arrival = 4056;
+ else if (BREG != 0) \PCOUT.abc9_arrival = 2960;
+ else if (ADREG != 0) \PCOUT.abc9_arrival = 2859;
end
else if (USE_MULT == "NONE" && USE_DPORT == "FALSE") begin
- if (PREG != 0) \DSP48E1.PCOUT_arrival = 435;
+ if (PREG != 0) \PCOUT.abc9_arrival = 435;
// Worst-case from AREG, BREG, CREG
- else if (CREG != 0) \DSP48E1.PCOUT_arrival = 1835;
- else if (AREG != 0) \DSP48E1.PCOUT_arrival = 1780;
- else if (BREG != 0) \DSP48E1.PCOUT_arrival = 1765;
+ else if (CREG != 0) \PCOUT.abc9_arrival = 1835;
+ else if (AREG != 0) \PCOUT.abc9_arrival = 1780;
+ else if (BREG != 0) \PCOUT.abc9_arrival = 1765;
end
//else
// $error("Invalid DSP48E1 configuration");
diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py
index d5c58c5d7..75646f594 100644
--- a/techlibs/xilinx/cells_xtra.py
+++ b/techlibs/xilinx/cells_xtra.py
@@ -180,18 +180,58 @@ CELLS = [
Cell('RAMB18E1', port_attrs={
'CLKARDCLK': ['clkbuf_sink'],
'CLKBWRCLK': ['clkbuf_sink'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143
'DOADO': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163
'DOBDO': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144
'DOPADOP': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164
'DOPBDOP': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13
+ 'ADDRARDADDR': ['abc9_required=566'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17
+ 'ADDRBWRADDR': ['abc9_required=566'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19
+ 'WEA': ['abc9_required=532'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21
+ 'WEBWE': ['abc9_required=532'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123
+ 'DIADI': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133
+ 'DIBDI': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125
+ 'DIPADIP': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135
+ 'DIPBDIP': ['abc9_required=737'],
}),
Cell('RAMB36E1', port_attrs={
'CLKARDCLK': ['clkbuf_sink'],
'CLKBWRCLK': ['clkbuf_sink'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L143
'DOADO': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L163
'DOBDO': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L144
'DOPADOP': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L164
'DOPBDOP': ['abc9_arrival=2454'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L13
+ 'ADDRARDADDR': ['abc9_required=566'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L17
+ 'ADDRBWRADDR': ['abc9_required=566'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L19
+ 'WEA': ['abc9_required=532'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L21
+ 'WEBWE': ['abc9_required=532'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L123
+ 'DIADI': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L133
+ 'DIBDI': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L125
+ 'DIPADIP': ['abc9_required=737'],
+ # https://github.com/SymbiFlow/prjxray-db/blob/23c8b0851f979f0799318eaca90174413a46b257/artix7/timings/BRAM_L.sdf#L135
+ 'DIPBDIP': ['abc9_required=737'],
}),
# Ultrascale.
Cell('FIFO18E2', port_attrs={'RDCLK': ['clkbuf_sink'], 'WRCLK': ['clkbuf_sink']}),
@@ -209,7 +249,7 @@ CELLS = [
# Cell('MULT18X18SIO', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3E
# Cell('DSP48A', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 3A DSP
# Cell('DSP48A1', port_attrs={'CLK': ['clkbuf_sink']}), # Spartan 6
- Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
+ # Cell('DSP48', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 4
Cell('DSP48E', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 5
#Cell('DSP48E1', port_attrs={'CLK': ['clkbuf_sink']}), # Virtex 6 / Series 7
Cell('DSP48E2', port_attrs={'CLK': ['clkbuf_sink']}), # Ultrascale
diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v
index c3e5c72f9..e87f4ec76 100644
--- a/techlibs/xilinx/cells_xtra.v
+++ b/techlibs/xilinx/cells_xtra.v
@@ -4518,13 +4518,21 @@ module RAMB18E1 (...);
input RSTREGARSTREG;
(* invertible_pin = "IS_RSTREGB_INVERTED" *)
input RSTREGB;
+ (* abc9_required=566 *)
input [13:0] ADDRARDADDR;
+ (* abc9_required=566 *)
input [13:0] ADDRBWRADDR;
+ (* abc9_required=737 *)
input [15:0] DIADI;
+ (* abc9_required=737 *)
input [15:0] DIBDI;
+ (* abc9_required=737 *)
input [1:0] DIPADIP;
+ (* abc9_required=737 *)
input [1:0] DIPBDIP;
+ (* abc9_required=532 *)
input [1:0] WEA;
+ (* abc9_required=532 *)
input [3:0] WEBWE;
endmodule
@@ -4742,13 +4750,21 @@ module RAMB36E1 (...);
input REGCEB;
input INJECTDBITERR;
input INJECTSBITERR;
+ (* abc9_required=566 *)
input [15:0] ADDRARDADDR;
+ (* abc9_required=566 *)
input [15:0] ADDRBWRADDR;
+ (* abc9_required=737 *)
input [31:0] DIADI;
+ (* abc9_required=737 *)
input [31:0] DIBDI;
+ (* abc9_required=737 *)
input [3:0] DIPADIP;
+ (* abc9_required=737 *)
input [3:0] DIPBDIP;
+ (* abc9_required=532 *)
input [3:0] WEA;
+ (* abc9_required=532 *)
input [7:0] WEBWE;
endmodule
@@ -5476,49 +5492,6 @@ module URAM288_BASE (...);
input SLEEP;
endmodule
-module DSP48 (...);
- parameter integer AREG = 1;
- parameter integer BREG = 1;
- parameter B_INPUT = "DIRECT";
- parameter integer CARRYINREG = 1;
- parameter integer CARRYINSELREG = 1;
- parameter integer CREG = 1;
- parameter LEGACY_MODE = "MULT18X18S";
- parameter integer MREG = 1;
- parameter integer OPMODEREG = 1;
- parameter integer PREG = 1;
- parameter integer SUBTRACTREG = 1;
- output [17:0] BCOUT;
- output [47:0] P;
- output [47:0] PCOUT;
- input [17:0] A;
- input [17:0] B;
- input [17:0] BCIN;
- input [47:0] C;
- input CARRYIN;
- input [1:0] CARRYINSEL;
- input CEA;
- input CEB;
- input CEC;
- input CECARRYIN;
- input CECINSUB;
- input CECTRL;
- input CEM;
- input CEP;
- (* clkbuf_sink *)
- input CLK;
- input [6:0] OPMODE;
- input [47:0] PCIN;
- input RSTA;
- input RSTB;
- input RSTC;
- input RSTCARRYIN;
- input RSTCTRL;
- input RSTM;
- input RSTP;
- input SUBTRACT;
-endmodule
-
module DSP48E (...);
parameter SIM_MODE = "SAFE";
parameter integer ACASCREG = 1;
diff --git a/techlibs/xilinx/lut4_lutrams.txt b/techlibs/xilinx/lut4_lutrams.txt
new file mode 100644
index 000000000..2b344a9ee
--- /dev/null
+++ b/techlibs/xilinx/lut4_lutrams.txt
@@ -0,0 +1,19 @@
+bram $__XILINX_RAM16X1D
+ init 1
+ abits 4
+ dbits 1
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 0 1
+ transp 0 0
+ clocks 0 1
+ clkpol 0 2
+endbram
+
+
+match $__XILINX_RAM16X1D
+ min bits 2
+ min wports 1
+ make_outreg
+endmatch
diff --git a/techlibs/xilinx/lutrams.txt b/techlibs/xilinx/lut6_lutrams.txt
index 29f6b05cc..3b3cb81e1 100644
--- a/techlibs/xilinx/lutrams.txt
+++ b/techlibs/xilinx/lut6_lutrams.txt
@@ -1,17 +1,3 @@
-
-bram $__XILINX_RAM16X1D
- init 1
- abits 4
- dbits 1
- groups 2
- ports 1 1
- wrmode 0 1
- enable 0 1
- transp 0 0
- clocks 0 1
- clkpol 0 2
-endbram
-
bram $__XILINX_RAM32X1D
init 1
abits 5
@@ -105,16 +91,6 @@ bram $__XILINX_RAM64X1Q
endbram
-# Disabled for now, pending support for LUT4 arches
-# since on LUT6 arches this occupies same area as
-# a RAM32X1D
-#match $__XILINX_RAM16X1D
-# min bits 2
-# min wports 1
-# make_outreg
-# or_next_if_better
-#endmatch
-
match $__XILINX_RAM32X1D
min bits 3
min wports 1
@@ -153,7 +129,7 @@ endmatch
match $__XILINX_RAM32X2Q
min bits 5
- min rports 3
+ min rports 2
min wports 1
make_outreg
or_next_if_better
@@ -161,7 +137,7 @@ endmatch
match $__XILINX_RAM64X1Q
min bits 5
- min rports 3
+ min rports 2
min wports 1
make_outreg
endmatch
diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v
index 62d501632..ec2e3b234 100644
--- a/techlibs/xilinx/lut_map.v
+++ b/techlibs/xilinx/lut_map.v
@@ -29,90 +29,67 @@ module \$lut (A, Y);
input [WIDTH-1:0] A;
output Y;
- // Need to swap input ordering, and fix init accordingly,
- // to match ABC's expectation of LUT inputs in non-decreasing
- // delay order
- function [WIDTH-1:0] permute_index;
- input [WIDTH-1:0] i;
- integer j;
- begin
- permute_index = 0;
- for (j = 0; j < WIDTH; j = j + 1)
- permute_index[WIDTH-1 - j] = i[j];
- end
- endfunction
-
- function [2**WIDTH-1:0] permute_init;
- input [2**WIDTH-1:0] orig;
- integer i;
- begin
- permute_init = 0;
- for (i = 0; i < 2**WIDTH; i = i + 1)
- permute_init[i] = orig[permute_index(i)];
- end
- endfunction
-
- parameter [2**WIDTH-1:0] P_LUT = permute_init(LUT);
-
generate
if (WIDTH == 1) begin
- if (P_LUT == 2'b01) begin
+ if (LUT == 2'b01) begin
INV _TECHMAP_REPLACE_ (.O(Y), .I(A[0]));
end else begin
- LUT1 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
.I0(A[0]));
end
end else
if (WIDTH == 2) begin
- LUT2 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[1]), .I1(A[0]));
+ LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]));
end else
if (WIDTH == 3) begin
- LUT3 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[2]), .I1(A[1]), .I2(A[0]));
+ LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]));
end else
if (WIDTH == 4) begin
- LUT4 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[3]), .I1(A[2]), .I2(A[1]),
- .I3(A[0]));
+ LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]));
+ end else
+ if (WIDTH == 5 && WIDTH <= `LUT_WIDTH) begin
+ LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]));
end else
- if (WIDTH == 5) begin
- LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[4]), .I1(A[3]), .I2(A[2]),
- .I3(A[1]), .I4(A[0]));
+ if (WIDTH == 6 && WIDTH <= `LUT_WIDTH) begin
+ LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y),
+ .I0(A[0]), .I1(A[1]), .I2(A[2]),
+ .I3(A[3]), .I4(A[4]), .I5(A[5]));
end else
- if (WIDTH == 6) begin
- LUT6 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y),
- .I0(A[5]), .I1(A[4]), .I2(A[3]),
- .I3(A[2]), .I4(A[1]), .I5(A[0]));
+ if (WIDTH == 5 && WIDTH > `LUT_WIDTH) begin
+ wire f0, f1;
+ \$lut #(.LUT(LUT[15: 0]), .WIDTH(4)) lut0 (.A(A[3:0]), .Y(f0));
+ \$lut #(.LUT(LUT[31:16]), .WIDTH(4)) lut1 (.A(A[3:0]), .Y(f1));
+ MUXF5 mux5(.I0(f0), .I1(f1), .S(A[4]), .O(Y));
+ end else
+ if (WIDTH == 6 && WIDTH > `LUT_WIDTH) begin
+ wire f0, f1;
+ \$lut #(.LUT(LUT[31: 0]), .WIDTH(5)) lut0 (.A(A[4:0]), .Y(f0));
+ \$lut #(.LUT(LUT[63:32]), .WIDTH(5)) lut1 (.A(A[4:0]), .Y(f1));
+ MUXF6 mux6(.I0(f0), .I1(f1), .S(A[5]), .O(Y));
end else
if (WIDTH == 7) begin
- wire T0, T1;
- LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[6]), .I1(A[5]), .I2(A[4]),
- .I3(A[3]), .I4(A[2]), .I5(A[1]));
- LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[6]), .I1(A[5]), .I2(A[4]),
- .I3(A[3]), .I4(A[2]), .I5(A[1]));
- MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[0]));
+ wire f0, f1;
+ \$lut #(.LUT(LUT[ 63: 0]), .WIDTH(6)) lut0 (.A(A[5:0]), .Y(f0));
+ \$lut #(.LUT(LUT[127:64]), .WIDTH(6)) lut1 (.A(A[5:0]), .Y(f1));
+ MUXF7 mux7(.I0(f0), .I1(f1), .S(A[6]), .O(Y));
end else
if (WIDTH == 8) begin
- wire T0, T1, T2, T3, T4, T5;
- LUT6 #(.INIT(P_LUT[63:0])) fpga_lut_0 (.O(T0),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[127:64])) fpga_lut_1 (.O(T1),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[191:128])) fpga_lut_2 (.O(T2),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- LUT6 #(.INIT(P_LUT[255:192])) fpga_lut_3 (.O(T3),
- .I0(A[7]), .I1(A[6]), .I2(A[5]),
- .I3(A[4]), .I4(A[3]), .I5(A[2]));
- MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[1]));
- MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[1]));
- MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[0]));
+ wire f0, f1;
+ \$lut #(.LUT(LUT[127: 0]), .WIDTH(7)) lut0 (.A(A[6:0]), .Y(f0));
+ \$lut #(.LUT(LUT[255:128]), .WIDTH(7)) lut1 (.A(A[6:0]), .Y(f1));
+ MUXF8 mux8(.I0(f0), .I1(f1), .S(A[7]), .O(Y));
+ end else
+ if (WIDTH == 9) begin
+ wire f0, f1;
+ \$lut #(.LUT(LUT[255: 0]), .WIDTH(8)) lut0 (.A(A[7:0]), .Y(f0));
+ \$lut #(.LUT(LUT[511:256]), .WIDTH(8)) lut1 (.A(A[7:0]), .Y(f1));
+ MUXF9 mux9(.I0(f0), .I1(f1), .S(A[8]), .O(Y));
end else begin
wire _TECHMAP_FAIL_ = 1;
end
diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc
index 3dc05cd10..a6b422b83 100644
--- a/techlibs/xilinx/synth_xilinx.cc
+++ b/techlibs/xilinx/synth_xilinx.cc
@@ -49,10 +49,25 @@ struct SynthXilinxPass : public ScriptPass
log(" -top <module>\n");
log(" use the specified module as top module\n");
log("\n");
- log(" -family {xcup|xcu|xc7|xc6v|xc5v|xc6s}\n");
+ log(" -family <family>\n");
log(" run synthesis for the specified Xilinx architecture\n");
log(" generate the synthesis netlist for the specified family.\n");
- log(" default: xc7\n");
+ log(" supported values:\n");
+ log(" - xcup: Ultrascale Plus\n");
+ log(" - xcu: Ultrascale\n");
+ log(" - xc7: Series 7 (default)\n");
+ log(" - xc6s: Spartan 6\n");
+ log(" - xc6v: Virtex 6\n");
+ log(" - xc5v: Virtex 5 (EXPERIMENTAL)\n");
+ log(" - xc4v: Virtex 4 (EXPERIMENTAL)\n");
+ log(" - xc3sda: Spartan 3A DSP (EXPERIMENTAL)\n");
+ log(" - xc3sa: Spartan 3A (EXPERIMENTAL)\n");
+ log(" - xc3se: Spartan 3E (EXPERIMENTAL)\n");
+ log(" - xc3s: Spartan 3 (EXPERIMENTAL)\n");
+ log(" - xc2vp: Virtex 2 Pro (EXPERIMENTAL)\n");
+ log(" - xc2v: Virtex 2 (EXPERIMENTAL)\n");
+ log(" - xcve: Virtex E, Spartan 2E (EXPERIMENTAL)\n");
+ log(" - xcv: Virtex, Spartan 2 (EXPERIMENTAL)\n");
log("\n");
log(" -edif <file>\n");
log(" write the design to the specified edif file. writing of an output file\n");
@@ -82,10 +97,10 @@ struct SynthXilinxPass : public ScriptPass
log(" do not use XORCY/MUXCY/CARRY4 cells in output netlist\n");
log("\n");
log(" -nowidelut\n");
- log(" do not use MUXF[78] resources to implement LUTs larger than LUT6s\n");
+ log(" do not use MUXF[5-9] resources to implement LUTs larger than native for the target\n");
log("\n");
log(" -nodsp\n");
- log(" do not use DSP48E1s to implement multipliers and associated logic\n");
+ log(" do not use DSP48*s to implement multipliers and associated logic\n");
log("\n");
log(" -noiopad\n");
log(" disable I/O buffer insertion (useful for hierarchical or \n");
@@ -131,6 +146,8 @@ struct SynthXilinxPass : public ScriptPass
bool abc9, dff_mode;
bool flatten_before_abc;
int widemux;
+ int lut_size;
+ int widelut_size;
void clear_flags() YS_OVERRIDE
{
@@ -156,6 +173,7 @@ struct SynthXilinxPass : public ScriptPass
dff_mode = false;
flatten_before_abc = false;
widemux = 0;
+ lut_size = 6;
}
void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
@@ -270,9 +288,38 @@ struct SynthXilinxPass : public ScriptPass
}
extra_args(args, argidx, design);
- if (family != "xcup" && family != "xcu" && family != "xc7" && family != "xc6v" && family != "xc5v" && family != "xc6s")
+ if (family == "xcup" || family == "xcu") {
+ lut_size = 6;
+ widelut_size = 9;
+ } else if (family == "xc7" ||
+ family == "xc6v" ||
+ family == "xc5v" ||
+ family == "xc6s") {
+ lut_size = 6;
+ widelut_size = 8;
+ } else if (family == "xc4v" ||
+ family == "xc3sda" ||
+ family == "xc3sa" ||
+ family == "xc3se" ||
+ family == "xc3s" ||
+ family == "xc2vp" ||
+ family == "xc2v") {
+ lut_size = 4;
+ widelut_size = 8;
+ } else if (family == "xcve" || family == "xcv") {
+ lut_size = 4;
+ widelut_size = 6;
+ } else
log_cmd_error("Invalid Xilinx -family setting: '%s'.\n", family.c_str());
+ if (widemux != 0 && lut_size != 6)
+ log_cmd_error("-widemux is not currently supported for LUT4-based architectures.\n");
+
+ if (lut_size != 6) {
+ log_warning("Shift register inference not yet supported for family %s.\n", family.c_str());
+ nosrl = true;
+ }
+
if (widemux != 0 && widemux < 2)
log_cmd_error("-widemux value must be 0 or >= 2.\n");
@@ -292,6 +339,9 @@ struct SynthXilinxPass : public ScriptPass
void script() YS_OVERRIDE
{
+ std::string lut_size_s = std::to_string(lut_size);
+ if (help_mode)
+ lut_size_s = "[46]";
std::string ff_map_file;
if (help_mode)
ff_map_file = "+/xilinx/{family}_ff_map.v";
@@ -316,7 +366,11 @@ struct SynthXilinxPass : public ScriptPass
run("proc");
if (flatten || help_mode)
run("flatten", "(with '-flatten')");
+ if (active_design)
+ active_design->scratchpad_unset("tribuf.added_something");
run("tribuf -logic");
+ if (noiopad && active_design && active_design->scratchpad_get_bool("tribuf.added_something"))
+ log_error("Tristate buffers are unsupported without the '-iopad' option.\n");
run("deminout");
run("opt_expr");
run("opt_clean");
@@ -340,7 +394,7 @@ struct SynthXilinxPass : public ScriptPass
run("clean", " (skip if '-nosrl' and '-widemux=0')");
}
- run("techmap -map +/cmp2lut.v -D LUT_WIDTH=6");
+ run("techmap -map +/cmp2lut.v -D LUT_WIDTH=" + lut_size_s);
}
if (check_label("map_dsp", "(skip if '-nodsp')")) {
@@ -349,7 +403,7 @@ struct SynthXilinxPass : public ScriptPass
// NB: Xilinx multipliers are signed only
if (help_mode)
run("techmap -map +/mul2dsp.v -map +/xilinx/{family}_dsp_map.v {options}");
- else if (family == "xc2v" || family == "xc3s" || family == "xc3se" || family == "xc3sa")
+ else if (family == "xc2v" || family == "xc2vp" || family == "xc3s" || family == "xc3se" || family == "xc3sa")
run("techmap -map +/mul2dsp.v -map +/xilinx/xc3s_mult_map.v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 "
"-D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 " // Blocks Nx1 multipliers
"-D DSP_Y_MINWIDTH=9 " // UG901 suggests small multiplies are those 4x4 and smaller
@@ -434,7 +488,19 @@ struct SynthXilinxPass : public ScriptPass
run("memory_bram -rules +/xilinx/{family}_brams.txt");
run("techmap -map +/xilinx/{family}_brams_map.v");
} else if (!nobram) {
- if (family == "xc6s") {
+ if (family == "xc2v" || family == "xc2vp" || family == "xc3s" || family == "xc3se") {
+ run("memory_bram -rules +/xilinx/xc2v_brams.txt");
+ run("techmap -map +/xilinx/xc2v_brams_map.v");
+ } else if (family == "xc3sa") {
+ // Superset of Virtex 2 primitives — uses common map file.
+ run("memory_bram -rules +/xilinx/xc3sa_brams.txt");
+ run("techmap -map +/xilinx/xc2v_brams_map.v");
+ } else if (family == "xc3sda") {
+ // Supported block RAMs for Spartan 3A DSP are
+ // a subset of Spartan 6's ones.
+ run("memory_bram -rules +/xilinx/xc3sda_brams.txt");
+ run("techmap -map +/xilinx/xc6s_brams_map.v");
+ } else if (family == "xc6s") {
run("memory_bram -rules +/xilinx/xc6s_brams.txt");
run("techmap -map +/xilinx/xc6s_brams_map.v");
} else if (family == "xc6v" || family == "xc7") {
@@ -451,7 +517,7 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("map_lutram", "(skip if '-nolutram')")) {
if (!nolutram || help_mode) {
- run("memory_bram -rules +/xilinx/lutrams.txt");
+ run("memory_bram -rules +/xilinx/lut" + lut_size_s + "_lutrams.txt");
run("techmap -map +/xilinx/lutrams_map.v");
}
}
@@ -477,9 +543,8 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("fine")) {
run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*");
- if (help_mode) {
- run("muxcover <internal options>, ('-widemux' only)");
- }
+ if (help_mode)
+ run("muxcover <internal options> ('-widemux' only)");
else if (widemux > 0) {
constexpr int cost_mux2 = 100;
std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2);
@@ -507,19 +572,15 @@ struct SynthXilinxPass : public ScriptPass
if (!nosrl || help_mode)
run("xilinx_srl -variable -minlen 3", "(skip if '-nosrl')");
- std::string techmap_args = " -map +/techmap.v";
+ std::string techmap_args = " -map +/techmap.v -D LUT_SIZE=" + lut_size_s;
if (help_mode)
techmap_args += " [-map +/xilinx/mux_map.v]";
else if (widemux > 0)
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", widemux);
- if (help_mode)
- techmap_args += " [-map +/xilinx/arith_map.v]";
- else if (!nocarry) {
+ if (!nocarry) {
techmap_args += " -map +/xilinx/arith_map.v";
if (vpr)
techmap_args += " -D _EXPLICIT_CARRY";
- else
- techmap_args += " -D _CLB_CARRY";
}
run("techmap " + techmap_args);
run("opt -fast");
@@ -528,7 +589,7 @@ struct SynthXilinxPass : public ScriptPass
if (check_label("map_cells")) {
// Needs to be done before logic optimization, so that inverters (OE vs T) are handled.
if (help_mode || !noiopad)
- run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(only if not '-noiopad')");
+ run("iopadmap -bits -outpad OBUF I:O -inpad IBUF O:I -toutpad $__XILINX_TOUTPAD OE:I:O -tinoutpad $__XILINX_TINOUTPAD OE:O:I:IO A:top", "(skip if '-noiopad')");
std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v";
if (widemux > 0)
techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux);
@@ -549,6 +610,8 @@ struct SynthXilinxPass : public ScriptPass
if (help_mode)
run("abc -luts 2:2,3,6:5[,10,20] [-dff] [-D 1]", "(option for 'nowidelut', '-dff', '-retime')");
else if (abc9) {
+ if (lut_size != 6)
+ log_error("'synth_xilinx -abc9' not currently supported for LUT4-based devices.\n");
if (family != "xc7")
log_warning("'synth_xilinx -abc9' not currently supported for the '%s' family, "
"will use timing for 'xc7' instead.\n", family.c_str());
@@ -574,10 +637,19 @@ struct SynthXilinxPass : public ScriptPass
}
else {
std::string abc_opts;
- if (nowidelut)
- abc_opts += " -luts 2:2,3,6:5";
- else
- abc_opts += " -luts 2:2,3,6:5,10,20";
+ if (lut_size != 6) {
+ if (nowidelut)
+ abc_opts += " -lut " + lut_size_s;
+ else
+ abc_opts += " -lut " + lut_size_s + ":" + std::to_string(widelut_size);
+ } else {
+ if (nowidelut)
+ abc_opts += " -luts 2:2,3,6:5";
+ else if (widelut_size == 8)
+ abc_opts += " -luts 2:2,3,6:5,10,20";
+ else
+ abc_opts += " -luts 2:2,3,6:5,10,20,40";
+ }
if (dff_mode)
abc_opts += " -dff";
if (retime)
@@ -591,17 +663,22 @@ struct SynthXilinxPass : public ScriptPass
if (!nosrl || help_mode)
run("xilinx_srl -fixed -minlen 3", "(skip if '-nosrl')");
std::string techmap_args = "-map +/xilinx/lut_map.v -map +/xilinx/cells_map.v";
- if (help_mode)
- techmap_args += stringf("[-map %s]", ff_map_file.c_str());
- else if (!abc9)
+ if (help_mode || !abc9)
techmap_args += stringf(" -map %s", ff_map_file.c_str());
- run("techmap " + techmap_args, "(only if '-abc9')");
- run("xilinx_dffopt");
+ techmap_args += " -D LUT_WIDTH=" + lut_size_s;
+ run("techmap " + techmap_args);
+ if (help_mode)
+ run("xilinx_dffopt [-lut4]");
+ else if (lut_size == 4)
+ run("xilinx_dffopt -lut4");
+ else
+ run("xilinx_dffopt");
+ run("opt_lut_ins -tech xilinx");
}
if (check_label("finalize")) {
if (help_mode || !noclkbuf)
- run("clkbufmap -buf BUFG O:I ", "(skip if '-noclkbuf')");
+ run("clkbufmap -buf BUFG O:I", "(skip if '-noclkbuf')");
if (help_mode || ise)
run("extractinv -inv INV O:I", "(only if '-ise')");
run("clean");
diff --git a/techlibs/xilinx/tests/.gitignore b/techlibs/xilinx/tests/.gitignore
index 848f88d53..0d9c28fde 100644
--- a/techlibs/xilinx/tests/.gitignore
+++ b/techlibs/xilinx/tests/.gitignore
@@ -12,4 +12,7 @@ test_dsp48a_model_ref.v
test_dsp48a1_model_ref.v
test_dsp48a1_model_uut.v
test_dsp48a1_model
+test_dsp48_model_ref.v
+test_dsp48_model_uut.v
+test_dsp48_model
*.vcd
diff --git a/techlibs/xilinx/tests/test_dsp48_model.sh b/techlibs/xilinx/tests/test_dsp48_model.sh
new file mode 100644
index 000000000..9a73f9b0c
--- /dev/null
+++ b/techlibs/xilinx/tests/test_dsp48_model.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+set -ex
+if [ -z $ISE_DIR ]; then
+ ISE_DIR=/opt/Xilinx/ISE/14.7
+fi
+sed 's/DSP48 /DSP48_UUT /; /DSP48_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48_model_uut.v
+if [ ! -f "test_dsp48_model_ref.v" ]; then
+ cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48.v test_dsp48_model_ref.v
+fi
+for tb in mult_allreg mult_noreg mult_inreg
+do
+ iverilog -s $tb -s glbl -o test_dsp48_model test_dsp48_model.v test_dsp48_model_uut.v test_dsp48_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v
+ vvp -N ./test_dsp48_model
+done
diff --git a/techlibs/xilinx/tests/test_dsp48_model.v b/techlibs/xilinx/tests/test_dsp48_model.v
new file mode 100644
index 000000000..d69c00e93
--- /dev/null
+++ b/techlibs/xilinx/tests/test_dsp48_model.v
@@ -0,0 +1,287 @@
+`timescale 1ns / 1ps
+
+module testbench;
+ parameter integer AREG = 1;
+ parameter integer BREG = 1;
+ parameter integer CREG = 1;
+ parameter integer MREG = 1;
+ parameter integer PREG = 1;
+ parameter integer CARRYINREG = 1;
+ parameter integer CARRYINSELREG = 1;
+ parameter integer OPMODEREG = 1;
+ parameter integer SUBTRACTREG = 1;
+ parameter B_INPUT = "DIRECT";
+ parameter LEGACY_MODE = "NONE";
+
+ reg CLK;
+ reg CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL;
+ reg RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL;
+ reg [17:0] A;
+ reg [17:0] B;
+ reg [47:0] C;
+ reg [17:0] BCIN;
+ reg [47:0] PCIN;
+ reg CARRYIN;
+ reg [6:0] OPMODE;
+ reg SUBTRACT;
+ reg [1:0] CARRYINSEL;
+
+ output [47:0] P, REF_P;
+ output [17:0] BCOUT, REF_BCOUT;
+ output [47:0] PCOUT, REF_PCOUT;
+
+ integer errcount = 0;
+
+ reg ERROR_FLAG = 0;
+
+ task clkcycle;
+ begin
+ #5;
+ CLK = ~CLK;
+ #10;
+ CLK = ~CLK;
+ #2;
+ ERROR_FLAG = 0;
+ if (REF_BCOUT !== BCOUT) begin
+ $display("ERROR at %1t: REF_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, BCOUT, REF_BCOUT ^ BCOUT);
+ errcount = errcount + 1;
+ ERROR_FLAG = 1;
+ end
+ if (REF_P !== P) begin
+ $display("ERROR at %1t: REF_P=%b UUT_P=%b DIFF=%b", $time, REF_P, P, REF_P ^ P);
+ errcount = errcount + 1;
+ ERROR_FLAG = 1;
+ end
+ if (REF_PCOUT !== PCOUT) begin
+ $display("ERROR at %1t: REF_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, PCOUT, REF_PCOUT ^ PCOUT);
+ errcount = errcount + 1;
+ ERROR_FLAG = 1;
+ end
+ #3;
+ end
+ endtask
+
+ reg config_valid = 0;
+ task drc;
+ begin
+ config_valid = 1;
+
+ if (OPMODE[1:0] == 2'b10 && PREG != 1) config_valid = 0;
+ if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b10) config_valid = 0;
+ if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b10) config_valid = 0;
+ if (OPMODE[1:0] == 2'b00 && CARRYINSEL == 2'b11) config_valid = 0;
+ if (OPMODE[1:0] == 2'b10 && CARRYINSEL == 2'b11) config_valid = 0;
+ if (OPMODE[3:2] == 2'b10) config_valid = 0;
+ if ((OPMODE[3:2] == 2'b01) ^ (OPMODE[1:0] == 2'b01) == 1'b1) config_valid = 0;
+ if ((OPMODE[6:4] == 3'b010 || OPMODE[6:4] == 3'b110) && PREG != 1) config_valid = 0;
+ if (OPMODE[6:4] == 3'b100) config_valid = 0;
+ if (OPMODE[6:4] == 3'b111) config_valid = 0;
+ if (OPMODE[6:4] == 3'b000 && CARRYINSEL == 2'b01) config_valid = 0;
+ if (OPMODE[6:4] == 3'b011 && CARRYINSEL == 2'b01) config_valid = 0;
+
+ // Xilinx models consider these combinations invalid for an unknown reason.
+ if (CARRYINSEL == 2'b01 && OPMODE[3:2] == 2'b00) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000011) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0000101) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0100011) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b0111111) config_valid = 0;
+ if (CARRYINSEL == 2'b10 && OPMODE == 7'b1100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0000101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0011111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0010011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0100101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0101111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0110011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b0111111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1010011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1011111) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100011) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1100101) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE == 7'b1101111) config_valid = 0;
+
+ if (CARRYINSEL == 2'b10 && OPMODE[3:0] == 4'b0101 && MREG == 1) config_valid = 0;
+ if (CARRYINSEL == 2'b11 && OPMODE[3:0] == 4'b0101 && MREG == 0) config_valid = 0;
+ end
+ endtask
+
+ initial begin
+ $dumpfile("test_dsp48_model.vcd");
+ $dumpvars(0, testbench);
+
+ #2;
+ CLK = 1'b0;
+ {CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = 8'b11111111;
+ {A, B, C, PCIN, OPMODE, SUBTRACT, CARRYIN, CARRYINSEL} = 0;
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 7'b1111111;
+ repeat (10) begin
+ #10;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0;
+ #10;
+ CLK = 1'b1;
+ #10;
+ CLK = 1'b0;
+ end
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = 0;
+
+ repeat (100000) begin
+ clkcycle;
+ config_valid = 0;
+ while (!config_valid) begin
+ A = $urandom;
+ B = $urandom;
+ C = {$urandom, $urandom};
+ BCIN = $urandom;
+ PCIN = {$urandom, $urandom};
+
+ {CEA, CEB, CEC, CEM, CEP, CECARRYIN, CECINSUB, CECTRL} = $urandom | $urandom | $urandom;
+ {RSTA, RSTB, RSTC, RSTM, RSTP, RSTCARRYIN, RSTCTRL} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom;
+ {CARRYIN, CARRYINSEL, OPMODE, SUBTRACT} = $urandom;
+
+ drc;
+ end
+ end
+
+ if (errcount == 0) begin
+ $display("All tests passed.");
+ $finish;
+ end else begin
+ $display("Caught %1d errors.", errcount);
+ $stop;
+ end
+ end
+
+ DSP48 #(
+ .AREG (AREG),
+ .BREG (BREG),
+ .CREG (CREG),
+ .MREG (MREG),
+ .PREG (PREG),
+ .CARRYINREG (CARRYINREG),
+ .CARRYINSELREG (CARRYINSELREG),
+ .OPMODEREG (OPMODEREG),
+ .SUBTRACTREG (SUBTRACTREG),
+ .B_INPUT (B_INPUT),
+ .LEGACY_MODE (LEGACY_MODE)
+ ) ref (
+ .A (A),
+ .B (B),
+ .C (C),
+ .BCIN (BCIN),
+ .PCIN (PCIN),
+ .CARRYIN (CARRYIN),
+ .OPMODE (OPMODE),
+ .SUBTRACT (SUBTRACT),
+ .CARRYINSEL (CARRYINSEL),
+ .BCOUT (REF_BCOUT),
+ .P (REF_P),
+ .PCOUT (REF_PCOUT),
+ .CEA (CEA),
+ .CEB (CEB),
+ .CEC (CEC),
+ .CEM (CEM),
+ .CEP (CEP),
+ .CECARRYIN (CECARRYIN),
+ .CECINSUB (CECINSUB),
+ .CECTRL (CECTRL),
+ .CLK (CLK),
+ .RSTA (RSTA),
+ .RSTB (RSTB),
+ .RSTC (RSTC),
+ .RSTM (RSTM),
+ .RSTP (RSTP),
+ .RSTCARRYIN (RSTCARRYIN),
+ .RSTCTRL (RSTCTRL)
+ );
+
+ DSP48_UUT #(
+ .AREG (AREG),
+ .BREG (BREG),
+ .CREG (CREG),
+ .MREG (MREG),
+ .PREG (PREG),
+ .CARRYINREG (CARRYINREG),
+ .CARRYINSELREG (CARRYINSELREG),
+ .OPMODEREG (OPMODEREG),
+ .SUBTRACTREG (SUBTRACTREG),
+ .B_INPUT (B_INPUT),
+ .LEGACY_MODE (LEGACY_MODE)
+ ) uut (
+ .A (A),
+ .B (B),
+ .C (C),
+ .BCIN (BCIN),
+ .PCIN (PCIN),
+ .CARRYIN (CARRYIN),
+ .OPMODE (OPMODE),
+ .SUBTRACT (SUBTRACT),
+ .CARRYINSEL (CARRYINSEL),
+ .BCOUT (BCOUT),
+ .P (P),
+ .PCOUT (PCOUT),
+ .CEA (CEA),
+ .CEB (CEB),
+ .CEC (CEC),
+ .CEM (CEM),
+ .CEP (CEP),
+ .CECARRYIN (CECARRYIN),
+ .CECINSUB (CECINSUB),
+ .CECTRL (CECTRL),
+ .CLK (CLK),
+ .RSTA (RSTA),
+ .RSTB (RSTB),
+ .RSTC (RSTC),
+ .RSTM (RSTM),
+ .RSTP (RSTP),
+ .RSTCARRYIN (RSTCARRYIN),
+ .RSTCTRL (RSTCTRL)
+ );
+endmodule
+
+module mult_noreg;
+ testbench #(
+ .AREG (0),
+ .BREG (0),
+ .CREG (0),
+ .MREG (0),
+ .PREG (0),
+ .CARRYINREG (0),
+ .CARRYINSELREG (0),
+ .OPMODEREG (0),
+ .SUBTRACTREG (0),
+ .B_INPUT ("DIRECT")
+ ) testbench ();
+endmodule
+
+module mult_allreg;
+ testbench #(
+ .AREG (1),
+ .BREG (1),
+ .CREG (1),
+ .MREG (1),
+ .PREG (1),
+ .CARRYINREG (1),
+ .CARRYINSELREG (1),
+ .OPMODEREG (1),
+ .SUBTRACTREG (1),
+ .B_INPUT ("CASCADE")
+ ) testbench ();
+endmodule
+
+module mult_inreg;
+ testbench #(
+ .AREG (1),
+ .BREG (1),
+ .CREG (1),
+ .MREG (0),
+ .PREG (0),
+ .CARRYINREG (1),
+ .CARRYINSELREG (0),
+ .OPMODEREG (0),
+ .SUBTRACTREG (0),
+ .B_INPUT ("DIRECT")
+ ) testbench ();
+endmodule
diff --git a/techlibs/xilinx/xc2v_brams.txt b/techlibs/xilinx/xc2v_brams.txt
new file mode 100644
index 000000000..ac8cfb552
--- /dev/null
+++ b/techlibs/xilinx/xc2v_brams.txt
@@ -0,0 +1,31 @@
+# Virtex 2, Virtex 2 Pro, Spartan 3, Spartan 3E block RAM rules.
+
+bram $__XILINX_RAMB16
+ init 1
+ abits 9 @a9d36
+ dbits 36 @a9d36
+ abits 10 @a10d18
+ dbits 18 @a10d18
+ abits 11 @a11d9
+ dbits 9 @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 0 1
+ enable 1 1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__XILINX_RAMB16
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+endmatch
diff --git a/techlibs/xilinx/xc2v_brams_map.v b/techlibs/xilinx/xc2v_brams_map.v
new file mode 100644
index 000000000..dc698f956
--- /dev/null
+++ b/techlibs/xilinx/xc2v_brams_map.v
@@ -0,0 +1,266 @@
+// Virtex 2, Virtex 2 Pro, Spartan 3, Spartan 3E, Spartan 3A block RAM
+// mapping (Spartan 3A is a superset of the other four).
+
+// ------------------------------------------------------------------------
+
+module \$__XILINX_RAMB16 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 9;
+ parameter CFG_DBITS = 36;
+ parameter CFG_ENABLE_B = 1;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [18431:0] INIT = 18432'bx;
+
+ input CLK2;
+ input CLK3;
+
+ 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 [CFG_ENABLE_B-1:0] B1EN;
+
+ generate if (CFG_DBITS == 1) begin
+ wire DOB;
+ RAMB16_S1_S1 #(
+ `include "brams_init_16.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(1'd0),
+ .DOA(A1DATA),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB(B1DATA),
+ .DOB(DOB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 2) begin
+ wire [1:0] DOB;
+ RAMB16_S2_S2 #(
+ `include "brams_init_16.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(2'd0),
+ .DOA(A1DATA),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB(B1DATA),
+ .DOB(DOB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 4) begin
+ wire [3:0] DOB;
+ RAMB16_S4_S4 #(
+ `include "brams_init_16.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(4'd0),
+ .DOA(A1DATA),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB(B1DATA),
+ .DOB(DOB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 9) begin
+ wire [7:0] DOB;
+ wire DOPB;
+ RAMB16_S9_S9 #(
+ `include "brams_init_18.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(8'd0),
+ .DIPA(1'd0),
+ .DOA(A1DATA[7:0]),
+ .DOPA(A1DATA[8]),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB(B1DATA[7:0]),
+ .DIPB(B1DATA[8]),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 18) begin
+ wire [15:0] DOB;
+ wire [1:0] DOPB;
+ RAMB16_S18_S18 #(
+ `include "brams_init_18.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(16'd0),
+ .DIPA(2'd0),
+ .DOA({A1DATA[16:9], A1DATA[7:0]}),
+ .DOPA({A1DATA[17], A1DATA[8]}),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB({B1DATA[16:9], B1DATA[7:0]}),
+ .DIPB({B1DATA[17], B1DATA[8]}),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 36) begin
+ wire [31:0] DOB;
+ wire [3:0] DOPB;
+ RAMB16_S36_S36 #(
+ `include "brams_init_18.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(32'd0),
+ .DIPA(4'd0),
+ .DOA({A1DATA[34:27], A1DATA[25:18], A1DATA[16:9], A1DATA[7:0]}),
+ .DOPA({A1DATA[35], A1DATA[26], A1DATA[17], A1DATA[8]}),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(1'b0),
+
+ .DIB({B1DATA[34:27], B1DATA[25:18], B1DATA[16:9], B1DATA[7:0]}),
+ .DIPB({B1DATA[35], B1DATA[26], B1DATA[17], B1DATA[8]}),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else begin
+ $error("Strange block RAM data width.");
+ end endgenerate
+endmodule
+
+
+// Version with separate byte enables, only available on Spartan 3A.
+
+module \$__XILINX_RAMB16BWE (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+ parameter CFG_ABITS = 9;
+ parameter CFG_DBITS = 36;
+ parameter CFG_ENABLE_B = 4;
+
+ parameter CLKPOL2 = 1;
+ parameter CLKPOL3 = 1;
+ parameter [18431:0] INIT = 18432'bx;
+
+ input CLK2;
+ input CLK3;
+
+ 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 [CFG_ENABLE_B-1:0] B1EN;
+
+ generate if (CFG_DBITS == 18) begin
+ wire [15:0] DOB;
+ wire [1:0] DOPB;
+ RAMB16BWE_S18_S18 #(
+ `include "brams_init_18.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(16'd0),
+ .DIPA(2'd0),
+ .DOA({A1DATA[16:9], A1DATA[7:0]}),
+ .DOPA({A1DATA[17], A1DATA[8]}),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(2'b00),
+
+ .DIB({B1DATA[16:9], B1DATA[7:0]}),
+ .DIPB({B1DATA[17], B1DATA[8]}),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else if (CFG_DBITS == 36) begin
+ wire [31:0] DOB;
+ wire [3:0] DOPB;
+ RAMB16BWE_S36_S36 #(
+ `include "brams_init_18.vh"
+ .WRITE_MODE_A("READ_FIRST"),
+ .WRITE_MODE_B("READ_FIRST"),
+ ) _TECHMAP_REPLACE_ (
+ .DIA(32'd0),
+ .DIPA(4'd0),
+ .DOA({A1DATA[34:27], A1DATA[25:18], A1DATA[16:9], A1DATA[7:0]}),
+ .DOPA({A1DATA[35], A1DATA[26], A1DATA[17], A1DATA[8]}),
+ .ADDRA(A1ADDR),
+ .CLKA(CLK2 ^ !CLKPOL2),
+ .ENA(A1EN),
+ .SSRA(|0),
+ .WEA(4'b0000),
+
+ .DIB({B1DATA[34:27], B1DATA[25:18], B1DATA[16:9], B1DATA[7:0]}),
+ .DIPB({B1DATA[35], B1DATA[26], B1DATA[17], B1DATA[8]}),
+ .DOB(DOB),
+ .DOPB(DOPB),
+ .ADDRB(B1ADDR),
+ .CLKB(CLK3 ^ !CLKPOL3),
+ .ENB(|1),
+ .SSRB(|0),
+ .WEB(B1EN)
+ );
+ end else begin
+ $error("Strange block RAM data width.");
+ end endgenerate
+endmodule
diff --git a/techlibs/xilinx/xc3sa_brams.txt b/techlibs/xilinx/xc3sa_brams.txt
new file mode 100644
index 000000000..22a62bd2c
--- /dev/null
+++ b/techlibs/xilinx/xc3sa_brams.txt
@@ -0,0 +1,51 @@
+# Spartan 3A block RAM rules.
+
+bram $__XILINX_RAMB16
+ init 1
+ abits 11 @a11d9
+ dbits 9 @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 0 1
+ enable 1 1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+bram $__XILINX_RAMB16BWE
+ init 1
+ abits 9 @a9d36
+ dbits 36 @a9d36
+ abits 10 @a10d18
+ dbits 18 @a10d18
+ groups 2
+ ports 1 1
+ wrmode 0 1
+ enable 1 4 @a9d36
+ enable 1 2 @a10d18
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__XILINX_RAMB16
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+ or_next_if_better
+endmatch
+
+match $__XILINX_RAMB16BWE
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+endmatch
diff --git a/techlibs/xilinx/xc3sda_brams.txt b/techlibs/xilinx/xc3sda_brams.txt
new file mode 100644
index 000000000..12c68ffd5
--- /dev/null
+++ b/techlibs/xilinx/xc3sda_brams.txt
@@ -0,0 +1,33 @@
+# Spartan 3A DSP block RAM rules.
+
+bram $__XILINX_RAMB16BWER_TDP
+ init 1
+ abits 9 @a9d36
+ dbits 36 @a9d36
+ abits 10 @a10d18
+ dbits 18 @a10d18
+ abits 11 @a11d9
+ dbits 9 @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 0 1
+ enable 1 4 @a9d36
+ enable 1 2 @a10d18
+ enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
+ transp 0 0
+ clocks 2 3
+ clkpol 2 3
+endbram
+
+match $__XILINX_RAMB16BWER_TDP
+ min bits 4096
+ min efficiency 5
+ shuffle_enable B
+ make_transp
+endmatch
diff --git a/techlibs/xilinx/xc6s_brams.txt b/techlibs/xilinx/xc6s_brams.txt
index 17cd8e355..6457097db 100644
--- a/techlibs/xilinx/xc6s_brams.txt
+++ b/techlibs/xilinx/xc6s_brams.txt
@@ -1,3 +1,4 @@
+# Spartan 6 block RAM rules.
bram $__XILINX_RAMB8BWER_SDP
init 1
diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v
index 16fd15e74..9577eebe4 100644
--- a/techlibs/xilinx/xc6s_brams_map.v
+++ b/techlibs/xilinx/xc6s_brams_map.v
@@ -1,3 +1,6 @@
+// Spartan 3A DSP and Spartan 6 block RAM mapping (Spartan 6 is a superset of
+// Spartan 3A DSP).
+
module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
diff --git a/techlibs/xilinx/xc7_brams_map.v b/techlibs/xilinx/xc7_brams_map.v
index 7ea49158d..2b6ad0da6 100644
--- a/techlibs/xilinx/xc7_brams_map.v
+++ b/techlibs/xilinx/xc7_brams_map.v
@@ -1,3 +1,5 @@
+// Virtex 6 and Series 7 block RAM mapping.
+
module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;
diff --git a/techlibs/xilinx/xc7_xcu_brams.txt b/techlibs/xilinx/xc7_xcu_brams.txt
index c63218ae1..650367abf 100644
--- a/techlibs/xilinx/xc7_xcu_brams.txt
+++ b/techlibs/xilinx/xc7_xcu_brams.txt
@@ -1,3 +1,5 @@
+# Virtex 6, Series 7, Ultrascale, Ultrascale Plus block RAM rules.
+
bram $__XILINX_RAMB36_SDP
init 1
abits 9
diff --git a/techlibs/xilinx/xcu_brams_map.v b/techlibs/xilinx/xcu_brams_map.v
index 6e7925b57..b6719b2dd 100644
--- a/techlibs/xilinx/xcu_brams_map.v
+++ b/techlibs/xilinx/xcu_brams_map.v
@@ -1,3 +1,5 @@
+// Ultrascale and Ultrascale Plus block RAM mapping.
+
module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
parameter CLKPOL2 = 1;
parameter CLKPOL3 = 1;