diff options
author | Eddie Hung <eddie@fpgeh.com> | 2020-02-05 10:47:31 -0800 |
---|---|---|
committer | Eddie Hung <eddie@fpgeh.com> | 2020-02-05 10:47:31 -0800 |
commit | b6a1f627b5871e750fe6a559fbb42334c7de8b84 (patch) | |
tree | f1b284aebe30d0f7eabd9e8919b4275a38ff2ae4 /techlibs/xilinx | |
parent | 5aaa19f1ab33394accbe633cd96a3fbe281dd09a (diff) | |
parent | 5ebdc0f8e07989b79337ced0553bd28819a8cf3e (diff) | |
download | yosys-b6a1f627b5871e750fe6a559fbb42334c7de8b84.tar.gz yosys-b6a1f627b5871e750fe6a559fbb42334c7de8b84.tar.bz2 yosys-b6a1f627b5871e750fe6a559fbb42334c7de8b84.zip |
Merge remote-tracking branch 'origin/master' into eddie/shiftx2mux
Diffstat (limited to 'techlibs/xilinx')
-rw-r--r-- | techlibs/xilinx/abc9_map.v | 16 | ||||
-rw-r--r-- | techlibs/xilinx/abc9_model.v | 7 | ||||
-rw-r--r-- | techlibs/xilinx/abc9_xc7.box | 61 | ||||
-rw-r--r-- | techlibs/xilinx/cells_sim.v | 625 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.py | 42 | ||||
-rw-r--r-- | techlibs/xilinx/cells_xtra.v | 59 | ||||
-rw-r--r-- | techlibs/xilinx/lut_map.v | 99 | ||||
-rw-r--r-- | techlibs/xilinx/lutrams.txt | 4 | ||||
-rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 15 | ||||
-rw-r--r-- | techlibs/xilinx/tests/.gitignore | 3 | ||||
-rw-r--r-- | techlibs/xilinx/tests/test_dsp48_model.sh | 14 | ||||
-rw-r--r-- | techlibs/xilinx/tests/test_dsp48_model.v | 287 |
12 files changed, 966 insertions, 266 deletions
diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v index 0652064cb..7dc027176 100644 --- a/techlibs/xilinx/abc9_map.v +++ b/techlibs/xilinx/abc9_map.v @@ -74,7 +74,7 @@ // (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; @@ -110,7 +110,7 @@ module FDRE (output Q, input C, CE, D, R); 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 @@ -138,7 +138,7 @@ module FDRE_1 (output Q, input C, CE, D, R); 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; @@ -173,7 +173,7 @@ module FDSE (output Q, input C, CE, D, S); 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 @@ -200,7 +200,7 @@ module FDSE_1 (output Q, input C, CE, D, S); 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; @@ -249,7 +249,7 @@ module FDCE (output Q, input C, CE, D, CLR); 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 @@ -288,7 +288,7 @@ module FDCE_1 (output Q, input C, CE, D, CLR); 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; @@ -335,7 +335,7 @@ module FDPE (output Q, input C, CE, D, PRE); 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 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/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/lut_map.v b/techlibs/xilinx/lut_map.v index 62d501632..718ec42f1 100644 --- a/techlibs/xilinx/lut_map.v +++ b/techlibs/xilinx/lut_map.v @@ -29,90 +29,65 @@ 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) begin - LUT5 #(.INIT(P_LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[4]), .I1(A[3]), .I2(A[2]), - .I3(A[1]), .I4(A[0])); + 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 == 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])); + 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 == 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])); + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); 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])); + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); + MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); + MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); end else begin wire _TECHMAP_FAIL_ = 1; end diff --git a/techlibs/xilinx/lutrams.txt b/techlibs/xilinx/lutrams.txt index 29f6b05cc..faf66bc18 100644 --- a/techlibs/xilinx/lutrams.txt +++ b/techlibs/xilinx/lutrams.txt @@ -153,7 +153,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 +161,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/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 5c3b5179d..5a28bb139 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -316,7 +316,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"); @@ -526,7 +530,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); @@ -589,17 +593,16 @@ 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("techmap " + techmap_args); 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 |