diff options
author | N. Engelhardt <nak@symbioticeda.com> | 2020-01-03 12:28:48 +0100 |
---|---|---|
committer | N. Engelhardt <nak@symbioticeda.com> | 2020-01-03 12:28:48 +0100 |
commit | 341fd872b59e8f95aa14afd9f17225d2c03a4283 (patch) | |
tree | 21802e73ca767d124971d43d3f78d9f4cf7d62e2 /techlibs | |
parent | c8bc1793a4e8230c29fca4a34862414e8ab8722b (diff) | |
parent | f8d5920a7e61f78873b7bf49dd7e8f3a83f7adf3 (diff) | |
download | yosys-341fd872b59e8f95aa14afd9f17225d2c03a4283.tar.gz yosys-341fd872b59e8f95aa14afd9f17225d2c03a4283.tar.bz2 yosys-341fd872b59e8f95aa14afd9f17225d2c03a4283.zip |
Merge branch 'master' of https://github.com/YosysHQ/yosys into abc_scratchpad_script
Diffstat (limited to 'techlibs')
46 files changed, 1820 insertions, 382 deletions
diff --git a/techlibs/achronix/synth_achronix.cc b/techlibs/achronix/synth_achronix.cc index 626860d9c..1dc6bdb2f 100755 --- a/techlibs/achronix/synth_achronix.cc +++ b/techlibs/achronix/synth_achronix.cc @@ -52,7 +52,7 @@ struct SynthAchronixPass : public ScriptPass { log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -152,12 +152,12 @@ struct SynthAchronixPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); + run("abc -markgroups -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) { - run("abc -lut 4" + string(retime ? " -dff" : "")); + run("abc -lut 4" + string(retime ? " -dff -D 1" : "")); run("clean"); } diff --git a/techlibs/anlogic/Makefile.inc b/techlibs/anlogic/Makefile.inc index 9426b5ca5..2d8d65e2e 100644 --- a/techlibs/anlogic/Makefile.inc +++ b/techlibs/anlogic/Makefile.inc @@ -7,6 +7,6 @@ $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v)) $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v)) -$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams.txt)) -$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/drams_map.v)) -$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/dram_init_16x4.vh)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams.txt)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams_map.v)) +$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutram_init_16x4.vh)) diff --git a/techlibs/anlogic/cells_map.v b/techlibs/anlogic/cells_map.v index cfc743a4b..8ac087d9d 100644 --- a/techlibs/anlogic/cells_map.v +++ b/techlibs/anlogic/cells_map.v @@ -6,14 +6,14 @@ module \$_DFFE_NP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REG module \$_DFFE_PN_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule module \$_DFFE_PP_ (input D, C, E, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'bx), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(E), .sr(1'b0)); endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("SYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(~C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C) , .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("INV"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b0), .SRMUX("SR"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); AL_MAP_SEQ #(.DFFMODE("FF"), .REGSET(1'b1), .SRMUX("SR"), . SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.d(D), .q(Q), .clk(C), .ce(1'b1), .sr(R)); endmodule module \$_DLATCH_N_ (E, D, Q); wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; diff --git a/techlibs/anlogic/dram_init_16x4.vh b/techlibs/anlogic/lutram_init_16x4.vh index 32fb1578c..32fb1578c 100644 --- a/techlibs/anlogic/dram_init_16x4.vh +++ b/techlibs/anlogic/lutram_init_16x4.vh diff --git a/techlibs/anlogic/drams.txt b/techlibs/anlogic/lutrams.txt index 4e903c0a2..4e903c0a2 100644 --- a/techlibs/anlogic/drams.txt +++ b/techlibs/anlogic/lutrams.txt diff --git a/techlibs/anlogic/drams_map.v b/techlibs/anlogic/lutrams_map.v index 084e2a25f..5a464cafc 100644 --- a/techlibs/anlogic/drams_map.v +++ b/techlibs/anlogic/lutrams_map.v @@ -10,7 +10,7 @@ module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); input B1EN; EG_LOGIC_DRAM16X4 #( - `include "dram_init_16x4.vh" + `include "lutram_init_16x4.vh" ) _TECHMAP_REPLACE_ ( .di(B1DATA), .waddr(B1ADDR), diff --git a/techlibs/anlogic/synth_anlogic.cc b/techlibs/anlogic/synth_anlogic.cc index b87fc8566..aaa6bda4a 100644 --- a/techlibs/anlogic/synth_anlogic.cc +++ b/techlibs/anlogic/synth_anlogic.cc @@ -58,7 +58,10 @@ struct SynthAnlogicPass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); + log("\n"); + log(" -nolutram\n"); + log(" do not use EG_LOGIC_DRAM16X4 cells in output netlist\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -67,7 +70,7 @@ struct SynthAnlogicPass : public ScriptPass } string top_opt, edif_file, json_file; - bool flatten, retime; + bool flatten, retime, nolutram; void clear_flags() YS_OVERRIDE { @@ -76,6 +79,7 @@ struct SynthAnlogicPass : public ScriptPass json_file = ""; flatten = true; retime = false; + nolutram = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -110,6 +114,10 @@ struct SynthAnlogicPass : public ScriptPass flatten = false; continue; } + if (args[argidx] == "-nolutram") { + nolutram = true; + continue; + } if (args[argidx] == "-retime") { retime = true; continue; @@ -150,21 +158,25 @@ struct SynthAnlogicPass : public ScriptPass run("synth -run coarse"); } - if (check_label("dram")) + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { - run("memory_bram -rules +/anlogic/drams.txt"); - run("techmap -map +/anlogic/drams_map.v"); + run("memory_bram -rules +/anlogic/lutrams.txt"); + run("techmap -map +/anlogic/lutrams_map.v"); run("setundef -zero -params t:EG_LOGIC_DRAM16X4"); } - if (check_label("fine")) + if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { run("techmap -map +/techmap.v -map +/anlogic/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) @@ -187,7 +199,7 @@ struct SynthAnlogicPass : public ScriptPass run("techmap -map +/anlogic/cells_map.v"); run("clean"); } - + if (check_label("map_anlogic")) { run("anlogic_fixcarry"); diff --git a/techlibs/coolrunner2/synth_coolrunner2.cc b/techlibs/coolrunner2/synth_coolrunner2.cc index 014c68622..388e2b792 100644 --- a/techlibs/coolrunner2/synth_coolrunner2.cc +++ b/techlibs/coolrunner2/synth_coolrunner2.cc @@ -55,7 +55,7 @@ struct SynthCoolrunner2Pass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -161,7 +161,7 @@ struct SynthCoolrunner2Pass : public ScriptPass if (check_label("map_pla")) { - run("abc -sop -I 40 -P 56"); + run("abc -sop -I 40 -P 56" + string(retime ? " -dff -D 1" : "")); run("clean"); } diff --git a/techlibs/easic/synth_easic.cc b/techlibs/easic/synth_easic.cc index dd9e3dab7..b4a3a1ac9 100644 --- a/techlibs/easic/synth_easic.cc +++ b/techlibs/easic/synth_easic.cc @@ -56,7 +56,7 @@ struct SynthEasicPass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -158,7 +158,7 @@ struct SynthEasicPass : public ScriptPass run("techmap"); run("opt -fast"); if (retime || help_mode) { - run("abc -dff", " (only if -retime)"); + run("abc -dff -D 1", " (only if -retime)"); run("opt_clean", "(only if -retime)"); } } diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 46463f510..2c33f23b9 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -8,9 +8,9 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_bb.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutram.txt)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/lutrams.txt)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams_map.v)) -$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/bram.txt)) +$(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams.txt)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v)) diff --git a/techlibs/ecp5/bram.txt b/techlibs/ecp5/brams.txt index 777ccaa2e..777ccaa2e 100644 --- a/techlibs/ecp5/bram.txt +++ b/techlibs/ecp5/brams.txt diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 71ae9237b..10e89a3e0 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,21 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), . module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +`ifdef ASYNC_PRLD +module \$_DLATCH_N_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(!E), .DI(1'b0), .M(D), .Q(Q)); endmodule +module \$_DLATCH_P_ (input E, input D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.LSR(E), .DI(1'b0), .M(D), .Q(Q)); endmodule + +module \$_DFFSR_NNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_NNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule +module \$_DFFSR_NPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_NPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule + +module \$_DFFSR_PNN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_PNP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(!S || R), .DI(D), .M(!R), .Q(Q)); endmodule +module \$_DFFSR_PPN_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || !R), .DI(D), .M(R), .Q(Q)); endmodule +module \$_DFFSR_PPP_ (input C, S, R, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(S || R), .DI(D), .M(!R), .Q(Q)); endmodule +`endif + `include "cells_ff.vh" `include "cells_io.vh" diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index f467218cc..0d3ec4e5b 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -1,5 +1,6 @@ // --------------------------------------- +(* lib_whitebox *) module LUT4(input A, B, C, D, output Z); parameter [15:0] INIT = 16'h0000; wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0]; @@ -31,13 +32,8 @@ module CCU2C( // First half wire LUT4_0, LUT2_0; -`ifdef _ABC - assign LUT4_0 = INIT0[{D0, C0, B0, A0}]; - assign LUT2_0 = INIT0[{2'b00, B0, A0}]; -`else LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); -`endif wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; assign S0 = LUT4_0 ^ gated_cin_0; @@ -46,13 +42,8 @@ module CCU2C( // Second half wire LUT4_1, LUT2_1; -`ifdef _ABC - assign LUT4_1 = INIT1[{D1, C1, B1, A1}]; - assign LUT2_1 = INIT1[{2'b00, B1, A1}]; -`else LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); -`endif wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; assign S1 = LUT4_1 ^ gated_cin_1; @@ -209,6 +200,7 @@ endmodule // --------------------------------------- +(* lib_whitebox *) module LUT2(input A, B, output Z); parameter [3:0] INIT = 4'h0; wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0]; diff --git a/techlibs/ecp5/lutram.txt b/techlibs/ecp5/lutrams.txt index b94357429..b94357429 100644 --- a/techlibs/ecp5/lutram.txt +++ b/techlibs/ecp5/lutrams.txt diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 4cbb56ea1..d616391b2 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -62,7 +62,7 @@ struct SynthEcp5Pass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log(" -noccu2\n"); log(" do not use CCU2 cells in output netlist\n"); @@ -79,6 +79,9 @@ struct SynthEcp5Pass : public ScriptPass log(" -nowidelut\n"); log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); log("\n"); + log(" -asyncprld\n"); + log(" use async PRLD mode to implement DLATCH and DFFSR (EXPERIMENTAL)\n"); + log("\n"); log(" -abc2\n"); log(" run two passes of 'abc' for slightly improved logic density\n"); log("\n"); @@ -99,7 +102,7 @@ struct SynthEcp5Pass : public ScriptPass } string top_opt, blif_file, edif_file, json_file; - bool noccu2, nodffe, nobram, nolutram, nowidelut, flatten, retime, abc2, abc9, nodsp, vpr; + bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, retime, abc2, abc9, nodsp, vpr; void clear_flags() YS_OVERRIDE { @@ -112,6 +115,7 @@ struct SynthEcp5Pass : public ScriptPass nobram = false; nolutram = false; nowidelut = false; + asyncprld = false; flatten = true; retime = false; abc2 = false; @@ -176,6 +180,10 @@ struct SynthEcp5Pass : public ScriptPass nobram = true; continue; } + if (args[argidx] == "-asyncprld") { + asyncprld = true; + continue; + } if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { nolutram = true; continue; @@ -222,7 +230,7 @@ struct SynthEcp5Pass : public ScriptPass { if (check_label("begin")) { - run("read_verilog -D_ABC -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v"); + run("read_verilog -lib +/ecp5/cells_sim.v +/ecp5/cells_bb.v"); run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); } @@ -258,13 +266,13 @@ struct SynthEcp5Pass : public ScriptPass if (!nobram && check_label("map_bram", "(skip if -nobram)")) { - run("memory_bram -rules +/ecp5/bram.txt"); + run("memory_bram -rules +/ecp5/brams.txt"); run("techmap -map +/ecp5/brams_map.v"); } if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { - run("memory_bram -rules +/ecp5/lutram.txt"); + run("memory_bram -rules +/ecp5/lutrams.txt"); run("techmap -map +/ecp5/lutrams_map.v"); } @@ -282,7 +290,7 @@ struct SynthEcp5Pass : public ScriptPass else run("techmap -map +/techmap.v -map +/ecp5/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) @@ -292,7 +300,7 @@ struct SynthEcp5Pass : public ScriptPass run("opt_clean"); if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); - run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); + run(stringf("techmap -D NO_LUT %s -map +/ecp5/cells_map.v", help_mode ? "[-D ASYNC_PRLD]" : (asyncprld ? "-D ASYNC_PRLD" : ""))); run("opt_expr -undriven -mux_undef"); run("simplemap"); run("ecp5_ffinit"); @@ -306,10 +314,11 @@ struct SynthEcp5Pass : public ScriptPass if (abc2 || help_mode) { run("abc", " (only if -abc2)"); } - std::string techmap_args = "-map +/ecp5/latches_map.v"; + std::string techmap_args = asyncprld ? "" : "-map +/ecp5/latches_map.v"; if (abc9) techmap_args += " -map +/ecp5/abc9_map.v -max_iter 1"; - run("techmap " + techmap_args); + if (!asyncprld || abc9) + run("techmap " + techmap_args); if (abc9) { run("read_verilog -icells -lib +/ecp5/abc9_model.v"); diff --git a/techlibs/efinix/Makefile.inc b/techlibs/efinix/Makefile.inc index 5013f7fc1..69665982c 100644 --- a/techlibs/efinix/Makefile.inc +++ b/techlibs/efinix/Makefile.inc @@ -7,4 +7,4 @@ $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_map.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/arith_map.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/cells_sim.v)) $(eval $(call add_share_file,share/efinix,techlibs/efinix/brams_map.v)) -$(eval $(call add_share_file,share/efinix,techlibs/efinix/bram.txt)) +$(eval $(call add_share_file,share/efinix,techlibs/efinix/brams.txt)) diff --git a/techlibs/efinix/bram.txt b/techlibs/efinix/brams.txt index 0b3fd9308..0b3fd9308 100644 --- a/techlibs/efinix/bram.txt +++ b/techlibs/efinix/brams.txt diff --git a/techlibs/efinix/synth_efinix.cc b/techlibs/efinix/synth_efinix.cc index 26a8d4eda..0efd91708 100644 --- a/techlibs/efinix/synth_efinix.cc +++ b/techlibs/efinix/synth_efinix.cc @@ -58,7 +58,10 @@ struct SynthEfinixPass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use EFX_RAM_5K cells in output netlist\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -67,7 +70,7 @@ struct SynthEfinixPass : public ScriptPass } string top_opt, edif_file, json_file; - bool flatten, retime; + bool flatten, retime, nobram; void clear_flags() YS_OVERRIDE { @@ -76,6 +79,7 @@ struct SynthEfinixPass : public ScriptPass json_file = ""; flatten = true; retime = false; + nobram = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -114,6 +118,10 @@ struct SynthEfinixPass : public ScriptPass retime = true; continue; } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } break; } extra_args(args, argidx, design); @@ -150,21 +158,25 @@ struct SynthEfinixPass : public ScriptPass run("synth -run coarse"); } - if (check_label("map_bram", "(skip if -nobram)")) + if (!nobram || check_label("map_bram", "(skip if -nobram)")) { - run("memory_bram -rules +/efinix/bram.txt"); + run("memory_bram -rules +/efinix/brams.txt"); run("techmap -map +/efinix/brams_map.v"); run("setundef -zero -params t:EFX_RAM_5K"); } - if (check_label("fine")) + if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { run("techmap -map +/techmap.v -map +/efinix/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) @@ -194,7 +206,7 @@ struct SynthEfinixPass : public ScriptPass run("efinix_fixcarry"); run("clean"); } - + if (check_label("check")) { run("hierarchy -check"); diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index d2853704b..fe5d9d6e6 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -7,9 +7,9 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) -$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt)) -$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v)) -$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) diff --git a/techlibs/gowin/bram.txt b/techlibs/gowin/brams.txt index e406f9c51..e406f9c51 100644 --- a/techlibs/gowin/bram.txt +++ b/techlibs/gowin/brams.txt diff --git a/techlibs/gowin/dram.txt b/techlibs/gowin/lutrams.txt index 9db530251..9db530251 100644 --- a/techlibs/gowin/dram.txt +++ b/techlibs/gowin/lutrams.txt diff --git a/techlibs/gowin/drams_map.v b/techlibs/gowin/lutrams_map.v index a50ab365a..a50ab365a 100644 --- a/techlibs/gowin/drams_map.v +++ b/techlibs/gowin/lutrams_map.v diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 6cf058f29..c5b41b503 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -55,23 +55,23 @@ struct SynthGowinPass : public ScriptPass log(" -nobram\n"); log(" do not use BRAM cells in output netlist\n"); log("\n"); - log(" -nodram\n"); + log(" -nolutram\n"); log(" do not use distributed RAM cells in output netlist\n"); log("\n"); log(" -noflatten\n"); log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log(" -nowidelut\n"); log(" do not use muxes to implement LUTs larger than LUT4s\n"); log("\n"); log(" -noiopads\n"); log(" do not emit IOB at top level ports\n"); - log("\n"); - log(" -abc9\n"); - log(" use new ABC9 flow (EXPERIMENTAL)\n"); + //log("\n"); + //log(" -abc9\n"); + //log(" use new ABC9 flow (EXPERIMENTAL)\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -80,7 +80,7 @@ struct SynthGowinPass : public ScriptPass } string top_opt, vout_file; - bool retime, nobram, nodram, flatten, nodffe, nowidelut, abc9, noiopads; + bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads; void clear_flags() YS_OVERRIDE { @@ -90,7 +90,7 @@ struct SynthGowinPass : public ScriptPass flatten = true; nobram = false; nodffe = false; - nodram = false; + nolutram = false; nowidelut = false; abc9 = false; noiopads = false; @@ -128,8 +128,8 @@ struct SynthGowinPass : public ScriptPass nobram = true; continue; } - if (args[argidx] == "-nodram") { - nodram = true; + if (args[argidx] == "-nolutram" || /*deprecated*/args[argidx] == "-nodram") { + nolutram = true; continue; } if (args[argidx] == "-nodffe") { @@ -144,10 +144,10 @@ struct SynthGowinPass : public ScriptPass nowidelut = true; continue; } - if (args[argidx] == "-abc9") { - abc9 = true; - continue; - } + //if (args[argidx] == "-abc9") { + // abc9 = true; + // continue; + //} if (args[argidx] == "-noiopads") { noiopads = true; continue; @@ -188,28 +188,32 @@ struct SynthGowinPass : public ScriptPass run("synth -run coarse"); } - if (!nobram && check_label("bram", "(skip if -nobram)")) + if (!nobram && check_label("map_bram", "(skip if -nobram)")) { - run("memory_bram -rules +/gowin/bram.txt"); + run("memory_bram -rules +/gowin/brams.txt"); run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v"); } - if (!nodram && check_label("dram", "(skip if -nodram)")) + if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { - run("memory_bram -rules +/gowin/dram.txt"); - run("techmap -map +/gowin/drams_map.v"); + run("memory_bram -rules +/gowin/lutrams.txt"); + run("techmap -map +/gowin/lutrams_map.v"); run("determine_init"); } - if (check_label("fine")) + if (check_label("map_ffram")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); run("techmap -map +/techmap.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); run("splitnets"); } @@ -227,13 +231,13 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_luts")) { - if (nowidelut && abc9) { + /*if (nowidelut && abc9) { run("abc9 -lut 4"); - } else if (nowidelut && !abc9) { + } else*/ if (nowidelut && !abc9) { run("abc -lut 4"); - } else if (!nowidelut && abc9) { + } else /*if (!nowidelut && abc9) { run("abc9 -lut 4:8"); - } else if (!nowidelut && !abc9) { + } else*/ if (!nowidelut && !abc9) { run("abc -lut 4:8"); } run("clean"); @@ -248,7 +252,6 @@ struct SynthGowinPass : public ScriptPass run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O " "-toutpad TBUF OEN:I:O -tinoutpad IOBUF OEN:O:I:IO", "(unless -noiopads)"); run("clean"); - } if (check_label("check")) diff --git a/techlibs/greenpak4/synth_greenpak4.cc b/techlibs/greenpak4/synth_greenpak4.cc index eeb001b46..e1fbe6b69 100644 --- a/techlibs/greenpak4/synth_greenpak4.cc +++ b/techlibs/greenpak4/synth_greenpak4.cc @@ -59,7 +59,7 @@ struct SynthGreenPAK4Pass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -165,7 +165,7 @@ struct SynthGreenPAK4Pass : public ScriptPass run("dfflibmap -prepare -liberty +/greenpak4/gp_dff.lib"); run("opt -fast"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index ed7a16c08..463c2063a 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -65,7 +65,7 @@ struct SynthIce40Pass : public ScriptPass log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log(" -nocarry\n"); log(" do not use SB_CARRY cells in output netlist\n"); @@ -316,7 +316,7 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/techmap.v -map +/ice40/arith_map.v"); } if (retime || help_mode) - run(abc + " -dff", "(only if -retime)"); + run(abc + " -dff -D 1", "(only if -retime)"); run("ice40_opt"); } diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index c8c690e45..2ebb8bf50 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -71,7 +71,7 @@ struct SynthIntelPass : public ScriptPass { log(" do not flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); help_script(); @@ -187,10 +187,10 @@ struct SynthIntelPass : public ScriptPass { } if (!nobram && check_label("map_bram", "(skip if -nobram)")) { - if (family_opt == "cycloneiv" || - family_opt == "cycloneive" || - family_opt == "max10" || - help_mode) { + if (family_opt == "cycloneiv" || + family_opt == "cycloneive" || + family_opt == "max10" || + help_mode) { run("memory_bram -rules +/intel/common/brams_m9k.txt", "(if applicable for family)"); run("techmap -map +/intel/common/brams_map_m9k.v", "(if applicable for family)"); } else { @@ -210,7 +210,7 @@ struct SynthIntelPass : public ScriptPass { run("clean -purge"); run("setundef -undriven -zero"); if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); + run("abc -markgroups -dff -D 1", "(only if -retime)"); } if (check_label("map_luts")) { @@ -224,7 +224,7 @@ struct SynthIntelPass : public ScriptPass { if (check_label("map_cells")) { if (iopads || help_mode) run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(if -iopads)"); - run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str())); + run(stringf("techmap -map +/intel/%s/cells_map.v", family_opt.c_str())); run("dffinit -highlow -ff dffeas q power_up"); run("clean -purge"); } diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index 0924df7a6..543dfdb9e 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -67,7 +67,7 @@ struct SynthSf2Pass : public ScriptPass log(" insert direct PAD->global_net buffers\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); @@ -181,7 +181,7 @@ struct SynthSf2Pass : public ScriptPass run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/sf2/arith_map.v"); if (retime || help_mode) - run("abc -dff", "(only if -retime)"); + run("abc -dff -D 1", "(only if -retime)"); } if (check_label("map_ffs")) diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 3ebc72fe8..3f2fbcc85 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/xilinx/synth_xilinx.o +OBJS += techlibs/xilinx/xilinx_dffopt.o GENFILES += techlibs/xilinx/brams_init_36.vh GENFILES += techlibs/xilinx/brams_init_32.vh diff --git a/techlibs/xilinx/abc9_map.v b/techlibs/xilinx/abc9_map.v index 6fd73c1e0..7b9427b2f 100644 --- a/techlibs/xilinx/abc9_map.v +++ b/techlibs/xilinx/abc9_map.v @@ -88,6 +88,84 @@ module RAM128X1D ( \$__ABC9_LUT7 dpo (.A(\$DPO ), .S(DPRA), .Y(DPO)); endmodule +module RAM32M ( + output [1:0] DOA, + output [1:0] DOB, + output [1:0] DOC, + output [1:0] DOD, + (* techmap_autopurge *) input [4:0] ADDRA, + (* techmap_autopurge *) input [4:0] ADDRB, + (* techmap_autopurge *) input [4:0] ADDRC, + (* techmap_autopurge *) input [4:0] ADDRD, + (* techmap_autopurge *) input [1:0] DIA, + (* techmap_autopurge *) input [1:0] DIB, + (* techmap_autopurge *) input [1:0] DIC, + (* techmap_autopurge *) input [1:0] DID, + (* techmap_autopurge *) input WCLK, + (* techmap_autopurge *) input WE +); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + wire [1:0] \$DOA , \$DOB , \$DOC , \$DOD ; + RAM32M #( + .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), + .IS_WCLK_INVERTED(IS_WCLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), + .WCLK(WCLK), .WE(WE), + .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), + .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) + ); + \$__ABC9_LUT6 doa0 (.A(\$DOA [0]), .S({1'b1, ADDRA}), .Y(DOA[0])); + \$__ABC9_LUT6 doa1 (.A(\$DOA [1]), .S({1'b1, ADDRA}), .Y(DOA[1])); + \$__ABC9_LUT6 dob0 (.A(\$DOB [0]), .S({1'b1, ADDRB}), .Y(DOB[0])); + \$__ABC9_LUT6 dob1 (.A(\$DOB [1]), .S({1'b1, ADDRB}), .Y(DOB[1])); + \$__ABC9_LUT6 doc0 (.A(\$DOC [0]), .S({1'b1, ADDRC}), .Y(DOC[0])); + \$__ABC9_LUT6 doc1 (.A(\$DOC [1]), .S({1'b1, ADDRC}), .Y(DOC[1])); + \$__ABC9_LUT6 dod0 (.A(\$DOD [0]), .S({1'b1, ADDRD}), .Y(DOD[0])); + \$__ABC9_LUT6 dod1 (.A(\$DOD [1]), .S({1'b1, ADDRD}), .Y(DOD[1])); +endmodule + +module RAM64M ( + output DOA, + output DOB, + output DOC, + output DOD, + (* techmap_autopurge *) input [5:0] ADDRA, + (* techmap_autopurge *) input [5:0] ADDRB, + (* techmap_autopurge *) input [5:0] ADDRC, + (* techmap_autopurge *) input [5:0] ADDRD, + (* techmap_autopurge *) input DIA, + (* techmap_autopurge *) input DIB, + (* techmap_autopurge *) input DIC, + (* techmap_autopurge *) input DID, + (* techmap_autopurge *) input WCLK, + (* techmap_autopurge *) input WE +); + parameter [63:0] INIT_A = 64'h0000000000000000; + parameter [63:0] INIT_B = 64'h0000000000000000; + parameter [63:0] INIT_C = 64'h0000000000000000; + parameter [63:0] INIT_D = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + wire \$DOA , \$DOB , \$DOC , \$DOD ; + RAM64M #( + .INIT_A(INIT_A), .INIT_B(INIT_B), .INIT_C(INIT_C), .INIT_D(INIT_D), + .IS_WCLK_INVERTED(IS_WCLK_INVERTED) + ) _TECHMAP_REPLACE_ ( + .DOA(\$DOA ), .DOB(\$DOB ), .DOC(\$DOC ), .DOD(\$DOD ), + .WCLK(WCLK), .WE(WE), + .ADDRA(ADDRA), .ADDRB(ADDRB), .ADDRC(ADDRC), .ADDRD(ADDRD), + .DIA(DIA), .DIB(DIB), .DIC(DIC), .DID(DID) + ); + \$__ABC9_LUT6 doa (.A(\$DOA ), .S(ADDRA), .Y(DOA)); + \$__ABC9_LUT6 dob (.A(\$DOB ), .S(ADDRB), .Y(DOB)); + \$__ABC9_LUT6 doc (.A(\$DOC ), .S(ADDRC), .Y(DOC)); + \$__ABC9_LUT6 dod (.A(\$DOD ), .S(ADDRD), .Y(DOD)); +endmodule + module SRL16E ( output Q, (* techmap_autopurge *) input A0, A1, A2, A3, CE, CLK, D diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index de2068bc5..cc180f2b9 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -28,6 +28,33 @@ module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1_ _TECHMAP_REPL (* techmap_celltype = "$_DFF_PN1_" *) module _90_dff_pn1_to_pp1 (input D, C, R, output Q); \$_DFF_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$__DFFE_NN0" *) +module _90_dffe_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFE_PN0" *) +module _90_dffe_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFE_NN1" *) +module _90_dffe_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFE_PN1" *) +module _90_dffe_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule + +(* techmap_celltype = "$__DFFS_NN0_" *) +module _90_dffs_nn0_to_np0 (input D, C, R, output Q); \$__DFFS_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$__DFFS_PN0_" *) +module _90_dffs_pn0_to_pp0 (input D, C, R, output Q); \$__DFFS_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$__DFFS_NN1_" *) +module _90_dffs_nn1_to_np1 (input D, C, R, output Q); \$__DFFS_NP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$__DFFS_PN1_" *) +module _90_dffs_pn1_to_pp1 (input D, C, R, output Q); \$__DFFS_PP1_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule + +(* techmap_celltype = "$__DFFSE_NN0" *) +module _90_dffse_nn0_to_np0 (input D, C, R, E, output Q); \$__DFFSE_NP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFSE_PN0" *) +module _90_dffse_pn0_to_pp0 (input D, C, R, E, output Q); \$__DFFSE_PP0 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFSE_NN1" *) +module _90_dffse_nn1_to_np1 (input D, C, R, E, output Q); \$__DFFSE_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule +(* techmap_celltype = "$__DFFSE_PN1" *) +module _90_dffse_pn1_to_pp1 (input D, C, R, E, output Q); \$__DFFSE_PP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R), .E(E)); endmodule + module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; parameter [DEPTH-1:0] INIT = 0; diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 3ed0759db..c27b0f02b 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -227,6 +227,14 @@ module MUXCY(output O, input CI, DI, S); assign O = S ? CI : DI; endmodule +module MUXF5(output O, input I0, I1, S); + assign O = S ? I1 : I0; +endmodule + +module MUXF6(output O, input I0, I1, S); + assign O = S ? I1 : I0; +endmodule + (* abc9_box_id = 1, lib_whitebox *) module MUXF7(output O, input I0, I1, S); assign O = S ? I1 : I0; @@ -237,6 +245,10 @@ module MUXF8(output O, input I0, I1, S); assign O = S ? I1 : I0; endmodule +module MUXF9(output O, input I0, I1, S); + assign O = S ? I1 : I0; +endmodule + module XORCY(output O, input CI, LI); assign O = CI ^ LI; endmodule @@ -258,6 +270,26 @@ module CARRY4( assign CO[3] = S[3] ? CO[2] : DI[3]; endmodule +module CARRY8( + output [7:0] CO, + output [7:0] O, + input CI, + input CI_TOP, + input [7:0] DI, S +); + parameter CARRY_TYPE = "SINGLE_CY8"; + wire CI4 = (CARRY_TYPE == "DUAL_CY4" ? CI_TOP : CO[3]); + assign O = S ^ {CO[6:4], CI4, CO[2:0], CI}; + assign CO[0] = S[0] ? CI : DI[0]; + assign CO[1] = S[1] ? CO[0] : DI[1]; + assign CO[2] = S[2] ? CO[1] : DI[2]; + assign CO[3] = S[3] ? CO[2] : DI[3]; + assign CO[4] = S[4] ? CI4 : DI[4]; + assign CO[5] = S[5] ? CO[4] : DI[5]; + assign CO[6] = S[6] ? CO[5] : DI[6]; + assign CO[7] = S[7] ? CO[6] : DI[7]; +endmodule + `ifdef _EXPLICIT_CARRY module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S); @@ -281,6 +313,16 @@ endmodule `endif +module ORCY (output O, input CI, I); + assign O = CI | I; +endmodule + +module MULT_AND (output LO, input I0, I1); + assign LO = I0 & I1; +endmodule + +// Flip-flops and latches. + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLL_L.sdf#L238-L250 module FDRE ( @@ -329,6 +371,41 @@ module FDSE ( endcase endgenerate endmodule +module FDRSE ( + output reg Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + (* invertible_pin = "IS_CE_INVERTED" *) + input CE, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_R_INVERTED" *) + input R, + (* invertible_pin = "IS_S_INVERTED" *) + input S +); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_CE_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_R_INVERTED = 1'b0; + parameter [0:0] IS_S_INVERTED = 1'b0; + initial Q <= INIT; + wire c = C ^ IS_C_INVERTED; + wire ce = CE ^ IS_CE_INVERTED; + wire d = D ^ IS_D_INVERTED; + wire r = R ^ IS_R_INVERTED; + wire s = S ^ IS_S_INVERTED; + always @(posedge c) + if (r) + Q <= 0; + else if (s) + Q <= 1; + else if (ce) + Q <= d; +endmodule + module FDCE ( (* abc9_arrival=303 *) output reg Q, @@ -379,6 +456,51 @@ module FDPE ( endcase endgenerate endmodule +module FDCPE ( + output wire Q, + (* clkbuf_sink *) + (* invertible_pin = "IS_C_INVERTED" *) + input C, + input CE, + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR, + input D, + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE +); + parameter [0:0] INIT = 1'b0; + parameter [0:0] IS_C_INVERTED = 1'b0; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + wire c = C ^ IS_C_INVERTED; + wire clr = CLR ^ IS_CLR_INVERTED; + wire pre = PRE ^ IS_PRE_INVERTED; + // Hacky model to avoid simulation-synthesis mismatches. + reg qc, qp, qs; + initial qc = INIT; + initial qp = INIT; + initial qs = 0; + always @(posedge c, posedge clr) begin + if (clr) + qc <= 0; + else if (CE) + qc <= D; + end + always @(posedge c, posedge pre) begin + if (pre) + qp <= 1; + else if (CE) + qp <= D; + end + always @* begin + if (clr) + qs <= 0; + else if (pre) + qs <= 1; + end + assign Q = qs ? qp : qc; +endmodule + module FDRE_1 ( (* abc9_arrival=303 *) output reg Q, @@ -445,8 +567,8 @@ module LDCE ( wire clr = CLR ^ IS_CLR_INVERTED; wire g = G ^ IS_G_INVERTED; always @* - if (clr) Q = 1'b0; - else if (GE && g) Q = D; + if (clr) Q <= 1'b0; + else if (GE && g) Q <= D; endmodule module LDPE ( @@ -467,8 +589,59 @@ module LDPE ( wire g = G ^ IS_G_INVERTED; wire pre = PRE ^ IS_PRE_INVERTED; always @* - if (pre) Q = 1'b1; - else if (GE && g) Q = D; + if (pre) Q <= 1'b1; + else if (GE && g) Q <= D; +endmodule + +module LDCPE ( + output reg Q, + (* invertible_pin = "IS_CLR_INVERTED" *) + input CLR, + (* invertible_pin = "IS_D_INVERTED" *) + input D, + (* invertible_pin = "IS_G_INVERTED" *) + input G, + (* invertible_pin = "IS_GE_INVERTED" *) + input GE, + (* invertible_pin = "IS_PRE_INVERTED" *) + input PRE +); + parameter [0:0] INIT = 1'b1; + parameter [0:0] IS_CLR_INVERTED = 1'b0; + parameter [0:0] IS_D_INVERTED = 1'b0; + parameter [0:0] IS_G_INVERTED = 1'b0; + parameter [0:0] IS_GE_INVERTED = 1'b0; + parameter [0:0] IS_PRE_INVERTED = 1'b0; + initial Q = INIT; + wire d = D ^ IS_D_INVERTED; + wire g = G ^ IS_G_INVERTED; + wire ge = GE ^ IS_GE_INVERTED; + wire clr = CLR ^ IS_CLR_INVERTED; + wire pre = PRE ^ IS_PRE_INVERTED; + always @* + if (clr) Q <= 1'b0; + else if (pre) Q <= 1'b1; + else if (ge && g) Q <= d; +endmodule + +module AND2B1L ( + output O, + input DI, + (* invertible_pin = "IS_SRI_INVERTED" *) + input SRI +); + parameter [0:0] IS_SRI_INVERTED = 1'b0; + assign O = DI & ~(SRI ^ IS_SRI_INVERTED); +endmodule + +module OR2L ( + output O, + input DI, + (* invertible_pin = "IS_SRI_INVERTED" *) + input SRI +); + parameter [0:0] IS_SRI_INVERTED = 1'b0; + assign O = DI | (SRI ^ IS_SRI_INVERTED); endmodule // LUTRAM. @@ -939,8 +1112,8 @@ module RAM16X1D_1 ( endmodule module RAM32X1D ( - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 - (* abc9_arrival=1153 *) + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 + (* abc9_arrival=1188 *) output DPO, SPO, input D, (* clkbuf_sink *) @@ -962,8 +1135,8 @@ module RAM32X1D ( endmodule module RAM32X1D_1 ( - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 - (* abc9_arrival=1153 *) + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 + (* abc9_arrival=1188 *) output DPO, SPO, input D, (* clkbuf_sink *) @@ -985,7 +1158,7 @@ module RAM32X1D_1 ( endmodule module RAM64X1D ( - // 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#L889 (* abc9_arrival=1153 *) output DPO, SPO, input D, @@ -1008,7 +1181,7 @@ module RAM64X1D ( endmodule module RAM64X1D_1 ( - // 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#L889 (* abc9_arrival=1153 *) output DPO, SPO, input D, @@ -1031,8 +1204,9 @@ module RAM64X1D_1 ( endmodule module RAM128X1D ( - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 - (* abc9_arrival=1153 *) + // 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, input D, (* clkbuf_sink *) @@ -1071,18 +1245,20 @@ endmodule // Multi port. module RAM32M ( + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L857 + (* abc9_arrival=1188 *) output [1:0] DOA, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L925 + (* abc9_arrival=1187 *) output [1:0] DOB, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L993 + (* abc9_arrival=1180 *) output [1:0] DOC, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1061 + (* abc9_arrival=1190 *) output [1:0] DOD, - input [4:0] ADDRA, - input [4:0] ADDRB, - input [4:0] ADDRC, - input [4:0] ADDRD, - input [1:0] DIA, - input [1:0] DIB, - input [1:0] DIC, - input [1:0] DID, + input [4:0] ADDRA, ADDRB, ADDRC, ADDRD, + input [1:0] DIA, DIB, DIC, DID, (* clkbuf_sink *) (* invertible_pin = "IS_WCLK_INVERTED" *) input WCLK, @@ -1181,18 +1357,20 @@ module RAM32M16 ( 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, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L957 + (* abc9_arrival=1161 *) output DOB, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L1025 + (* abc9_arrival=1158 *) 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 [4:0] ADDRA, - input [4:0] ADDRB, - input [4:0] ADDRC, - input [4:0] ADDRD, - input DIA, - input DIB, - input DIC, - input DID, + input [5:0] ADDRA, ADDRB, ADDRC, ADDRD, + input DIA, DIB, DIC, DID, (* clkbuf_sink *) (* invertible_pin = "IS_WCLK_INVERTED" *) input WCLK, @@ -1230,14 +1408,14 @@ module RAM64M8 ( output DOF, output DOG, output DOH, - input [4:0] ADDRA, - input [4:0] ADDRB, - input [4:0] ADDRC, - input [4:0] ADDRD, - input [4:0] ADDRE, - input [4:0] ADDRF, - input [4:0] ADDRG, - input [4:0] ADDRH, + input [5:0] ADDRA, + input [5:0] ADDRB, + input [5:0] ADDRC, + input [5:0] ADDRD, + input [5:0] ADDRE, + input [5:0] ADDRF, + input [5:0] ADDRG, + input [5:0] ADDRH, input DIA, input DIB, input DIC, @@ -1334,8 +1512,22 @@ endmodule // Shift registers. +module SRL16 ( + output Q, + input A0, A1, A2, A3, + (* clkbuf_sink *) + input CLK, + input D +); + parameter [15:0] INIT = 16'h0000; + + reg [15:0] r = INIT; + assign Q = r[{A3,A2,A1,A0}]; + always @(posedge CLK) r <= { r[14:0], D }; +endmodule + module SRL16E ( - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 (* abc9_arrival=1472 *) output Q, input A0, A1, A2, A3, CE, @@ -1358,6 +1550,22 @@ module SRL16E ( endgenerate endmodule +module SRLC16 ( + output Q, + output Q15, + input A0, A1, A2, A3, + (* clkbuf_sink *) + input CLK, + input D +); + parameter [15:0] INIT = 16'h0000; + + reg [15:0] r = INIT; + assign Q15 = r[15]; + assign Q = r[{A3,A2,A1,A0}]; + always @(posedge CLK) r <= { r[14:0], D }; +endmodule + module SRLC16E ( output Q, output Q15, @@ -1383,9 +1591,10 @@ module SRLC16E ( endmodule module SRLC32E ( - // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904-L905 + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L905 (* abc9_arrival=1472 *) output Q, + // Max delay from: https://github.com/SymbiFlow/prjxray-db/blob/34ea6eb08a63d21ec16264ad37a0a7b142ff6031/artix7/timings/CLBLM_R.sdf#L904 (* abc9_arrival=1114 *) output Q31, input [4:0] A, @@ -1410,6 +1619,31 @@ module SRLC32E ( endgenerate endmodule +module CFGLUT5 ( + output CDO, + output O5, + output O6, + input I4, + input I3, + input I2, + input I1, + input I0, + input CDI, + input CE, + (* clkbuf_sink *) + (* invertible_pin = "IS_CLK_INVERTED" *) + input CLK +); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + wire clk = CLK ^ IS_CLK_INVERTED; + reg [31:0] r = INIT; + assign CDO = r[31]; + assign O5 = r[{1'b0, I3, I2, I1, I0}]; + assign O6 = r[{I4, I3, I2, I1, I0}]; + always @(posedge clk) if (CE) r <= {r[30:0], CDI}; +endmodule + // DSP // Virtex 2, Virtex 2 Pro, Spartan 3. @@ -1885,7 +2119,7 @@ always @* begin 2'b00: XMUX <= 0; 2'b01: XMUX <= M; 2'b10: XMUX <= P; - 2'b11: XMUX <= {D_OUT[11:0], B1_OUT, A1_OUT}; + 2'b11: XMUX <= {D_OUT[11:0], A1_OUT, B1_OUT}; default: XMUX <= 48'hxxxxxxxxxxxx; endcase end @@ -1903,8 +2137,8 @@ end // The post-adder. wire signed [48:0] X_EXT; wire signed [48:0] Z_EXT; -assign X_EXT = XMUX; -assign Z_EXT = ZMUX; +assign X_EXT = {1'b0, XMUX}; +assign Z_EXT = {1'b0, ZMUX}; assign {CARRYOUT_IN, P_IN} = OPMODE_OUT[7] ? (Z_EXT - (X_EXT + CARRYIN_OUT)) : (Z_EXT + X_EXT + CARRYIN_OUT); // Cascade outputs. @@ -2002,7 +2236,7 @@ module DSP48E1 ( parameter [6:0] IS_OPMODE_INVERTED = 7'b0; initial begin -`ifdef __ICARUS__ +`ifndef YOSYS if (AUTORESET_PATDET != "NO_RESET") $fatal(1, "Unsupported AUTORESET_PATDET value"); if (SEL_MASK != "MASK") $fatal(1, "Unsupported SEL_MASK value"); if (SEL_PATTERN != "PATTERN") $fatal(1, "Unsupported SEL_PATTERN value"); @@ -2165,12 +2399,12 @@ module DSP48E1 ( case (OPMODEr[1:0]) 2'b00: X = 48'b0; 2'b01: begin X = $signed(Mrx); -`ifdef __ICARUS__ +`ifndef YOSYS if (OPMODEr[3:2] != 2'b01) $fatal(1, "OPMODEr[3:2] must be 2'b01 when OPMODEr[1:0] is 2'b01"); `endif end 2'b10: begin X = P; -`ifdef __ICARUS__ +`ifndef YOSYS if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[1:0] is 2'b10"); `endif end @@ -2182,7 +2416,7 @@ module DSP48E1 ( case (OPMODEr[3:2]) 2'b00: Y = 48'b0; 2'b01: begin Y = 48'b0; // FIXME: more accurate partial product modelling? -`ifdef __ICARUS__ +`ifndef YOSYS if (OPMODEr[1:0] != 2'b01) $fatal(1, "OPMODEr[1:0] must be 2'b01 when OPMODEr[3:2] is 2'b01"); `endif end @@ -2196,13 +2430,13 @@ module DSP48E1 ( 3'b000: Z = 48'b0; 3'b001: Z = PCIN; 3'b010: begin Z = P; -`ifdef __ICARUS__ +`ifndef YOSYS if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] i0s 3'b010"); `endif end 3'b011: Z = Cr; 3'b100: begin Z = P; -`ifdef __ICARUS__ +`ifndef YOSYS if (PREG != 1) $fatal(1, "PREG must be 1 when OPMODEr[6:4] is 3'b100"); if (OPMODEr[3:0] != 4'b1000) $fatal(1, "OPMODEr[3:0] must be 4'b1000 when OPMODEr[6:4] i0s 3'b100"); `endif diff --git a/techlibs/xilinx/cells_xtra.py b/techlibs/xilinx/cells_xtra.py index e4c580b9d..d5c58c5d7 100644 --- a/techlibs/xilinx/cells_xtra.py +++ b/techlibs/xilinx/cells_xtra.py @@ -65,9 +65,9 @@ CELLS = [ # CLB -- registers/latches. # Virtex 1/2/4/5, Spartan 3. - Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}), - Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}), - Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}), + # Cell('FDCPE', port_attrs={'C': ['clkbuf_sink']}), + # Cell('FDRSE', port_attrs={'C': ['clkbuf_sink']}), + # Cell('LDCPE', port_attrs={'C': ['clkbuf_sink']}), # Virtex 6, Spartan 6, Series 7, Ultrascale. # Cell('FDCE'), # Cell('FDPE'), @@ -75,8 +75,8 @@ CELLS = [ # Cell('FDSE'), # Cell('LDCE'), # Cell('LDPE'), - Cell('AND2B1L'), - Cell('OR2L'), + # Cell('AND2B1L'), + # Cell('OR2L'), # CLB -- other. # Cell('LUT1'), @@ -86,23 +86,23 @@ CELLS = [ # Cell('LUT5'), # Cell('LUT6'), # Cell('LUT6_2'), - Cell('MUXF5'), - Cell('MUXF6'), + # Cell('MUXF5'), + # Cell('MUXF6'), # Cell('MUXF7'), # Cell('MUXF8'), - Cell('MUXF9'), + # Cell('MUXF9'), # Cell('CARRY4'), - Cell('CARRY8'), + # Cell('CARRY8'), # Cell('MUXCY'), # Cell('XORCY'), - Cell('ORCY'), - Cell('MULT_AND'), - Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('ORCY'), + # Cell('MULT_AND'), + # Cell('SRL16', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRL16E', port_attrs={'CLK': ['clkbuf_sink']}), - Cell('SRLC16', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('SRLC16', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRLC16E', port_attrs={'CLK': ['clkbuf_sink']}), # Cell('SRLC32E', port_attrs={'CLK': ['clkbuf_sink']}), - Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), + # Cell('CFGLUT5', port_attrs={'CLK': ['clkbuf_sink']}), # Block RAM. # Virtex. diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 8ac596459..c3e5c72f9 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -1,165 +1,5 @@ // Created by cells_xtra.py from Xilinx models -module FDCPE (...); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; - output Q; - (* clkbuf_sink *) - (* invertible_pin = "IS_C_INVERTED" *) - input C; - input CE; - (* invertible_pin = "IS_CLR_INVERTED" *) - input CLR; - input D; - (* invertible_pin = "IS_PRE_INVERTED" *) - input PRE; -endmodule - -module FDRSE (...); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_C_INVERTED = 1'b0; - parameter [0:0] IS_CE_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_R_INVERTED = 1'b0; - parameter [0:0] IS_S_INVERTED = 1'b0; - output Q; - (* clkbuf_sink *) - (* invertible_pin = "IS_C_INVERTED" *) - input C; - (* invertible_pin = "IS_CE_INVERTED" *) - input CE; - (* invertible_pin = "IS_D_INVERTED" *) - input D; - (* invertible_pin = "IS_R_INVERTED" *) - input R; - (* invertible_pin = "IS_S_INVERTED" *) - input S; -endmodule - -module LDCPE (...); - parameter [0:0] INIT = 1'b0; - parameter [0:0] IS_CLR_INVERTED = 1'b0; - parameter [0:0] IS_D_INVERTED = 1'b0; - parameter [0:0] IS_G_INVERTED = 1'b0; - parameter [0:0] IS_GE_INVERTED = 1'b0; - parameter [0:0] IS_PRE_INVERTED = 1'b0; - output Q; - (* invertible_pin = "IS_CLR_INVERTED" *) - input CLR; - (* invertible_pin = "IS_D_INVERTED" *) - input D; - (* invertible_pin = "IS_G_INVERTED" *) - input G; - (* invertible_pin = "IS_GE_INVERTED" *) - input GE; - (* invertible_pin = "IS_PRE_INVERTED" *) - input PRE; -endmodule - -module AND2B1L (...); - parameter [0:0] IS_SRI_INVERTED = 1'b0; - output O; - input DI; - (* invertible_pin = "IS_SRI_INVERTED" *) - input SRI; -endmodule - -module OR2L (...); - parameter [0:0] IS_SRI_INVERTED = 1'b0; - output O; - input DI; - (* invertible_pin = "IS_SRI_INVERTED" *) - input SRI; -endmodule - -module MUXF5 (...); - output O; - input I0; - input I1; - input S; -endmodule - -module MUXF6 (...); - output O; - input I0; - input I1; - input S; -endmodule - -module MUXF9 (...); - output O; - input I0; - input I1; - input S; -endmodule - -module CARRY8 (...); - parameter CARRY_TYPE = "SINGLE_CY8"; - output [7:0] CO; - output [7:0] O; - input CI; - input CI_TOP; - input [7:0] DI; - input [7:0] S; -endmodule - -module ORCY (...); - output O; - input CI; - input I; -endmodule - -module MULT_AND (...); - output LO; - input I0; - input I1; -endmodule - -module SRL16 (...); - parameter [15:0] INIT = 16'h0000; - output Q; - input A0; - input A1; - input A2; - input A3; - (* clkbuf_sink *) - input CLK; - input D; -endmodule - -module SRLC16 (...); - parameter [15:0] INIT = 16'h0000; - output Q; - output Q15; - input A0; - input A1; - input A2; - input A3; - (* clkbuf_sink *) - input CLK; - input D; -endmodule - -module CFGLUT5 (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output CDO; - output O5; - output O6; - input I4; - input I3; - input I2; - input I1; - input I0; - input CDI; - input CE; - (* clkbuf_sink *) - (* invertible_pin = "IS_CLK_INVERTED" *) - input CLK; -endmodule - module RAMB16_S1 (...); parameter [0:0] INIT = 1'h0; parameter [0:0] SRVAL = 1'h0; diff --git a/techlibs/xilinx/lutrams.txt b/techlibs/xilinx/lutrams.txt index 2613c206c..29f6b05cc 100644 --- a/techlibs/xilinx/lutrams.txt +++ b/techlibs/xilinx/lutrams.txt @@ -1,4 +1,17 @@ +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 @@ -38,6 +51,70 @@ bram $__XILINX_RAM128X1D clkpol 0 2 endbram + +bram $__XILINX_RAM32X6SDP + init 1 + abits 5 + dbits 6 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + +bram $__XILINX_RAM64X3SDP + init 1 + abits 6 + dbits 3 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + +bram $__XILINX_RAM32X2Q + init 1 + abits 5 + dbits 2 + groups 2 + ports 3 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +endbram + +bram $__XILINX_RAM64X1Q + init 1 + abits 6 + dbits 1 + groups 2 + ports 3 1 + wrmode 0 1 + enable 0 1 + transp 0 0 + clocks 0 1 + clkpol 0 2 +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 @@ -56,5 +133,35 @@ match $__XILINX_RAM128X1D min bits 9 min wports 1 make_outreg + or_next_if_better +endmatch + + +match $__XILINX_RAM32X6SDP + min bits 5 + min wports 1 + make_outreg + or_next_if_better +endmatch + +match $__XILINX_RAM64X3SDP + min bits 6 + min wports 1 + make_outreg + or_next_if_better +endmatch + +match $__XILINX_RAM32X2Q + min bits 5 + min rports 3 + min wports 1 + make_outreg + or_next_if_better endmatch +match $__XILINX_RAM64X1Q + min bits 5 + min rports 3 + min wports 1 + make_outreg +endmatch diff --git a/techlibs/xilinx/lutrams_map.v b/techlibs/xilinx/lutrams_map.v index 77041ca86..3ac1143bb 100644 --- a/techlibs/xilinx/lutrams_map.v +++ b/techlibs/xilinx/lutrams_map.v @@ -1,4 +1,36 @@ +module \$__XILINX_RAM16X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [15:0] INIT = 16'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [3:0] A1ADDR; + output A1DATA; + + input [3:0] B1ADDR; + input B1DATA; + input B1EN; + + RAM16X1D #( + .INIT(INIT), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .DPRA0(A1ADDR[0]), + .DPRA1(A1ADDR[1]), + .DPRA2(A1ADDR[2]), + .DPRA3(A1ADDR[3]), + .DPO(A1DATA), + + .A0(B1ADDR[0]), + .A1(B1ADDR[1]), + .A2(B1ADDR[2]), + .A3(B1ADDR[3]), + .D(B1DATA), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); parameter [31:0] INIT = 32'bx; parameter CLKPOL2 = 1; @@ -95,3 +127,153 @@ module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); ); endmodule + +module \$__XILINX_RAM32X6SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [32*6-1:0] INIT = {32*6{1'bx}}; + parameter CLKPOL2 = 1; + input CLK1; + + input [4:0] A1ADDR; + output [5:0] A1DATA; + + input [4:0] B1ADDR; + input [5:0] B1DATA; + input B1EN; + + wire [1:0] DOD_unused; + + RAM32M #( + .INIT_A({INIT[187:186], INIT[181:180], INIT[175:174], INIT[169:168], INIT[163:162], INIT[157:156], INIT[151:150], INIT[145:144], INIT[139:138], INIT[133:132], INIT[127:126], INIT[121:120], INIT[115:114], INIT[109:108], INIT[103:102], INIT[ 97: 96], INIT[ 91: 90], INIT[ 85: 84], INIT[ 79: 78], INIT[ 73: 72], INIT[ 67: 66], INIT[ 61: 60], INIT[ 55: 54], INIT[ 49: 48], INIT[ 43: 42], INIT[ 37: 36], INIT[ 31: 30], INIT[ 25: 24], INIT[ 19: 18], INIT[ 13: 12], INIT[ 7: 6], INIT[ 1: 0]}), + .INIT_B({INIT[189:188], INIT[183:182], INIT[177:176], INIT[171:170], INIT[165:164], INIT[159:158], INIT[153:152], INIT[147:146], INIT[141:140], INIT[135:134], INIT[129:128], INIT[123:122], INIT[117:116], INIT[111:110], INIT[105:104], INIT[ 99: 98], INIT[ 93: 92], INIT[ 87: 86], INIT[ 81: 80], INIT[ 75: 74], INIT[ 69: 68], INIT[ 63: 62], INIT[ 57: 56], INIT[ 51: 50], INIT[ 45: 44], INIT[ 39: 38], INIT[ 33: 32], INIT[ 27: 26], INIT[ 21: 20], INIT[ 15: 14], INIT[ 9: 8], INIT[ 3: 2]}), + .INIT_C({INIT[191:190], INIT[185:184], INIT[179:178], INIT[173:172], INIT[167:166], INIT[161:160], INIT[155:154], INIT[149:148], INIT[143:142], INIT[137:136], INIT[131:130], INIT[125:124], INIT[119:118], INIT[113:112], INIT[107:106], INIT[101:100], INIT[ 95: 94], INIT[ 89: 88], INIT[ 83: 82], INIT[ 77: 76], INIT[ 71: 70], INIT[ 65: 64], INIT[ 59: 58], INIT[ 53: 52], INIT[ 47: 46], INIT[ 41: 40], INIT[ 35: 34], INIT[ 29: 28], INIT[ 23: 22], INIT[ 17: 16], INIT[ 11: 10], INIT[ 5: 4]}), + .INIT_D(64'bx), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .ADDRA(A1ADDR), + .ADDRB(A1ADDR), + .ADDRC(A1ADDR), + .DOA(A1DATA[1:0]), + .DOB(A1DATA[3:2]), + .DOC(A1DATA[5:4]), + .DOD(DOD_unused), + + .ADDRD(B1ADDR), + .DIA(B1DATA[1:0]), + .DIB(B1DATA[3:2]), + .DIC(B1DATA[5:4]), + .DID(2'b00), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + +module \$__XILINX_RAM64X3SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN); + parameter [64*3-1:0] INIT = {64*3{1'bx}}; + parameter CLKPOL2 = 1; + input CLK1; + + input [5:0] A1ADDR; + output [2:0] A1DATA; + + input [5:0] B1ADDR; + input [2:0] B1DATA; + input B1EN; + + wire DOD_unused; + + RAM64M #( + .INIT_A({INIT[189], INIT[186], INIT[183], INIT[180], INIT[177], INIT[174], INIT[171], INIT[168], INIT[165], INIT[162], INIT[159], INIT[156], INIT[153], INIT[150], INIT[147], INIT[144], INIT[141], INIT[138], INIT[135], INIT[132], INIT[129], INIT[126], INIT[123], INIT[120], INIT[117], INIT[114], INIT[111], INIT[108], INIT[105], INIT[102], INIT[ 99], INIT[ 96], INIT[ 93], INIT[ 90], INIT[ 87], INIT[ 84], INIT[ 81], INIT[ 78], INIT[ 75], INIT[ 72], INIT[ 69], INIT[ 66], INIT[ 63], INIT[ 60], INIT[ 57], INIT[ 54], INIT[ 51], INIT[ 48], INIT[ 45], INIT[ 42], INIT[ 39], INIT[ 36], INIT[ 33], INIT[ 30], INIT[ 27], INIT[ 24], INIT[ 21], INIT[ 18], INIT[ 15], INIT[ 12], INIT[ 9], INIT[ 6], INIT[ 3], INIT[ 0]}), + .INIT_B({INIT[190], INIT[187], INIT[184], INIT[181], INIT[178], INIT[175], INIT[172], INIT[169], INIT[166], INIT[163], INIT[160], INIT[157], INIT[154], INIT[151], INIT[148], INIT[145], INIT[142], INIT[139], INIT[136], INIT[133], INIT[130], INIT[127], INIT[124], INIT[121], INIT[118], INIT[115], INIT[112], INIT[109], INIT[106], INIT[103], INIT[100], INIT[ 97], INIT[ 94], INIT[ 91], INIT[ 88], INIT[ 85], INIT[ 82], INIT[ 79], INIT[ 76], INIT[ 73], INIT[ 70], INIT[ 67], INIT[ 64], INIT[ 61], INIT[ 58], INIT[ 55], INIT[ 52], INIT[ 49], INIT[ 46], INIT[ 43], INIT[ 40], INIT[ 37], INIT[ 34], INIT[ 31], INIT[ 28], INIT[ 25], INIT[ 22], INIT[ 19], INIT[ 16], INIT[ 13], INIT[ 10], INIT[ 7], INIT[ 4], INIT[ 1]}), + .INIT_C({INIT[191], INIT[188], INIT[185], INIT[182], INIT[179], INIT[176], INIT[173], INIT[170], INIT[167], INIT[164], INIT[161], INIT[158], INIT[155], INIT[152], INIT[149], INIT[146], INIT[143], INIT[140], INIT[137], INIT[134], INIT[131], INIT[128], INIT[125], INIT[122], INIT[119], INIT[116], INIT[113], INIT[110], INIT[107], INIT[104], INIT[101], INIT[ 98], INIT[ 95], INIT[ 92], INIT[ 89], INIT[ 86], INIT[ 83], INIT[ 80], INIT[ 77], INIT[ 74], INIT[ 71], INIT[ 68], INIT[ 65], INIT[ 62], INIT[ 59], INIT[ 56], INIT[ 53], INIT[ 50], INIT[ 47], INIT[ 44], INIT[ 41], INIT[ 38], INIT[ 35], INIT[ 32], INIT[ 29], INIT[ 26], INIT[ 23], INIT[ 20], INIT[ 17], INIT[ 14], INIT[ 11], INIT[ 8], INIT[ 5], INIT[ 2]}), + .INIT_D(64'bx), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .ADDRA(A1ADDR), + .ADDRB(A1ADDR), + .ADDRC(A1ADDR), + .DOA(A1DATA[0]), + .DOB(A1DATA[1]), + .DOC(A1DATA[2]), + .DOD(DOD_unused), + + .ADDRD(B1ADDR), + .DIA(B1DATA[0]), + .DIB(B1DATA[1]), + .DIC(B1DATA[2]), + .DID(1'b0), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + +module \$__XILINX_RAM32X2Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN); + parameter [63:0] INIT = 64'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [4:0] A1ADDR, A2ADDR, A3ADDR; + output [1:0] A1DATA, A2DATA, A3DATA; + + input [4:0] B1ADDR; + input [1:0] B1DATA; + input B1EN; + + RAM32M #( + .INIT_A(INIT), + .INIT_B(INIT), + .INIT_C(INIT), + .INIT_D(INIT), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .ADDRA(A1ADDR), + .ADDRB(A2ADDR), + .ADDRC(A3ADDR), + .DOA(A1DATA), + .DOB(A2DATA), + .DOC(A3DATA), + + .ADDRD(B1ADDR), + .DIA(B1DATA), + .DIB(B1DATA), + .DIC(B1DATA), + .DID(B1DATA), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule + +module \$__XILINX_RAM64X1Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN); + parameter [63:0] INIT = 64'bx; + parameter CLKPOL2 = 1; + input CLK1; + + input [5:0] A1ADDR, A2ADDR, A3ADDR; + output A1DATA, A2DATA, A3DATA; + + input [5:0] B1ADDR; + input B1DATA; + input B1EN; + + RAM64M #( + .INIT_A(INIT), + .INIT_B(INIT), + .INIT_C(INIT), + .INIT_D(INIT), + .IS_WCLK_INVERTED(!CLKPOL2) + ) _TECHMAP_REPLACE_ ( + .ADDRA(A1ADDR), + .ADDRB(A2ADDR), + .ADDRC(A3ADDR), + .DOA(A1DATA), + .DOB(A2DATA), + .DOC(A3DATA), + + .ADDRD(B1ADDR), + .DIA(B1DATA), + .DIB(B1DATA), + .DIC(B1DATA), + .DID(B1DATA), + .WCLK(CLK1), + .WE(B1EN) + ); +endmodule diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 2c5686a35..b0c4795ee 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -64,7 +64,7 @@ struct SynthXilinxPass : public ScriptPass log(" (this feature is experimental and incomplete)\n"); log("\n"); log(" -ise\n"); - log(" generate an output netlist suitable for ISE (enables -iopad)\n"); + log(" generate an output netlist suitable for ISE\n"); log("\n"); log(" -nobram\n"); log(" do not use block RAM cells in output netlist\n"); @@ -84,11 +84,9 @@ struct SynthXilinxPass : public ScriptPass log(" -nodsp\n"); log(" do not use DSP48E1s to implement multipliers and associated logic\n"); log("\n"); - log(" -iopad\n"); - log(" enable I/O buffer insertion (selected automatically by -ise)\n"); - log("\n"); log(" -noiopad\n"); - log(" disable I/O buffer insertion (only useful with -ise)\n"); + log(" disable I/O buffer insertion (useful for hierarchical or \n"); + log(" out-of-context flows)\n"); log("\n"); log(" -noclkbuf\n"); log(" disable automatic clock buffer insertion\n"); @@ -110,7 +108,7 @@ struct SynthXilinxPass : public ScriptPass log(" flatten design before synthesis\n"); log("\n"); log(" -retime\n"); - log(" run 'abc' with -dff option\n"); + log(" run 'abc' with '-dff -D 1' options\n"); log("\n"); log(" -abc9\n"); log(" use new ABC9 flow (EXPERIMENTAL)\n"); @@ -122,7 +120,7 @@ struct SynthXilinxPass : public ScriptPass } std::string top_opt, edif_file, blif_file, family; - bool flatten, retime, vpr, ise, iopad, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9; + bool flatten, retime, vpr, ise, noiopad, noclkbuf, nobram, nolutram, nosrl, nocarry, nowidelut, nodsp, uram, abc9; bool flatten_before_abc; int widemux; @@ -136,7 +134,6 @@ struct SynthXilinxPass : public ScriptPass retime = false; vpr = false; ise = false; - iopad = false; noiopad = false; noclkbuf = false; nocarry = false; @@ -213,7 +210,6 @@ struct SynthXilinxPass : public ScriptPass continue; } if (args[argidx] == "-iopad") { - iopad = true; continue; } if (args[argidx] == "-noiopad") { @@ -282,7 +278,6 @@ struct SynthXilinxPass : public ScriptPass void script() YS_OVERRIDE { - bool do_iopad = iopad || (ise && !noiopad); std::string ff_map_file; if (help_mode) ff_map_file = "+/xilinx/{family}_ff_map.v"; @@ -387,7 +382,10 @@ struct SynthXilinxPass : public ScriptPass run("opt_expr -fine"); run("wreduce"); run("select -clear"); - run("xilinx_dsp"); + if (help_mode) + run("xilinx_dsp -family <family>"); + else + run("xilinx_dsp -family " + family); run("chtype -set $mul t:$__soft_mul"); } } @@ -444,6 +442,16 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("map_ffram")) { + // Required for dffsr2dff to work. + run("simplemap t:$dff t:$adff t:$mux"); + // Needs to be done before opt -mux_bool happens. + run("dffsr2dff"); + if (help_mode) + run("dff2dffs [-match-init]", "(-match-init for xc6s only)"); + else if (family == "xc6s") + run("dff2dffs -match-init"); + else + run("dff2dffs"); if (widemux > 0) run("opt -fast -mux_bool -undriven -fine"); // Necessary to omit -mux_undef otherwise muxcover // performs less efficiently @@ -453,14 +461,11 @@ struct SynthXilinxPass : public ScriptPass } if (check_label("fine")) { - run("dffsr2dff"); - run("dff2dffe"); + run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); if (help_mode) { - run("simplemap t:$mux", " ('-widemux' only)"); run("muxcover <internal options>, ('-widemux' only)"); } else if (widemux > 0) { - run("simplemap t:$mux"); constexpr int cost_mux2 = 100; std::string muxcover_args = stringf(" -nodecode -mux2=%d", cost_mux2); switch (widemux) { @@ -507,8 +512,8 @@ 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 || do_iopad) - 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 '-iopad' or '-ise' and not '-noiopad')"); + 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')"); std::string techmap_args = "-map +/techmap.v -map +/xilinx/cells_map.v"; if (widemux > 0) techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", widemux); @@ -545,9 +550,9 @@ struct SynthXilinxPass : public ScriptPass } else { if (nowidelut) - run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff -D 1" : "")); else - run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff -D 1" : "")); } run("clean"); @@ -563,6 +568,7 @@ struct SynthXilinxPass : public ScriptPass else techmap_args += " -map " + ff_map_file; run("techmap " + techmap_args); + run("xilinx_dffopt"); run("clean"); } diff --git a/techlibs/xilinx/tests/.gitignore b/techlibs/xilinx/tests/.gitignore index ef3699bd2..848f88d53 100644 --- a/techlibs/xilinx/tests/.gitignore +++ b/techlibs/xilinx/tests/.gitignore @@ -8,4 +8,8 @@ dsp_work*/ test_dsp_model_ref.v test_dsp_model_uut.v test_dsp_model +test_dsp48a_model_ref.v +test_dsp48a1_model_ref.v +test_dsp48a1_model_uut.v +test_dsp48a1_model *.vcd diff --git a/techlibs/xilinx/tests/test_dsp48a1_model.sh b/techlibs/xilinx/tests/test_dsp48a1_model.sh new file mode 100644 index 000000000..a14a78e72 --- /dev/null +++ b/techlibs/xilinx/tests/test_dsp48a1_model.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -ex +if [ -z $ISE_DIR ]; then + ISE_DIR=/opt/Xilinx/ISE/14.7 +fi +sed 's/DSP48A1/MARKER1/; s/DSP48A/DSP48A_UUT/; s/MARKER1/DSP48A1_UUT/; /module DSP48A_UUT/,/endmodule/ p; /module DSP48A1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp48a1_model_uut.v +if [ ! -f "test_dsp48a1_model_ref.v" ]; then + cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A1.v test_dsp48a1_model_ref.v +fi +if [ ! -f "test_dsp48a_model_ref.v" ]; then + cp $ISE_DIR/ISE_DS/ISE/verilog/src/unisims/DSP48A.v test_dsp48a_model_ref.v +fi +for tb in mult_allreg mult_noreg mult_inreg +do + iverilog -s $tb -s glbl -o test_dsp48a1_model test_dsp48a1_model.v test_dsp48a1_model_uut.v test_dsp48a1_model_ref.v test_dsp48a_model_ref.v $ISE_DIR/ISE_DS/ISE/verilog/src/glbl.v + vvp -N ./test_dsp48a1_model +done diff --git a/techlibs/xilinx/tests/test_dsp48a1_model.v b/techlibs/xilinx/tests/test_dsp48a1_model.v new file mode 100644 index 000000000..66346b47b --- /dev/null +++ b/techlibs/xilinx/tests/test_dsp48a1_model.v @@ -0,0 +1,331 @@ +`timescale 1ns / 1ps + +module testbench; + parameter integer A0REG = 1; + parameter integer A1REG = 1; + parameter integer B0REG = 1; + parameter integer B1REG = 1; + parameter integer CREG = 1; + parameter integer DREG = 1; + parameter integer MREG = 1; + parameter integer PREG = 1; + parameter integer CARRYINREG = 1; + parameter integer CARRYOUTREG = 1; + parameter integer OPMODEREG = 1; + parameter CARRYINSEL = "OPMODE5"; + parameter RSTTYPE = "SYNC"; + + reg CLK; + reg CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE; + reg RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE; + reg [17:0] A; + reg [17:0] B; + reg [47:0] C; + reg [17:0] D; + reg [47:0] PCIN; + reg [7:0] OPMODE; + reg CARRYIN; + + output CARRYOUTF, REF_CARRYOUTF; + output CARRYOUT, REF_CARRYOUT, REF_OLD_CARRYOUT; + output [35:0] M, REF_M; + output [47:0] P, REF_P, REF_OLD_P; + output [17:0] BCOUT, REF_BCOUT, REF_OLD_BCOUT; + output [47:0] PCOUT, REF_PCOUT, REF_OLD_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 || REF_OLD_BCOUT != BCOUT) begin + $display("ERROR at %1t: REF_BCOUT=%b REF_OLD_BCOUT=%b UUT_BCOUT=%b DIFF=%b", $time, REF_BCOUT, REF_OLD_BCOUT, BCOUT, REF_BCOUT ^ BCOUT); + errcount = errcount + 1; + ERROR_FLAG = 1; + end + if (REF_M !== M) begin + $display("ERROR at %1t: REF_M=%b UUT_M=%b DIFF=%b", $time, REF_M, M, REF_M ^ M); + errcount = errcount + 1; + ERROR_FLAG = 1; + end + if (REF_P !== P || REF_OLD_P != P) begin + $display("ERROR at %1t: REF_P=%b REF_OLD_P=%b UUT_P=%b DIFF=%b", $time, REF_P, REF_OLD_P, P, REF_P ^ P); + errcount = errcount + 1; + ERROR_FLAG = 1; + end + if (REF_PCOUT !== PCOUT || REF_OLD_PCOUT != PCOUT) begin + $display("ERROR at %1t: REF_PCOUT=%b REF_OLD_PCOUT=%b UUT_PCOUT=%b DIFF=%b", $time, REF_PCOUT, REF_OLD_PCOUT, PCOUT, REF_PCOUT ^ PCOUT); + errcount = errcount + 1; + ERROR_FLAG = 1; + end + if (REF_CARRYOUT !== CARRYOUT || (REF_OLD_CARRYOUT != CARRYOUT && !CARRYOUTREG)) begin + $display("ERROR at %1t: REF_CARRYOUT=%b REF_OLD_CARRYOUT=%b UUT_CARRYOUT=%b DIFF=%b", $time, REF_CARRYOUT, REF_OLD_CARRYOUT, CARRYOUT, REF_CARRYOUT ^ CARRYOUT); + errcount = errcount + 1; + ERROR_FLAG = 1; + end + if (REF_CARRYOUTF !== CARRYOUTF) begin + $display("ERROR at %1t: REF_CARRYOUTF=%b UUT_CARRYOUTF=%b", $time, REF_CARRYOUTF, CARRYOUTF); + 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[3:2] == 2'b10 && PREG != 1) config_valid = 0; + end + endtask + + initial begin + $dumpfile("test_dsp48a1_model.vcd"); + $dumpvars(0, testbench); + + #2; + CLK = 1'b0; + {CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = 8'b11111111; + {A, B, C, D, PCIN, OPMODE, CARRYIN} = 0; + {RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 8'b11111111; + repeat (10) begin + #10; + CLK = 1'b1; + #10; + CLK = 1'b0; + #10; + CLK = 1'b1; + #10; + CLK = 1'b0; + end + {RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = 0; + + repeat (10000) begin + clkcycle; + config_valid = 0; + while (!config_valid) begin + A = $urandom; + B = $urandom; + C = {$urandom, $urandom}; + D = $urandom; + PCIN = {$urandom, $urandom}; + + {CEA, CEB, CEC, CED, CEM, CEP, CECARRYIN, CEOPMODE} = $urandom | $urandom | $urandom; + {RSTA, RSTB, RSTC, RSTD, RSTM, RSTP, RSTCARRYIN, RSTOPMODE} = $urandom & $urandom & $urandom & $urandom & $urandom & $urandom; + {CARRYIN, OPMODE} = $urandom; + + drc; + end + end + + if (errcount == 0) begin + $display("All tests passed."); + $finish; + end else begin + $display("Caught %1d errors.", errcount); + $stop; + end + end + + DSP48A #( + .A0REG (A0REG), + .A1REG (A1REG), + .B0REG (B0REG), + .B1REG (B1REG), + .CREG (CREG), + .DREG (DREG), + .MREG (MREG), + .PREG (PREG), + .CARRYINREG (CARRYINREG), + .OPMODEREG (OPMODEREG), + .CARRYINSEL (CARRYINSEL), + .RSTTYPE (RSTTYPE) + ) ref_old ( + .A (A), + .B (B), + .C (C), + .D (D), + .PCIN (PCIN), + .CARRYIN (CARRYIN), + .OPMODE (OPMODE), + .BCOUT (REF_OLD_BCOUT), + .CARRYOUT (REF_OLD_CARRYOUT), + .P (REF_OLD_P), + .PCOUT (REF_OLD_PCOUT), + .CEA (CEA), + .CEB (CEB), + .CEC (CEC), + .CED (CED), + .CEM (CEM), + .CEP (CEP), + .CECARRYIN (CECARRYIN), + .CEOPMODE (CEOPMODE), + .CLK (CLK), + .RSTA (RSTA), + .RSTB (RSTB), + .RSTC (RSTC), + .RSTD (RSTD), + .RSTM (RSTM), + .RSTP (RSTP), + .RSTCARRYIN (RSTCARRYIN), + .RSTOPMODE (RSTOPMODE) + ); + + DSP48A1 #( + .A0REG (A0REG), + .A1REG (A1REG), + .B0REG (B0REG), + .B1REG (B1REG), + .CREG (CREG), + .DREG (DREG), + .MREG (MREG), + .PREG (PREG), + .CARRYINREG (CARRYINREG), + .CARRYOUTREG (CARRYOUTREG), + .OPMODEREG (OPMODEREG), + .CARRYINSEL (CARRYINSEL), + .RSTTYPE (RSTTYPE) + ) ref ( + .A (A), + .B (B), + .C (C), + .D (D), + .PCIN (PCIN), + .CARRYIN (CARRYIN), + .OPMODE (OPMODE), + .BCOUT (REF_BCOUT), + .CARRYOUTF (REF_CARRYOUTF), + .CARRYOUT (REF_CARRYOUT), + .P (REF_P), + .M (REF_M), + .PCOUT (REF_PCOUT), + .CEA (CEA), + .CEB (CEB), + .CEC (CEC), + .CED (CED), + .CEM (CEM), + .CEP (CEP), + .CECARRYIN (CECARRYIN), + .CEOPMODE (CEOPMODE), + .CLK (CLK), + .RSTA (RSTA), + .RSTB (RSTB), + .RSTC (RSTC), + .RSTD (RSTD), + .RSTM (RSTM), + .RSTP (RSTP), + .RSTCARRYIN (RSTCARRYIN), + .RSTOPMODE (RSTOPMODE) + ); + + DSP48A1_UUT #( + .A0REG (A0REG), + .A1REG (A1REG), + .B0REG (B0REG), + .B1REG (B1REG), + .CREG (CREG), + .DREG (DREG), + .MREG (MREG), + .PREG (PREG), + .CARRYINREG (CARRYINREG), + .CARRYOUTREG (CARRYOUTREG), + .OPMODEREG (OPMODEREG), + .CARRYINSEL (CARRYINSEL), + .RSTTYPE (RSTTYPE) + ) uut ( + .A (A), + .B (B), + .C (C), + .D (D), + .PCIN (PCIN), + .CARRYIN (CARRYIN), + .OPMODE (OPMODE), + .BCOUT (BCOUT), + .CARRYOUTF (CARRYOUTF), + .CARRYOUT (CARRYOUT), + .P (P), + .M (M), + .PCOUT (PCOUT), + .CEA (CEA), + .CEB (CEB), + .CEC (CEC), + .CED (CED), + .CEM (CEM), + .CEP (CEP), + .CECARRYIN (CECARRYIN), + .CEOPMODE (CEOPMODE), + .CLK (CLK), + .RSTA (RSTA), + .RSTB (RSTB), + .RSTC (RSTC), + .RSTD (RSTD), + .RSTM (RSTM), + .RSTP (RSTP), + .RSTCARRYIN (RSTCARRYIN), + .RSTOPMODE (RSTOPMODE) + ); +endmodule + +module mult_noreg; + testbench #( + .A0REG (0), + .A1REG (0), + .B0REG (0), + .B1REG (0), + .CREG (0), + .DREG (0), + .MREG (0), + .PREG (0), + .CARRYINREG (0), + .CARRYOUTREG (0), + .OPMODEREG (0), + .CARRYINSEL ("CARRYIN"), + .RSTTYPE ("SYNC") + ) testbench (); +endmodule + +module mult_allreg; + testbench #( + .A0REG (1), + .A1REG (1), + .B0REG (1), + .B1REG (1), + .CREG (1), + .DREG (1), + .MREG (1), + .PREG (1), + .CARRYINREG (1), + .CARRYOUTREG (1), + .OPMODEREG (1), + .CARRYINSEL ("OPMODE5"), + .RSTTYPE ("SYNC") + ) testbench (); +endmodule + +module mult_inreg; + testbench #( + .A0REG (1), + .A1REG (1), + .B0REG (1), + .B1REG (1), + .CREG (1), + .DREG (1), + .MREG (0), + .PREG (0), + .CARRYINREG (1), + .CARRYOUTREG (0), + .OPMODEREG (0), + .CARRYINSEL ("CARRYIN"), + .RSTTYPE ("SYNC") + ) testbench (); +endmodule diff --git a/techlibs/xilinx/tests/test_dsp_model.sh b/techlibs/xilinx/tests/test_dsp_model.sh index ae925c402..d005cd40c 100644 --- a/techlibs/xilinx/tests/test_dsp_model.sh +++ b/techlibs/xilinx/tests/test_dsp_model.sh @@ -1,14 +1,17 @@ #!/bin/bash set -ex +if [ -z $VIVADO_DIR ]; then + VIVADO_DIR=/opt/Xilinx/Vivado/2019.1 +fi sed 's/DSP48E1/DSP48E1_UUT/; /DSP48E1_UUT/,/endmodule/ p; d;' < ../cells_sim.v > test_dsp_model_uut.v if [ ! -f "test_dsp_model_ref.v" ]; then - cat /opt/Xilinx/Vivado/2019.1/data/verilog/src/unisims/DSP48E1.v > test_dsp_model_ref.v + cp $VIVADO_DIR/data/verilog/src/unisims/DSP48E1.v test_dsp_model_ref.v fi for tb in macc_overflow_underflow \ - simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \ - mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \ + simd24_preadd_noreg_nocasc simd12_preadd_noreg_nocasc \ + mult_allreg_nopreadd_nocasc mult_noreg_nopreadd_nocasc \ mult_allreg_preadd_nocasc mult_noreg_preadd_nocasc mult_inreg_preadd_nocasc do - iverilog -s $tb -s glbl -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v /opt/Xilinx/Vivado/2019.1/data/verilog/src/glbl.v + iverilog -s $tb -s glbl -o test_dsp_model test_dsp_model.v test_dsp_model_uut.v test_dsp_model_ref.v $VIVADO_DIR/data/verilog/src/glbl.v vvp -N ./test_dsp_model done diff --git a/techlibs/xilinx/xc3sda_dsp_map.v b/techlibs/xilinx/xc3sda_dsp_map.v index 87348a173..258f90395 100644 --- a/techlibs/xilinx/xc3sda_dsp_map.v +++ b/techlibs/xilinx/xc3sda_dsp_map.v @@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); .D(18'b0), .P(P_48), - .OPMODE(8'b0000010) + .OPMODE(8'b0000001) ); assign Y = P_48; endmodule diff --git a/techlibs/xilinx/xc6s_dsp_map.v b/techlibs/xilinx/xc6s_dsp_map.v index e8705723b..bdce60c14 100644 --- a/techlibs/xilinx/xc6s_dsp_map.v +++ b/techlibs/xilinx/xc6s_dsp_map.v @@ -27,7 +27,7 @@ module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); .D(18'b0), .P(P_48), - .OPMODE(8'b0000010) + .OPMODE(8'b0000001) ); assign Y = P_48; endmodule diff --git a/techlibs/xilinx/xc6s_ff_map.v b/techlibs/xilinx/xc6s_ff_map.v index bf35b09e5..c40f446e0 100644 --- a/techlibs/xilinx/xc6s_ff_map.v +++ b/techlibs/xilinx/xc6s_ff_map.v @@ -27,6 +27,8 @@ `ifndef _NO_FFS +// No reset. + module \$_DFF_N_ (input D, C, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) @@ -46,6 +48,8 @@ module \$_DFF_P_ (input D, C, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +// No reset, enable. + module \$_DFFE_NP_ (input D, C, E, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) @@ -65,80 +69,168 @@ module \$_DFFE_PP_ (input D, C, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); +// Async reset. + +module \$_DFF_NP0_ (input D, C, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); else - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); +module \$_DFF_PP0_ (input D, C, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); else - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); + +module \$_DFF_NP1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + else + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Async reset, enable. + +module \$__DFFE_NP0 (input D, C, E, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); else - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); +module \$__DFFE_PP0 (input D, C, E, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) $error("Spartan 6 doesn't support FFs with asynchronous reset initialized to 1"); else - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); +module \$__DFFE_NP1 (input D, C, E, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); else - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); +module \$__DFFE_PP1 (input D, C, E, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); else - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Sync reset. + +module \$__DFFS_NP0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with reset initialized to 1"); + else + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); +module \$__DFFS_PP0_ (input D, C, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with reset initialized to 1"); + else + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$__DFFS_NP1_ (input D, C, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + $error("Spartan 6 doesn't support FFs with set initialized to 0"); else - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); +module \$__DFFS_PP1_ (input D, C, R, output Q); parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) - $error("Spartan 6 doesn't support FFs with asynchronous set initialized to 0"); + $error("Spartan 6 doesn't support FFs with set initialized to 0"); else - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); endgenerate wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +// Sync reset, enable. + +module \$__DFFSE_NP0 (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with reset initialized to 1"); + else + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$__DFFSE_PP0 (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) + $error("Spartan 6 doesn't support FFs with reset initialized to 1"); + else + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$__DFFSE_NP1 (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with set initialized to 0"); + else + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$__DFFSE_PP1 (input D, C, E, R, output Q); + parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx; + generate if (_TECHMAP_WIREINIT_Q_ === 1'b0) + $error("Spartan 6 doesn't support FFs with set initialized to 0"); + else + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); + endgenerate + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Latches (no reset). + module \$_DLATCH_N_ (input E, D, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; generate if (_TECHMAP_WIREINIT_Q_ === 1'b1) @@ -158,5 +250,7 @@ module \$_DLATCH_P_ (input E, D, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +// Latches with reset (TODO). + `endif diff --git a/techlibs/xilinx/xc7_ff_map.v b/techlibs/xilinx/xc7_ff_map.v index 32ca9f560..2bd874457 100644 --- a/techlibs/xilinx/xc7_ff_map.v +++ b/techlibs/xilinx/xc7_ff_map.v @@ -37,6 +37,8 @@ `ifndef _NO_FFS +// No reset. + module \$_DFF_N_ (input D, C, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); @@ -48,6 +50,8 @@ module \$_DFF_P_ (input D, C, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +// No reset, enable. + module \$_DFFE_NP_ (input D, C, E, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); @@ -59,47 +63,103 @@ module \$_DFFE_PP_ (input D, C, E, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NN0_ (input D, C, R, output Q); +// Async reset. + +module \$_DFF_NP0_ (input D, C, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); +module \$_DFF_PP0_ (input D, C, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); + +module \$_DFF_NP1_ (input D, C, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); +module \$_DFF_PP1_ (input D, C, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); +// Async reset, enable. + +module \$__DFFE_NP0 (input D, C, E, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + FDCE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); +module \$__DFFE_PP0 (input D, C, E, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + FDCE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .CLR( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); + +module \$__DFFE_NP1 (input D, C, E, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); + FDPE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); +module \$__DFFE_PP1 (input D, C, E, R, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; - FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); + FDPE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .PRE( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Sync reset. + +module \$__DFFS_NP0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +module \$__DFFS_PP0_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$__DFFS_NP1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$__DFFS_PP1_ (input D, C, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .S( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Sync reset, enable. + +module \$__DFFSE_NP0 (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$__DFFSE_PP0 (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDRE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +module \$__DFFSE_NP1 (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE_1 #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule +module \$__DFFSE_PP1 (input D, C, E, R, output Q); + parameter _TECHMAP_WIREINIT_Q_ = 1'bx; + FDSE #(.INIT(_TECHMAP_WIREINIT_Q_)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .S( R)); + wire _TECHMAP_REMOVEINIT_Q_ = 1; +endmodule + +// Latches (no reset). module \$_DLATCH_N_ (input E, D, output Q); parameter _TECHMAP_WIREINIT_Q_ = 1'bx; @@ -112,5 +172,7 @@ module \$_DLATCH_P_ (input E, D, output Q); wire _TECHMAP_REMOVEINIT_Q_ = 1; endmodule +// Latches with reset (TODO). + `endif diff --git a/techlibs/xilinx/xc7_xcu_brams.txt b/techlibs/xilinx/xc7_xcu_brams.txt index f1161114e..c63218ae1 100644 --- a/techlibs/xilinx/xc7_xcu_brams.txt +++ b/techlibs/xilinx/xc7_xcu_brams.txt @@ -1,4 +1,3 @@ - bram $__XILINX_RAMB36_SDP init 1 abits 9 @@ -72,34 +71,79 @@ bram $__XILINX_RAMB18_TDP clkpol 2 3 endbram +# The "min bits" value were taken from: +# [[CITE]] 7 Series FPGAs Memory Resources User Guide (UG473), +# v1.14 ed., p 29-30, July, 2019. +# https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf + match $__XILINX_RAMB36_SDP - min bits 4096 + attribute !ram_style + attribute !logic_block + min bits 1024 min efficiency 5 shuffle_enable B make_transp or_next_if_better endmatch +match $__XILINX_RAMB36_SDP + attribute ram_style=block ram_block + attribute !logic_block + shuffle_enable B + make_transp + or_next_if_better +endmatch + match $__XILINX_RAMB18_SDP - min bits 4096 + attribute !ram_style + attribute !logic_block + min bits 1024 min efficiency 5 shuffle_enable B make_transp or_next_if_better endmatch +match $__XILINX_RAMB18_SDP + attribute ram_style=block ram_block + attribute !logic_block + shuffle_enable B + make_transp + or_next_if_better +endmatch + match $__XILINX_RAMB36_TDP - min bits 4096 + attribute !ram_style + attribute !logic_block + min bits 1024 min efficiency 5 shuffle_enable B make_transp or_next_if_better endmatch +match $__XILINX_RAMB36_TDP + attribute ram_style=block ram_block + attribute !logic_block + shuffle_enable B + make_transp + or_next_if_better +endmatch + match $__XILINX_RAMB18_TDP - min bits 4096 + attribute !ram_style + attribute !logic_block + min bits 1024 min efficiency 5 shuffle_enable B make_transp + or_next_if_better +endmatch + +match $__XILINX_RAMB18_TDP + attribute ram_style=block ram_block + attribute !logic_block + shuffle_enable B + make_transp endmatch diff --git a/techlibs/xilinx/xilinx_dffopt.cc b/techlibs/xilinx/xilinx_dffopt.cc new file mode 100644 index 000000000..13a0b9b83 --- /dev/null +++ b/techlibs/xilinx/xilinx_dffopt.cc @@ -0,0 +1,365 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +typedef std::pair<Const, std::vector<SigBit>> LutData; + +// Compute a LUT implementing (select ^ select_inv) ? alt_data : data. Returns true if successful. +bool merge_lut(LutData &result, const LutData &data, const LutData select, bool select_inv, SigBit alt_data, int max_lut_size) { + // First, gather input signals -- insert new signals at the beginning + // of the vector, so they don't disturb the likely-critical D LUT input + // timings. + result.second = data.second; + // D lut inputs initially start at 0. + int idx_data = 0; + // Now add the control input LUT inputs. + std::vector<int> idx_sel; + for (auto bit : select.second) { + int idx = -1; + for (int i = 0; i < GetSize(result.second); i++) + if (result.second[i] == bit) + idx = i; + if (idx == -1) { + idx = 0; + // Insert new signal at the beginning and bump all indices. + result.second.insert(result.second.begin(), bit); + idx_data++; + for (int &sidx : idx_sel) + sidx++; + } + idx_sel.push_back(idx); + } + // Insert the Q signal, if any, to the slowest input -- it will have + // no problem meeting timing. + int idx_alt = -1; + if (alt_data.wire) { + // Check if we already have it. + for (int i = 0; i < GetSize(result.second); i++) + if (result.second[i] == alt_data) + idx_alt = i; + // If not, add it. + if (idx_alt == -1) { + idx_alt = 0; + result.second.insert(result.second.begin(), alt_data); + idx_data++; + for (int &sidx : idx_sel) + sidx++; + } + } + + // If LUT would be too large, bail. + if (GetSize(result.second) > max_lut_size) + return false; + + // Okay, we're doing it — compute the LUT mask. + result.first = Const(0, 1 << GetSize(result.second)); + for (int i = 0; i < GetSize(result.first); i++) { + int sel_lut_idx = 0; + for (int j = 0; j < GetSize(select.second); j++) + if (i & 1 << idx_sel[j]) + sel_lut_idx |= 1 << j; + bool select_val = (select.first.bits[sel_lut_idx] == State::S1); + bool new_bit; + if (select_val ^ select_inv) { + // Use alt_data. + if (alt_data.wire) + new_bit = (i & 1 << idx_alt) != 0; + else + new_bit = alt_data.data == State::S1; + } else { + // Use original LUT. + int lut_idx = i >> idx_data & ((1 << GetSize(data.second)) - 1); + new_bit = data.first.bits[lut_idx] == State::S1; + } + result.first.bits[i] = new_bit ? State::S1 : State::S0; + } + return true; +} + +struct XilinxDffOptPass : public Pass { + XilinxDffOptPass() : Pass("xilinx_dffopt", "Xilinx: optimize FF control signal usage") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" xilinx_dffopt [options] [selection]\n"); + log("\n"); + log("Converts hardware clock enable and set/reset signals on FFs to emulation\n"); + log("using LUTs, if doing so would improve area. Operates on post-techmap Xilinx\n"); + log("cells (LUT*, FD*).\n"); + log("\n"); + log(" -lut4\n"); + log(" Assume a LUT4-based device (instead of a LUT6-based device).\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing XILINX_DFFOPT pass (optimize FF control signal usage).\n"); + + size_t argidx; + int max_lut_size = 6; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-lut4") { + max_lut_size = 4; + continue; + } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Optimizing FFs in %s.\n", log_id(module)); + + SigMap sigmap(module); + dict<SigBit, pair<LutData, Cell *>> bit_to_lut; + dict<SigBit, int> bit_uses; + + // Gather LUTs. + for (auto cell : module->selected_cells()) + { + for (auto port : cell->connections()) + for (auto bit : port.second) + bit_uses[sigmap(bit)]++; + if (cell->get_bool_attribute(ID::keep)) + continue; + if (cell->type == ID(INV)) { + SigBit sigout = sigmap(cell->getPort(ID(O))); + SigBit sigin = sigmap(cell->getPort(ID(I))); + bit_to_lut[sigout] = make_pair(LutData(Const(1, 2), {sigin}), cell); + } else if (cell->type.in(ID(LUT1), ID(LUT2), ID(LUT3), ID(LUT4), ID(LUT5), ID(LUT6))) { + SigBit sigout = sigmap(cell->getPort(ID(O))); + const Const &init = cell->getParam(ID(INIT)); + std::vector<SigBit> sigin; + sigin.push_back(sigmap(cell->getPort(ID(I0)))); + if (cell->type == ID(LUT1)) + goto lut_sigin_done; + sigin.push_back(sigmap(cell->getPort(ID(I1)))); + if (cell->type == ID(LUT2)) + goto lut_sigin_done; + sigin.push_back(sigmap(cell->getPort(ID(I2)))); + if (cell->type == ID(LUT3)) + goto lut_sigin_done; + sigin.push_back(sigmap(cell->getPort(ID(I3)))); + if (cell->type == ID(LUT4)) + goto lut_sigin_done; + sigin.push_back(sigmap(cell->getPort(ID(I4)))); + if (cell->type == ID(LUT5)) + goto lut_sigin_done; + sigin.push_back(sigmap(cell->getPort(ID(I5)))); +lut_sigin_done: + bit_to_lut[sigout] = make_pair(LutData(init, sigin), cell); + } + } + for (auto wire : module->wires()) + if (wire->port_output || wire->port_input) + for (int i = 0; i < GetSize(wire); i++) + bit_uses[sigmap(SigBit(wire, i))]++; + + // Iterate through FFs. + for (auto cell : module->selected_cells()) + { + bool has_s = false, has_r = false; + if (cell->type.in(ID(FDCE), ID(FDPE), ID(FDCPE), ID(FDCE_1), ID(FDPE_1), ID(FDCPE_1))) { + // Async reset. + } else if (cell->type.in(ID(FDRE), ID(FDRE_1))) { + has_r = true; + } else if (cell->type.in(ID(FDSE), ID(FDSE_1))) { + has_s = true; + } else if (cell->type.in(ID(FDRSE), ID(FDRSE_1))) { + has_r = true; + has_s = true; + } else { + // Not a FF. + continue; + } + if (cell->get_bool_attribute(ID::keep)) + continue; + + // Don't bother if D has more than one use. + SigBit sig_D = sigmap(cell->getPort(ID(D))); + if (bit_uses[sig_D] > 2) + continue; + + // Find the D LUT. + auto it_D = bit_to_lut.find(sig_D); + if (it_D == bit_to_lut.end()) + continue; + LutData lut_d = it_D->second.first; + Cell *cell_d = it_D->second.second; + if (cell->hasParam(ID(IS_D_INVERTED)) && cell->getParam(ID(IS_D_INVERTED)).as_bool()) { + // Flip all bits in the LUT. + for (int i = 0; i < GetSize(lut_d.first); i++) + lut_d.first.bits[i] = (lut_d.first.bits[i] == State::S1) ? State::S0 : State::S1; + } + + LutData lut_d_post_ce; + LutData lut_d_post_s; + LutData lut_d_post_r; + bool worthy_post_ce = false; + bool worthy_post_s = false; + bool worthy_post_r = false; + + // First, unmap CE. + SigBit sig_Q = sigmap(cell->getPort(ID(Q))); + SigBit sig_CE = sigmap(cell->getPort(ID(CE))); + LutData lut_ce = LutData(Const(2, 2), {sig_CE}); + auto it_CE = bit_to_lut.find(sig_CE); + if (it_CE != bit_to_lut.end()) + lut_ce = it_CE->second.first; + if (sig_CE.wire) { + // Merge CE LUT and D LUT into one. If it cannot be done, nothing to do about this FF. + if (!merge_lut(lut_d_post_ce, lut_d, lut_ce, true, sig_Q, max_lut_size)) + continue; + + // If this gets rid of a CE LUT, it's worth it. If not, it still may be worth it, if we can remove set/reset as well. + if (it_CE != bit_to_lut.end()) + worthy_post_ce = true; + } else if (sig_CE.data != State::S1) { + // Strange. Should not happen in a reasonable flow, so bail. + continue; + } else { + lut_d_post_ce = lut_d; + } + + // Second, unmap S, if any. + lut_d_post_s = lut_d_post_ce; + if (has_s) { + SigBit sig_S = sigmap(cell->getPort(ID(S))); + LutData lut_s = LutData(Const(2, 2), {sig_S}); + bool inv_s = cell->hasParam(ID(IS_S_INVERTED)) && cell->getParam(ID(IS_S_INVERTED)).as_bool(); + auto it_S = bit_to_lut.find(sig_S); + if (it_S != bit_to_lut.end()) + lut_s = it_S->second.first; + if (sig_S.wire) { + // Merge S LUT and D LUT into one. If it cannot be done, try to at least merge CE. + if (!merge_lut(lut_d_post_s, lut_d_post_ce, lut_s, inv_s, SigBit(State::S1), max_lut_size)) + goto unmap; + // If this gets rid of an S LUT, it's worth it. + if (it_S != bit_to_lut.end()) + worthy_post_s = true; + } else if (sig_S.data != (inv_s ? State::S1 : State::S0)) { + // Strange. Should not happen in a reasonable flow, so bail. + continue; + } + } + + // Third, unmap R, if any. + lut_d_post_r = lut_d_post_s; + if (has_r) { + SigBit sig_R = sigmap(cell->getPort(ID(R))); + LutData lut_r = LutData(Const(2, 2), {sig_R}); + bool inv_r = cell->hasParam(ID(IS_R_INVERTED)) && cell->getParam(ID(IS_R_INVERTED)).as_bool(); + auto it_R = bit_to_lut.find(sig_R); + if (it_R != bit_to_lut.end()) + lut_r = it_R->second.first; + if (sig_R.wire) { + // Merge R LUT and D LUT into one. If it cannot be done, try to at least merge CE/S. + if (!merge_lut(lut_d_post_r, lut_d_post_s, lut_r, inv_r, SigBit(State::S0), max_lut_size)) + goto unmap; + // If this gets rid of an S LUT, it's worth it. + if (it_R != bit_to_lut.end()) + worthy_post_r = true; + } else if (sig_R.data != (inv_r ? State::S1 : State::S0)) { + // Strange. Should not happen in a reasonable flow, so bail. + continue; + } + } + +unmap: + LutData final_lut; + if (worthy_post_r) { + final_lut = lut_d_post_r; + log(" Merging R LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); + } else if (worthy_post_s) { + final_lut = lut_d_post_s; + log(" Merging S LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); + } else if (worthy_post_ce) { + final_lut = lut_d_post_ce; + log(" Merging CE LUT for %s/%s (%d -> %d)\n", log_id(cell), log_id(sig_Q.wire), GetSize(lut_d.second), GetSize(final_lut.second)); + } else { + // Nothing to do here. + continue; + } + + // Okay, we're doing it. Unmap ports. + if (worthy_post_r) { + cell->unsetParam(ID(IS_R_INVERTED)); + cell->setPort(ID(R), Const(0, 1)); + } + if (has_s && (worthy_post_r || worthy_post_s)) { + cell->unsetParam(ID(IS_S_INVERTED)); + cell->setPort(ID(S), Const(0, 1)); + } + cell->setPort(ID(CE), Const(1, 1)); + cell->unsetParam(ID(IS_D_INVERTED)); + + // Create the new LUT. + Cell *lut_cell = 0; + switch (GetSize(final_lut.second)) { + case 1: + lut_cell = module->addCell(NEW_ID, ID(LUT1)); + break; + case 2: + lut_cell = module->addCell(NEW_ID, ID(LUT2)); + break; + case 3: + lut_cell = module->addCell(NEW_ID, ID(LUT3)); + break; + case 4: + lut_cell = module->addCell(NEW_ID, ID(LUT4)); + break; + case 5: + lut_cell = module->addCell(NEW_ID, ID(LUT5)); + break; + case 6: + lut_cell = module->addCell(NEW_ID, ID(LUT6)); + break; + default: + log_assert(!"unknown lut size"); + } + lut_cell->attributes = cell_d->attributes; + Wire *lut_out = module->addWire(NEW_ID); + lut_cell->setParam(ID(INIT), final_lut.first); + cell->setPort(ID(D), lut_out); + lut_cell->setPort(ID(O), lut_out); + lut_cell->setPort(ID(I0), final_lut.second[0]); + if (GetSize(final_lut.second) >= 2) + lut_cell->setPort(ID(I1), final_lut.second[1]); + if (GetSize(final_lut.second) >= 3) + lut_cell->setPort(ID(I2), final_lut.second[2]); + if (GetSize(final_lut.second) >= 4) + lut_cell->setPort(ID(I3), final_lut.second[3]); + if (GetSize(final_lut.second) >= 5) + lut_cell->setPort(ID(I4), final_lut.second[4]); + if (GetSize(final_lut.second) >= 6) + lut_cell->setPort(ID(I5), final_lut.second[5]); + } + } + } +} XilinxDffOptPass; + +PRIVATE_NAMESPACE_END + |