diff options
Diffstat (limited to 'techlibs')
47 files changed, 2900 insertions, 788 deletions
diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v index a94dce9b1..a0c60b4be 100755 --- a/techlibs/achronix/speedster22i/cells_sim.v +++ b/techlibs/achronix/speedster22i/cells_sim.v @@ -30,7 +30,7 @@ endmodule module PADOUT (output padout, input padin, input oe); assign padout = padin; assign oe = oe; -endmodule +endmodule module LUT4 (output dout, input din0, din1, din2, din3); @@ -66,14 +66,14 @@ always @(dataa_w or datab_w or datac_w or datad_w) begin datac_w, datad_w); end assign dout = combout_rt & 1'b1; -endmodule +endmodule module DFF (output q, input d, ck); reg q; always @(posedge ck) q <= d; - + endmodule diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc index c025c65c4..741bf04cc 100644 --- a/techlibs/anlogic/anlogic_eqn.cc +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -52,13 +52,13 @@ struct AnlogicEqnPass : public Pass { eqn += names[j]; else eqn += std::string("~") + names[j]; - + if (j!=(inputs-1)) eqn += "*"; } eqn += ")+"; } } - if (eqn.empty()) return Const("0"); + if (eqn.empty()) return Const("0"); eqn = eqn.substr(0, eqn.length()-1); return Const(eqn); } diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index 86fb4d6c6..cdd21c3b3 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -195,9 +195,11 @@ struct PrepPass : public ScriptPass run(nokeepdc ? "opt" : "opt -keepdc"); if (!ifxmode) { if (help_mode) - run("wreduce [-memx]"); - else + run("wreduce -keepdc [-memx]"); + else if (nokeepdc) run(memxmode ? "wreduce -memx" : "wreduce"); + else + run(memxmode ? "wreduce -keepdc -memx" : "wreduce -keepdc"); } if (!nomemmode) { run(string("memory_dff") + (help_mode ? " [-nordff]" : nordff ? " -nordff" : "")); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 8e43fe058..a424d3089 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1271,6 +1271,181 @@ endmodule // -------------------------------------------------------- +module \$specify2 (EN, SRC, DST); + +parameter FULL = 0; +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter SRC_DST_PEN = 0; +parameter SRC_DST_POL = 0; + +parameter T_RISE_MIN = 0; +parameter T_RISE_TYP = 0; +parameter T_RISE_MAX = 0; + +parameter T_FALL_MIN = 0; +parameter T_FALL_TYP = 0; +parameter T_FALL_MAX = 0; + +input EN; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST; + +localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; + +`ifdef SIMLIB_SPECIFY +specify + if (EN && SD==0 && !FULL) (SRC => DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==0 && FULL) (SRC *> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==1 && !FULL) (SRC +=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==1 && FULL) (SRC +*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==2 && !FULL) (SRC -=> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && SD==2 && FULL) (SRC -*> DST) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + +module \$specify3 (EN, SRC, DST, DAT); + +parameter FULL = 0; +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter EDGE_EN = 0; +parameter EDGE_POL = 0; + +parameter SRC_DST_PEN = 0; +parameter SRC_DST_POL = 0; + +parameter DAT_DST_PEN = 0; +parameter DAT_DST_POL = 0; + +parameter T_RISE_MIN = 0; +parameter T_RISE_TYP = 0; +parameter T_RISE_MAX = 0; + +parameter T_FALL_MIN = 0; +parameter T_FALL_TYP = 0; +parameter T_FALL_MAX = 0; + +input EN; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST, DAT; + +localparam ED = EDGE_EN ? (EDGE_POL ? 1 : 2) : 0; +localparam SD = SRC_DST_PEN ? (SRC_DST_POL ? 1 : 2) : 0; +localparam DD = DAT_DST_PEN ? (DAT_DST_POL ? 1 : 2) : 0; + +`ifdef SIMLIB_SPECIFY +specify + // DD=0 + + if (EN && DD==0 && SD==0 && ED==0 && !FULL) ( SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==0 && FULL) ( SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==0 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==0 && FULL) ( SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==0 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==0 && FULL) ( SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==0 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST : DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + // DD=1 + + if (EN && DD==1 && SD==0 && ED==0 && !FULL) ( SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==0 && FULL) ( SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==1 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==0 && FULL) ( SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==1 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==0 && FULL) ( SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==1 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST +: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + // DD=2 + + if (EN && DD==2 && SD==0 && ED==0 && !FULL) ( SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==0 && FULL) ( SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==1 && !FULL) (posedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==1 && FULL) (posedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==2 && !FULL) (negedge SRC => (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==0 && ED==2 && FULL) (negedge SRC *> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==2 && SD==1 && ED==0 && !FULL) ( SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==0 && FULL) ( SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==1 && !FULL) (posedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==1 && FULL) (posedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==2 && !FULL) (negedge SRC +=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==1 && ED==2 && FULL) (negedge SRC +*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + + if (EN && DD==2 && SD==2 && ED==0 && !FULL) ( SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==0 && FULL) ( SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==1 && !FULL) (posedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==1 && FULL) (posedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==2 && !FULL) (negedge SRC -=> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); + if (EN && DD==2 && SD==2 && ED==2 && FULL) (negedge SRC -*> (DST -: DAT)) = (T_RISE_MIN:T_RISE_TYP:T_RISE_MAX, T_FALL_MIN:T_FALL_TYP:T_FALL_MAX); +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + +module \$specrule (EN_SRC, EN_DST, SRC, DST); + +parameter TYPE = ""; +parameter T_LIMIT = 0; +parameter T_LIMIT2 = 0; + +parameter SRC_WIDTH = 1; +parameter DST_WIDTH = 1; + +parameter SRC_PEN = 0; +parameter SRC_POL = 0; + +parameter DST_PEN = 0; +parameter DST_POL = 0; + +input EN_SRC, EN_DST; +input [SRC_WIDTH-1:0] SRC; +input [DST_WIDTH-1:0] DST; + +`ifdef SIMLIB_SPECIFY +specify + // TBD +endspecify +`endif + +endmodule + +// -------------------------------------------------------- + module \$assert (A, EN); input A, EN; @@ -1863,4 +2038,5 @@ end endmodule `endif + // -------------------------------------------------------- diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index ccfa76e02..e41c0fe97 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -201,6 +201,8 @@ struct SynthPass : public ScriptPass run("check"); run("opt"); run("wreduce"); + run("peepopt"); + run("opt_clean"); if (help_mode) run("techmap -map +/cmp2lut.v", " (if -lut)"); else diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 8df02be5f..4db087e87 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,5 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index 1094c5f8a..eb7947601 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); input CI, BI; output [Y_WIDTH-1:0] CO; - wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 425d62d24..223e19b9e 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -156,6 +156,41 @@ module OSCG( parameter DIV = 128; endmodule +(* blackbox *) (* keep *) +module USRMCLK( + input USRMCLKI, USRMCLKTS, + output USRMCLKO +); +endmodule + +(* blackbox *) (* keep *) +module JTAGG( + input TCK, TMS, TDI, JTDO2, JTDO1, + output TDO, JTDI, JTCK, JRTI2, JRTI1, + output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1 +); +parameter ER1 = "ENABLED"; +parameter ER2 = "ENABLED"; +endmodule + +(* blackbox *) +module DELAYF( + input A, LOADN, MOVE, DIRECTION, + output Z, CFLAG +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + +(* blackbox *) +module DELAYG( + input A, + output Z +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + (* blackbox *) module IDDRX1F( input D, SCLK, RST, @@ -165,6 +200,31 @@ module IDDRX1F( endmodule (* blackbox *) +module IDDRX2F( + input D, SCLK, ECLK, RST, + output Q0, Q1, Q2, Q3 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDR71B( + input D, SCLK, ECLK, RST, ALIGNWD, + output Q0, Q1, Q2, Q3, Q4, Q5, Q6 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDRX2DQA( + input D, DQSR90, ECLK, SCLK, RST, + input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output Q0, Q1, Q2, Q3, QWL +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) module ODDRX1F( input SCLK, RST, D0, D1, output Q @@ -173,6 +233,91 @@ module ODDRX1F( endmodule (* blackbox *) +module ODDRX2F( + input SCLK, ECLK, RST, D0, D1, D2, D3, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDR71B( + input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module OSHX2A( + input D0, D1, RST, ECLK, SCLK, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQA( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQSB( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module TSHX2DQA( + input T0, T1, SCLK, ECLK, DQSW270, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module TSHX2DQSA( + input T0, T1, SCLK, ECLK, DQSW, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module DQSBUFM( + input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, + input ECLK, SCLK, + input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4, + input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, + input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE, + output DQSR90, DQSW, DQSW270, + output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG +); + parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LI_DEL_VAL = 0; + parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LO_DEL_VAL = 0; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module DDRDLLA( + input CLK, RST, UDDCNTLN, FREEZE, + output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0 +); + parameter FORCE_MAX_DELAY = "NO"; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) module CLKDIVF( input CLKI, RST, ALIGNWD, output CDIVX @@ -182,6 +327,13 @@ module CLKDIVF( endmodule (* blackbox *) +module ECLKSYNCB( + input ECLKI, STOP, + output ECLKO +); +endmodule + +(* blackbox *) module DCCA( input CLKI, CE, output CLKO diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 23182bdeb..f6c71a03d 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,24 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .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("DISABLED"), .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 +// Diamond I/O buffers +module IB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPU (input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPD (input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module OB (input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule +module OBZ (input I, T, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS _TECHMAP_REPLACE_ (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, output Z); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule +module OLVDS(input A, output Z, ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule + +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule + `ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index f27540bd7..1e4002ee0 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -203,13 +203,14 @@ endmodule // --------------------------------------- -module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); +module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); parameter GSR = "ENABLED"; parameter [127:0] CEMUX = "1"; parameter CLKMUX = "CLK"; parameter LSRMUX = "LSR"; parameter SRMODE = "LSR_OVER_CE"; parameter REGSET = "RESET"; + parameter [127:0] LSRMODE = "LSR"; reg muxce; always @(*) @@ -222,8 +223,13 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; - - localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; + wire srval; + generate + if (LSRMODE == "PRLD") + assign srval = M; + else + assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; + endgenerate initial Q = srval; @@ -339,6 +345,8 @@ module TRELLIS_SLICE( parameter REG1_SD = "0"; parameter REG0_REGSET = "RESET"; parameter REG1_REGSET = "RESET"; + parameter REG0_LSRMODE = "LSR"; + parameter REG1_LSRMODE = "LSR"; parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter WREMUX = "WRE"; @@ -428,10 +436,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG0_REGSET) + .REGSET(REG0_REGSET), + .LSRMODE(REG0_LSRMODE) ) ff_0 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi0), + .DI(muxdi0), .M(M0), .Q(Q0) ); TRELLIS_FF #( @@ -440,10 +449,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG1_REGSET) + .REGSET(REG1_REGSET), + .LSRMODE(REG1_LSRMODE) ) ff_1 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi1), + .DI(muxdi1), .M(M1), .Q(Q1) ); endmodule @@ -547,3 +557,20 @@ module DP16KD( parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule + +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); + TRELLIS_FF #( + .GSR("DISABLED"), + .CEMUX("1"), + .CLKMUX("CLK"), + .LSRMUX("LSR"), + .REGSET("SET"), + .SRMODE("ASYNC") + ) tff_i ( + .CLK(CK), + .LSR(PD), + .DI(D), + .Q(Q) + ); +endmodule diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc new file mode 100644 index 000000000..dbd16cac9 --- /dev/null +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -0,0 +1,203 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018-19 David Shah <david@symbioticeda.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Ecp5FfinitPass : public Pass { + Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ecp5_ffinit [options] [selection]\n"); + log("\n"); + log("Remove init values for FF output signals when equal to reset value.\n"); + log("If reset is not used, set the reset value to the init value, otherwise\n"); + log("unmap out the reset (if not an async reset).\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Handling FF init values in %s.\n", log_id(module)); + + SigMap sigmap(module); + pool<Wire*> init_wires; + dict<SigBit, State> initbits; + dict<SigBit, SigBit> initbit_to_wire; + pool<SigBit> handled_initbits; + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + init_wires.insert(wire); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit) != val) { + log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + initbits.at(bit) = State::Sx; + } + continue; + } + + initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); + } + } + for (auto cell : module->selected_cells()) + { + if (cell->type != "\\TRELLIS_FF") + continue; + SigSpec sig_d = cell->getPort("\\DI"); + SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_lsr = cell->getPort("\\LSR"); + + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + std::string regset = "RESET"; + if (cell->hasParam("\\REGSET")) + regset = cell->getParam("\\REGSET").decode_string(); + State resetState; + if (regset == "SET") + resetState = State::S1; + else if (regset == "RESET") + resetState = State::S0; + else + log_error("FF cell %s has illegal REGSET value %s.\n", + log_id(cell), regset.c_str()); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + + if (val == State::Sx) + continue; + + log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), + log_signal(bit_q), val != State::S0 ? '1' : '0'); + // Initval is the same as the reset state. Matches hardware, nowt more to do + if (val == resetState) { + handled_initbits.insert(bit_q); + continue; + } + + if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { + std::string srmode = "LSR_OVER_CE"; + if (cell->hasParam("\\SRMODE")) + srmode = cell->getParam("\\SRMODE").decode_string(); + if (srmode == "ASYNC") { + log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", + resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); + } else { + SigBit bit_lsr = sigmap(sig_lsr[0]); + Wire *new_bit_d = module->addWire(NEW_ID); + if (resetState == State::S0) { + module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } else { + module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } + + cell->setPort("\\DI", new_bit_d); + cell->setPort("\\LSR", State::S0); + + if(cell->hasPort("\\CE")) { + std::string cemux = "CE"; + if (cell->hasParam("\\CEMUX")) + cemux = cell->getParam("\\CEMUX").decode_string(); + SigSpec sig_ce = cell->getPort("\\CE"); + if (GetSize(sig_ce) >= 1) { + SigBit bit_ce = sigmap(sig_ce[0]); + Wire *new_bit_ce = module->addWire(NEW_ID); + if (cemux == "INV") + module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + else + module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + cell->setPort("\\CE", new_bit_ce); + } + } + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } else { + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } + + for (auto wire : init_wires) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + bool remove_attribute = true; + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { + if (handled_initbits.count(wirebits[i])) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + remove_attribute = false; + } + + if (remove_attribute) + wire->attributes.erase("\\init"); + } + } + } +} Ecp5FfinitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index bda03d251..c6e12248e 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -253,12 +253,9 @@ struct SynthEcp5Pass : public ScriptPass if (!nodffe) run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); - run("opt_expr -mux_undef"); + run("opt_expr -undriven -mux_undef"); run("simplemap"); - // TODO -#if 0 run("ecp5_ffinit"); -#endif } if (check_label("map_luts")) diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 2f82def7d..6f2159349 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -1,7 +1,17 @@ OBJS += techlibs/gowin/synth_gowin.o +OBJS += techlibs/gowin/determine_init.o + $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/bram.txt)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/drams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/dram.txt)) + + + +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh)) diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v index 25e789e4a..e15de6423 100644 --- a/techlibs/gowin/arith_map.v +++ b/techlibs/gowin/arith_map.v @@ -25,24 +25,24 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; - + input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; output [Y_WIDTH-1:0] X, Y; - + input CI, BI; output [Y_WIDTH-1:0] CO; - + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; - + wire [Y_WIDTH-1:0] A_buf, B_buf; \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); - + wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] C = {CO, CI}; - + genvar i; generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice ALU #(.ALU_MODE(32'b0)) diff --git a/techlibs/gowin/bram.txt b/techlibs/gowin/bram.txt new file mode 100644 index 000000000..b5f9a981c --- /dev/null +++ b/techlibs/gowin/bram.txt @@ -0,0 +1,29 @@ +bram $__GW1NR_SDP +# uncomment when done +# init 1 + abits 10 @a10d18 + dbits 16 @a10d18 + abits 11 @a11d9 + dbits 8 @a11d9 + abits 12 @a12d4 + dbits 4 @a12d4 + abits 13 @a13d2 + dbits 2 @a13d2 + abits 14 @a14d1 + dbits 1 @a14d1 + groups 2 + ports 1 1 + wrmode 1 0 + enable 1 1 @a10d18 + enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1 + transp 0 0 + clocks 2 3 + clkpol 2 3 +endbram + +match $__GW1NR_SDP + min bits 2048 + min efficiency 5 + shuffle_enable B + make_transp +endmatch diff --git a/techlibs/gowin/brams_init3.vh b/techlibs/gowin/brams_init3.vh new file mode 100644 index 000000000..84397fa24 --- /dev/null +++ b/techlibs/gowin/brams_init3.vh @@ -0,0 +1,12 @@ +localparam [15:0] INIT_0 = { + INIT[ 60], INIT[ 56], INIT[ 52], INIT[ 48], INIT[ 44], INIT[ 40], INIT[ 36], INIT[ 32], INIT[ 28], INIT[ 24], INIT[ 20], INIT[ 16], INIT[ 12], INIT[ 8], INIT[ 4], INIT[ 0] +}; +localparam [15:0] INIT_1 = { + INIT[ 61], INIT[ 57], INIT[ 53], INIT[ 49], INIT[ 45], INIT[ 41], INIT[ 37], INIT[ 33], INIT[ 29], INIT[ 25], INIT[ 21], INIT[ 17], INIT[ 13], INIT[ 9], INIT[ 5], INIT[ 1] +}; +localparam [15:0] INIT_2 = { + INIT[ 62], INIT[ 58], INIT[ 54], INIT[ 50], INIT[ 46], INIT[ 42], INIT[ 38], INIT[ 34], INIT[ 30], INIT[ 26], INIT[ 22], INIT[ 18], INIT[ 14], INIT[ 10], INIT[ 6], INIT[ 2] +}; +localparam [15:0] INIT_3 = { + INIT[ 63], INIT[ 59], INIT[ 55], INIT[ 51], INIT[ 47], INIT[ 43], INIT[ 39], INIT[ 35], INIT[ 31], INIT[ 27], INIT[ 23], INIT[ 19], INIT[ 15], INIT[ 11], INIT[ 7], INIT[ 3] +}; diff --git a/techlibs/gowin/brams_map.v b/techlibs/gowin/brams_map.v new file mode 100644 index 000000000..e963cfa88 --- /dev/null +++ b/techlibs/gowin/brams_map.v @@ -0,0 +1,103 @@ +/* Semi Dual Port (SDP) memory have the following configurations: + * Memory Config RAM(BIT) Port Mode Memory Depth Data Depth + * ----------------|---------| ----------|--------------|------------| + * B-SRAM_16K_SD1 16K 16Kx1 16,384 1 + * B-SRAM_8K_SD2 16K 8Kx2 8,192 2 + * B-SRAM_4K_SD4 16K 4Kx2 4,096 4 + */ +module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 10; + parameter CFG_DBITS = 16; + parameter CFG_ENABLE_A = 3; + + parameter [16383:0] INIT = 16384'hx; + parameter CLKPOL2 = 1; + parameter CLKPOL3 = 1; + + input CLK2; + input CLK3; + + input [CFG_ABITS-1:0] A1ADDR; + input [CFG_DBITS-1:0] A1DATA; + input [CFG_ENABLE_A-1:0] A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + output [CFG_DBITS-1:0] B1DATA; + input B1EN; + + + generate if (CFG_DBITS == 1) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(1), + .BIT_WIDTH_1(1), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS == 2) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(2), + .BIT_WIDTH_1(2), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 4) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(4), + .BIT_WIDTH_1(4), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 8) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(8), + .BIT_WIDTH_1(8), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), .CEA(1'b1), + .WREB(1'b0), .CEB(B1EN), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else if (CFG_DBITS <= 16) begin + SDP #( + .READ_MODE(0), + .BIT_WIDTH_0(16), + .BIT_WIDTH_1(16), + .BLK_SEL(3'b000), + .RESET_MODE("SYNC") + ) _TECHMAP_REPLACE_ ( + .CLKA(CLK2), .CLKB(CLK3), + .WREA(A1EN), .OCE(1'b0), + .WREB(1'b0), .CEB(B1EN), .CEA(1'b1), + .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000), + .DI(A1DATA), .DO(B1DATA), .ADA(A1ADDR), .ADB(B1ADDR) + ); + end else begin + wire TECHMAP_FAIL = 1'b1; + end endgenerate + +endmodule diff --git a/techlibs/gowin/cells_map.v b/techlibs/gowin/cells_map.v index e1f85effa..ebdc88a0a 100644 --- a/techlibs/gowin/cells_map.v +++ b/techlibs/gowin/cells_map.v @@ -1,5 +1,9 @@ module \$_DFF_N_ (input D, C, output Q); DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule -module \$_DFF_P_ (input D, C, output Q); DFF _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule +module \$_DFF_P_ #(parameter INIT = 1'b0) (input D, C, output Q); DFF #(.INIT(INIT)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C)); endmodule + +module \$__DFFS_PN0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(!R)); endmodule +module \$__DFFS_PP0_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule +module \$__DFFS_PP1_ (input D, C, R, output Q); DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .CLK(C), .RESET(R)); endmodule module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/gowin/cells_sim.v b/techlibs/gowin/cells_sim.v index 14441c2fc..ebb238bad 100644 --- a/techlibs/gowin/cells_sim.v +++ b/techlibs/gowin/cells_sim.v @@ -38,6 +38,17 @@ module DFFN (output reg Q, input CLK, D); Q <= D; endmodule +module DFFR (output reg Q, input D, CLK, RESET); + parameter [0:0] INIT = 1'b0; + initial Q = INIT; + always @(posedge CLK) begin + if (RESET) + Q <= 1'b0; + else + Q <= D; + end +endmodule // DFFR (positive clock edge; synchronous reset) + module VCC(output V); assign V = 1; endmodule @@ -63,3 +74,126 @@ module ALU (input I0, input I1, input I3, input CIN, output COUT, output SUM); assign {COUT, SUM} = CIN + I1 + I0; endmodule // alu +module RAM16S4 (DO, DI, AD, WRE, CLK); + parameter WIDTH = 4; + parameter INIT_0 = 16'h0000; + parameter INIT_1 = 16'h0000; + parameter INIT_2 = 16'h0000; + parameter INIT_3 = 16'h0000; + + input [WIDTH-1:0] AD; + input [WIDTH-1:0] DI; + output [WIDTH-1:0] DO; + input CLK; + input WRE; + + reg [15:0] mem0, mem1, mem2, mem3; + + initial begin + mem0 = INIT_0; + mem1 = INIT_1; + mem2 = INIT_2; + mem3 = INIT_3; + end + + assign DO[0] = mem0[AD]; + assign DO[1] = mem1[AD]; + assign DO[2] = mem2[AD]; + assign DO[3] = mem3[AD]; + + always @(posedge CLK) begin + if (WRE) begin + mem0[AD] <= DI[0]; + mem1[AD] <= DI[1]; + mem2[AD] <= DI[2]; + mem3[AD] <= DI[3]; + end + end + +endmodule // RAM16S4 + + +(* blackbox *) +module SDP (DO, DI, BLKSEL, ADA, ADB, WREA, WREB, CLKA, CLKB, CEA, CEB, OCE, RESETA, RESETB); +//1'b0: Bypass mode; 1'b1 Pipeline mode +parameter READ_MODE = 1'b0; +parameter BIT_WIDTH_0 = 32; // 1, 2, 4, 8, 16, 32 +parameter BIT_WIDTH_1 = 32; // 1, 2, 4, 8, 16, 32 +parameter BLK_SEL = 3'b000; +parameter RESET_MODE = "SYNC"; +parameter INIT_RAM_00 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_01 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_02 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_03 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_04 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_05 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_06 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_07 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_08 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_09 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_0F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_10 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_11 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_12 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_13 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_14 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_15 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_16 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_17 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_18 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_19 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_1F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_20 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_21 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_22 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_23 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_24 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_25 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_26 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_27 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_28 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_29 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_2F = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_30 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_31 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_32 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_33 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_34 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_35 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_36 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_37 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_38 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_39 = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3A = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3B = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3C = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3D = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3E = 256'h0000000000000000000000000000000000000000000000000000000000000000; +parameter INIT_RAM_3F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + +input CLKA, CEA, CLKB, CEB; +input OCE; // clock enable of memory output register +input RESETA, RESETB; // resets output registers, not memory contents +input WREA, WREB; // 1'b0: read enabled; 1'b1: write enabled +input [13:0] ADA, ADB; +input [31:0] DI; +input [2:0] BLKSEL; +output [31:0] DO; + +endmodule + diff --git a/techlibs/gowin/determine_init.cc b/techlibs/gowin/determine_init.cc new file mode 100644 index 000000000..991e5245a --- /dev/null +++ b/techlibs/gowin/determine_init.cc @@ -0,0 +1,72 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DetermineInitPass : public Pass { + DetermineInitPass() : Pass("determine_init", "Determine the init value of cells") { } + void help() YS_OVERRIDE + { + log("\n"); + log(" determine_init [selection]\n"); + log("\n"); + log("Determine the init value of cells that doesn't allow unknown init value.\n"); + log("\n"); + } + + Const determine_init(Const init) + { + for (int i = 0; i < GetSize(init); i++) { + if (init[i] != State::S0 && init[i] != State::S1) + init[i] = State::S0; + } + + return init; + } + + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing DETERMINE_INIT pass (determine init value for cells).\n"); + + extra_args(args, args.size(), design); + + size_t cnt = 0; + for (auto module : design->selected_modules()) + { + for (auto cell : module->selected_cells()) + { + if (cell->type == "\\RAM16S4") + { + cell->setParam("\\INIT_0", determine_init(cell->getParam("\\INIT_0"))); + cell->setParam("\\INIT_1", determine_init(cell->getParam("\\INIT_1"))); + cell->setParam("\\INIT_2", determine_init(cell->getParam("\\INIT_2"))); + cell->setParam("\\INIT_3", determine_init(cell->getParam("\\INIT_3"))); + cnt++; + } + } + } + log_header(design, "Updated %lu cells with determined init value.\n", cnt); + } +} DetermineInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/gowin/dram.txt b/techlibs/gowin/dram.txt new file mode 100644 index 000000000..9db530251 --- /dev/null +++ b/techlibs/gowin/dram.txt @@ -0,0 +1,17 @@ +bram $__GW1NR_RAM16S4 + init 1 + abits 4 + dbits 4 + groups 2 + ports 1 1 + wrmode 0 1 + enable 0 1 + transp 0 1 + clocks 0 1 + clkpol 0 1 +endbram + +match $__GW1NR_RAM16S4 + make_outreg + min wports 1 +endmatch diff --git a/techlibs/gowin/drams_map.v b/techlibs/gowin/drams_map.v new file mode 100644 index 000000000..a50ab365a --- /dev/null +++ b/techlibs/gowin/drams_map.v @@ -0,0 +1,31 @@ +module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN); + parameter CFG_ABITS = 4; + parameter CFG_DBITS = 4; + + parameter [63:0] INIT = 64'bx; + input CLK1; + + input [CFG_ABITS-1:0] A1ADDR; + output [CFG_DBITS-1:0] A1DATA; + input A1EN; + + input [CFG_ABITS-1:0] B1ADDR; + input [CFG_DBITS-1:0] B1DATA; + input B1EN; + + `include "brams_init3.vh" + + RAM16S4 + #(.INIT_0(INIT_0), + .INIT_1(INIT_1), + .INIT_2(INIT_2), + .INIT_3(INIT_3)) + _TECHMAP_REPLACE_ + (.AD(B1ADDR), + .DI(B1DATA), + .DO(A1DATA), + .CLK(CLK1), + .WRE(B1EN)); + + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 96128a680..ac3dbfb29 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -49,9 +49,15 @@ struct SynthGowinPass : public ScriptPass log(" from label is synonymous to 'begin', and empty to label is\n"); log(" synonymous to the end of the command list.\n"); log("\n"); + log(" -nodffe\n"); + log(" do not use flipflops with CE in output netlist\n"); + log("\n"); log(" -nobram\n"); log(" do not use BRAM cells in output netlist\n"); log("\n"); + log(" -nodram\n"); + log(" do not use distributed RAM cells in output netlist\n"); + log("\n"); log(" -noflatten\n"); log(" do not flatten design before synthesis\n"); log("\n"); @@ -65,7 +71,7 @@ struct SynthGowinPass : public ScriptPass } string top_opt, vout_file; - bool retime, flatten, nobram; + bool retime, nobram, nodram, flatten, nodffe; void clear_flags() YS_OVERRIDE { @@ -73,7 +79,9 @@ struct SynthGowinPass : public ScriptPass vout_file = ""; retime = false; flatten = true; - nobram = true; + nobram = false; + nodffe = false; + nodram = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -108,10 +116,18 @@ struct SynthGowinPass : public ScriptPass nobram = true; continue; } + if (args[argidx] == "-nodram") { + nodram = true; + continue; + } + if (args[argidx] == "-nodffe") { + nodffe = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; - } + } break; } extra_args(args, argidx, design); @@ -147,25 +163,43 @@ struct SynthGowinPass : public ScriptPass { run("synth -run coarse"); } - if (!nobram && check_label("bram", "(skip if -nobram)")) + + if (!nobram && check_label("bram", "(skip if -nobram)")) { run("memory_bram -rules +/gowin/bram.txt"); - run("techmap -map +/gowin/brams_map.v"); + run("techmap -map +/gowin/brams_map.v -map +/gowin/cells_sim.v"); } + + if (!nodram && check_label("dram", "(skip if -nodram)")) + { + run("memory_bram -rules +/gowin/dram.txt"); + run("techmap -map +/gowin/drams_map.v"); + run("determine_init"); + } + if (check_label("fine")) { run("opt -fast -mux_undef -undriven -fine"); run("memory_map"); run("opt -undriven -fine"); run("techmap -map +/techmap.v -map +/gowin/arith_map.v"); - run("opt -fine"); - run("clean -purge"); - run("splitnets -ports"); - run("setundef -undriven -zero"); + run("techmap -map +/techmap.v"); if (retime || help_mode) run("abc -dff", "(only if -retime)"); } + if (check_label("map_ffs")) + { + run("dffsr2dff"); + run("dff2dffs"); + run("opt_clean"); + if (!nodffe) + run("dff2dffe -direct-match $_DFF_* -direct-match $__DFFS_*"); + run("techmap -map +/gowin/cells_map.v"); + run("opt_expr -mux_undef"); + run("simplemap"); + } + if (check_label("map_luts")) { run("abc -lut 4"); @@ -176,8 +210,10 @@ struct SynthGowinPass : public ScriptPass { run("techmap -map +/gowin/cells_map.v"); run("hilomap -hicell VCC V -locell GND G"); - run("iopadmap -inpad IBUF O:I -outpad OBUF I:O"); - run("clean -purge"); + run("iopadmap -bits -inpad IBUF O:I -outpad OBUF I:O", "(unless -noiopads)"); + run("dffinit -ff DFF Q INIT"); + run("clean"); + } if (check_label("check")) diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 2750901c8..723b59d6f 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/ice40/synth_ice40.o +OBJS += techlibs/ice40/ice40_braminit.o OBJS += techlibs/ice40/ice40_ffssr.o OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_opt.o diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v index 19a61d73b..ad3bccd21 100644 --- a/techlibs/ice40/brams_map.v +++ b/techlibs/ice40/brams_map.v @@ -7,8 +7,8 @@ module \$__ICE40_RAM4K ( input [10:0] WADDR, input [15:0] MASK, WDATA ); - parameter integer READ_MODE = 0; - parameter integer WRITE_MODE = 0; + parameter [1:0] READ_MODE = 0; + parameter [1:0] WRITE_MODE = 0; parameter [0:0] NEGCLK_R = 0; parameter [0:0] NEGCLK_W = 0; diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 2041693cc..f9945b2b5 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -27,18 +27,27 @@ module SB_IO ( reg dout_q_0, dout_q_1; reg outena_q; + // IO tile generates a constant 1'b1 internally if global_cen is not connected + wire clken_pulled = CLOCK_ENABLE || CLOCK_ENABLE === 1'bz; + reg clken_pulled_ri; + reg clken_pulled_ro; + generate if (!NEG_TRIGGER) begin - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(posedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(posedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(negedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(posedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(posedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(negedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(posedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end else begin - always @(negedge INPUT_CLK) if (CLOCK_ENABLE) din_q_0 <= PACKAGE_PIN; - always @(posedge INPUT_CLK) if (CLOCK_ENABLE) din_q_1 <= PACKAGE_PIN; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_0 <= D_OUT_0; - always @(posedge OUTPUT_CLK) if (CLOCK_ENABLE) dout_q_1 <= D_OUT_1; - always @(negedge OUTPUT_CLK) if (CLOCK_ENABLE) outena_q <= OUTPUT_ENABLE; + always @(negedge INPUT_CLK) clken_pulled_ri <= clken_pulled; + always @(negedge INPUT_CLK) if (clken_pulled) din_q_0 <= PACKAGE_PIN; + always @(posedge INPUT_CLK) if (clken_pulled_ri) din_q_1 <= PACKAGE_PIN; + always @(negedge OUTPUT_CLK) clken_pulled_ro <= clken_pulled; + always @(negedge OUTPUT_CLK) if (clken_pulled) dout_q_0 <= D_OUT_0; + always @(posedge OUTPUT_CLK) if (clken_pulled_ro) dout_q_1 <= D_OUT_1; + always @(negedge OUTPUT_CLK) if (clken_pulled) outena_q <= OUTPUT_ENABLE; end endgenerate always @* begin @@ -326,6 +335,8 @@ module SB_RAM40_4K ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + `ifndef BLACKBOX wire [15:0] WMASK_I; wire [15:0] RMASK_I; @@ -408,43 +419,27 @@ module SB_RAM40_4K ( reg [15:0] memory [0:255]; initial begin - for (i=0; i<16; i=i+1) begin -`ifdef YOSYS - memory[ 0*16 + i] <= INIT_0[16*i +: 16]; - memory[ 1*16 + i] <= INIT_1[16*i +: 16]; - memory[ 2*16 + i] <= INIT_2[16*i +: 16]; - memory[ 3*16 + i] <= INIT_3[16*i +: 16]; - memory[ 4*16 + i] <= INIT_4[16*i +: 16]; - memory[ 5*16 + i] <= INIT_5[16*i +: 16]; - memory[ 6*16 + i] <= INIT_6[16*i +: 16]; - memory[ 7*16 + i] <= INIT_7[16*i +: 16]; - memory[ 8*16 + i] <= INIT_8[16*i +: 16]; - memory[ 9*16 + i] <= INIT_9[16*i +: 16]; - memory[10*16 + i] <= INIT_A[16*i +: 16]; - memory[11*16 + i] <= INIT_B[16*i +: 16]; - memory[12*16 + i] <= INIT_C[16*i +: 16]; - memory[13*16 + i] <= INIT_D[16*i +: 16]; - memory[14*16 + i] <= INIT_E[16*i +: 16]; - memory[15*16 + i] <= INIT_F[16*i +: 16]; -`else - memory[ 0*16 + i] = INIT_0[16*i +: 16]; - memory[ 1*16 + i] = INIT_1[16*i +: 16]; - memory[ 2*16 + i] = INIT_2[16*i +: 16]; - memory[ 3*16 + i] = INIT_3[16*i +: 16]; - memory[ 4*16 + i] = INIT_4[16*i +: 16]; - memory[ 5*16 + i] = INIT_5[16*i +: 16]; - memory[ 6*16 + i] = INIT_6[16*i +: 16]; - memory[ 7*16 + i] = INIT_7[16*i +: 16]; - memory[ 8*16 + i] = INIT_8[16*i +: 16]; - memory[ 9*16 + i] = INIT_9[16*i +: 16]; - memory[10*16 + i] = INIT_A[16*i +: 16]; - memory[11*16 + i] = INIT_B[16*i +: 16]; - memory[12*16 + i] = INIT_C[16*i +: 16]; - memory[13*16 + i] = INIT_D[16*i +: 16]; - memory[14*16 + i] = INIT_E[16*i +: 16]; - memory[15*16 + i] = INIT_F[16*i +: 16]; -`endif - end + if (INIT_FILE != "") + $readmemh(INIT_FILE, memory); + else + for (i=0; i<16; i=i+1) begin + memory[ 0*16 + i] = INIT_0[16*i +: 16]; + memory[ 1*16 + i] = INIT_1[16*i +: 16]; + memory[ 2*16 + i] = INIT_2[16*i +: 16]; + memory[ 3*16 + i] = INIT_3[16*i +: 16]; + memory[ 4*16 + i] = INIT_4[16*i +: 16]; + memory[ 5*16 + i] = INIT_5[16*i +: 16]; + memory[ 6*16 + i] = INIT_6[16*i +: 16]; + memory[ 7*16 + i] = INIT_7[16*i +: 16]; + memory[ 8*16 + i] = INIT_8[16*i +: 16]; + memory[ 9*16 + i] = INIT_9[16*i +: 16]; + memory[10*16 + i] = INIT_A[16*i +: 16]; + memory[11*16 + i] = INIT_B[16*i +: 16]; + memory[12*16 + i] = INIT_C[16*i +: 16]; + memory[13*16 + i] = INIT_D[16*i +: 16]; + memory[14*16 + i] = INIT_E[16*i +: 16]; + memory[15*16 + i] = INIT_F[16*i +: 16]; + end end always @(posedge WCLK) begin @@ -504,6 +499,8 @@ module SB_RAM40_4KNR ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -522,7 +519,8 @@ module SB_RAM40_4KNR ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -566,6 +564,8 @@ module SB_RAM40_4KNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -584,7 +584,8 @@ module SB_RAM40_4KNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (RCLK ), @@ -628,6 +629,8 @@ module SB_RAM40_4KNRNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -646,7 +649,8 @@ module SB_RAM40_4KNRNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -926,10 +930,21 @@ endmodule (* blackbox *) module SB_HFOSC( + input TRIM0, + input TRIM1, + input TRIM2, + input TRIM3, + input TRIM4, + input TRIM5, + input TRIM6, + input TRIM7, + input TRIM8, + input TRIM9, input CLKHFPU, input CLKHFEN, output CLKHF ); +parameter TRIM_EN = "0b0"; parameter CLKHF_DIV = "0b00"; endmodule @@ -959,6 +974,30 @@ parameter RGB2_CURRENT = "0b000000"; endmodule (* blackbox *) +module SB_LED_DRV_CUR( + input EN, + output LEDPU +); +endmodule + +(* blackbox *) +module SB_RGB_DRV( + input RGBLEDEN, + input RGB0PWM, + input RGB1PWM, + input RGB2PWM, + input RGBPU, + output RGB0, + output RGB1, + output RGB2 +); +parameter CURRENT_MODE = "0b0"; +parameter RGB0_CURRENT = "0b000000"; +parameter RGB1_CURRENT = "0b000000"; +parameter RGB2_CURRENT = "0b000000"; +endmodule + +(* blackbox *) module SB_I2C( input SBCLKI, input SBRWI, diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc new file mode 100644 index 000000000..4fa6b0792 --- /dev/null +++ b/techlibs/ice40/ice40_braminit.cc @@ -0,0 +1,159 @@ +/* + * 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" +#include <stdlib.h> +#include <stdio.h> +#include <bitset> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +static void run_ice40_braminit(Module *module) +{ + for (auto cell : module->selected_cells()) + { + uint16_t mem[256]; + + /* Only consider cells we're interested in */ + if (cell->type != "\\SB_RAM40_4K" && + cell->type != "\\SB_RAM40_4KNR" && + cell->type != "\\SB_RAM40_4KNW" && + cell->type != "\\SB_RAM40_4KNRNW") + continue; + if (!cell->hasParam("\\INIT_FILE")) + continue; + std::string init_file = cell->getParam("\\INIT_FILE").decode_string(); + cell->unsetParam("\\INIT_FILE"); + if (init_file == "") + continue; + + /* Open file */ + log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str()); + + std::ifstream f; + f.open(init_file.c_str()); + if (f.fail()) { + log("Can not open file `%s`.\n", init_file.c_str()); + continue; + } + + /* Defaults to 0 */ + memset(mem, 0x00, sizeof(mem)); + + /* Process each line */ + bool in_comment = false; + int cursor = 0; + + while (!f.eof()) + { + std::string line, token; + std::getline(f, line); + + for (int i = 0; i < GetSize(line); i++) + { + if (in_comment && line.substr(i, 2) == "*/") { + line[i] = ' '; + line[i+1] = ' '; + in_comment = false; + continue; + } + if (!in_comment && line.substr(i, 2) == "/*") + in_comment = true; + if (in_comment) + line[i] = ' '; + } + + while (1) + { + bool set_cursor = false; + long value; + + token = next_token(line, " \t\r\n"); + if (token.empty() || token.substr(0, 2) == "//") + break; + + if (token[0] == '@') { + token = token.substr(1); + set_cursor = true; + } + + const char *nptr = token.c_str(); + char *endptr; + value = strtol(nptr, &endptr, 16); + if (!*nptr || *endptr) { + log("Can not parse %s `%s` for %s.\n", + set_cursor ? "address" : "value", + nptr, token.c_str() + ); + continue; + } + + if (set_cursor) + cursor = value; + else if (cursor >= 0 && cursor < 256) + mem[cursor++] = value; + else + log("Attempt to initialize non existent address %d\n", cursor); + } + } + + /* Set attributes */ + const char *hex = "0123456789ABCDEF"; + for (int i=0; i<16; i++) { + std::string val = ""; + for (int j=15; j>=0; j--) + val += std::bitset<16>(mem[i*16+j]).to_string(); + cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val)); + } + } +} + +struct Ice40BRAMInitPass : public Pass { + Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_braminit\n"); + log("\n"); + log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n"); + log("parameter and converts it into the required INIT_x attributes\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_BRAMINIT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-???") { + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + run_ice40_braminit(module); + } +} Ice40BRAMInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 34501b335..bb96d66d1 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -225,11 +225,13 @@ struct SynthIce40Pass : public ScriptPass run("proc"); } - if (flatten && check_label("flatten", "(unless -noflatten)")) + if (check_label("flatten", "(unless -noflatten)")) { - run("flatten"); - run("tribuf -logic"); - run("deminout"); + if (flatten) { + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } } if (check_label("coarse")) @@ -239,6 +241,8 @@ struct SynthIce40Pass : public ScriptPass run("check"); run("opt"); run("wreduce"); + run("peepopt"); + run("opt_clean"); run("share"); run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); run("opt_expr"); @@ -257,6 +261,7 @@ struct SynthIce40Pass : public ScriptPass { run("memory_bram -rules +/ice40/brams.txt"); run("techmap -map +/ice40/brams_map.v"); + run("ice40_braminit"); } if (check_label("map")) diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index b3a11272b..49e36aa25 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -32,7 +32,7 @@ module fa wire VCC; assign VCC = 1'b1; - + cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x), .dataa(a_c), .datab(b_c), @@ -40,7 +40,7 @@ module fa .datad(VCC)); defparam syn__05_.lut_mask = 16'b1001011010010110; defparam syn__05_.sum_lutc_input = "datac"; - + cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t), .dataa(cin_c), .datab(b_c), @@ -48,11 +48,11 @@ module fa .datad(VCC)); defparam syn__06_.lut_mask = 16'b1110000011100000; defparam syn__06_.sum_lutc_input = "datac"; - + endmodule // fa module f_stage(); - + endmodule // f_stage module f_end(); @@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); .cin_c(C[0]), .cout_t(C0[1]), .sum_x(Y[0])); - + genvar i; generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i])); diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index bd60d4e17..f8d142bc9 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -76,7 +76,7 @@ module \$lut (A, Y); wire VCC; wire GND; assign {VCC,GND} = {1'b1,1'b0}; - + generate if (WIDTH == 1) begin assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function @@ -151,7 +151,7 @@ module \$lut (A, Y); TODO: There's not a just 7-input function on Cyclone V, see the following note: **Extended LUT Mode** Use extended LUT mode to implement a specific set of 7-input functions. The set must - be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. + be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. [source](Device Interfaces and Integration Basics for Cyclone V Devices). end*/ else diff --git a/techlibs/intel/cyclonev/cells_sim.v b/techlibs/intel/cyclonev/cells_sim.v index fa27c2c8e..9b2a10e72 100644 --- a/techlibs/intel/cyclonev/cells_sim.v +++ b/techlibs/intel/cyclonev/cells_sim.v @@ -85,7 +85,7 @@ module cyclonev_lcell_comb begin upper_lut_value = lut4(mask[31:16], dataa, datab, datac, datad); lower_lut_value = lut4(mask[15:0], dataa, datab, datac, datad); - lut5 = (datae) ? upper_mask_value : lower_mask_value; + lut5 = (datae) ? upper_lut_value : lower_lut_value; end endfunction // lut5 @@ -95,15 +95,16 @@ module cyclonev_lcell_comb input dataa, datab, datac, datad, datae, dataf; reg upper_lut_value; reg lower_lut_value; + reg out_0, out_1, out_2, out_3; begin upper_lut_value = lut5(mask[63:32], dataa, datab, datac, datad, datae); lower_lut_value = lut5(mask[31:0], dataa, datab, datac, datad, datae); - lut6 = (dataf) ? upper_mask_value : lower_mask_value; + lut6 = (dataf) ? upper_lut_value : lower_lut_value; end endfunction // lut6 assign {mask_a, mask_b, mask_c, mask_d} = {lut_mask[15:0], lut_mask[31:16], lut_mask[47:32], lut_mask[63:48]}; - +`ifdef ADVANCED_ALM always @(*) begin if(extended_lut == "on") shared_lut_alm = datag; @@ -115,6 +116,11 @@ module cyclonev_lcell_comb out_2 = lut4(mask_c, dataa, datab, datac, datad); out_3 = lut4(mask_d, dataa, datab, shared_lut_alm, datad); end +`else + `ifdef DEBUG + initial $display("Advanced ALM lut combine is not implemented yet"); + `endif +`endif endmodule // cyclonev_lcell_comb diff --git a/techlibs/intel/synth_intel.cc b/techlibs/intel/synth_intel.cc index 0f1d7a7b5..639cba2c2 100644 --- a/techlibs/intel/synth_intel.cc +++ b/techlibs/intel/synth_intel.cc @@ -17,254 +17,243 @@ * */ -#include "kernel/register.h" #include "kernel/celltypes.h" -#include "kernel/rtlil.h" #include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN struct SynthIntelPass : public ScriptPass { - SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") { } + SynthIntelPass() : ScriptPass("synth_intel", "synthesis for Intel (Altera) FPGAs.") {} - void help() YS_OVERRIDE - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_intel [options]\n"); - log("\n"); - log("This command runs synthesis for Intel FPGAs.\n"); - log("\n"); - log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); - log(" generate the synthesis netlist for the specified family.\n"); - log(" MAX10 is the default target if not family argument specified.\n"); - log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); - log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); - log("\n"); - log(" -top <module>\n"); - log(" use the specified module as top module (default='top')\n"); - log("\n"); - log(" -vqm <file>\n"); - log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); - log(" output file is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -vpr <file>\n"); - log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); - log(" compatible with the Quartus flow. Writing of an\n"); - log(" output file is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run <from_label>:<to_label>\n"); - log(" only run the commands between the labels (see below). an empty\n"); - log(" from label is synonymous to 'begin', and empty to label is\n"); - log(" synonymous to the end of the command list.\n"); - log("\n"); - log(" -noiopads\n"); - log(" do not use altsyncram cells in output netlist\n"); - log("\n"); - log(" -nobram\n"); - log(" do not use altsyncram 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("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_intel [options]\n"); + log("\n"); + log("This command runs synthesis for Intel FPGAs.\n"); + log("\n"); + log(" -family < max10 | a10gx | cyclone10 | cyclonev | cycloneiv | cycloneive>\n"); + log(" generate the synthesis netlist for the specified family.\n"); + log(" MAX10 is the default target if not family argument specified.\n"); + log(" For Cyclone GX devices, use cycloneiv argument; For Cyclone E, use cycloneive.\n"); + log(" Cyclone V and Arria 10 GX devices are experimental, use it with a10gx argument.\n"); + log("\n"); + log(" -top <module>\n"); + log(" use the specified module as top module (default='top')\n"); + log("\n"); + log(" -vqm <file>\n"); + log(" write the design to the specified Verilog Quartus Mapping File. Writing of an\n"); + log(" output file is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -vpr <file>\n"); + log(" write BLIF files for VPR flow experiments. The synthesized BLIF output file is not\n"); + log(" compatible with the Quartus flow. Writing of an\n"); + log(" output file is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run <from_label>:<to_label>\n"); + log(" only run the commands between the labels (see below). an empty\n"); + log(" from label is synonymous to 'begin', and empty to label is\n"); + log(" synonymous to the end of the command list.\n"); + log("\n"); + log(" -noiopads\n"); + log(" do not use altsyncram cells in output netlist\n"); + log("\n"); + log(" -nobram\n"); + log(" do not use altsyncram 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("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } - string top_opt, family_opt, vout_file, blif_file; - bool retime, flatten, nobram, noiopads; + string top_opt, family_opt, vout_file, blif_file; + bool retime, flatten, nobram, noiopads; - void clear_flags() YS_OVERRIDE - { - top_opt = "-auto-top"; - family_opt = "max10"; - vout_file = ""; - blif_file = ""; - retime = false; - flatten = true; - nobram = false; - noiopads = false; - } + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + family_opt = "max10"; + vout_file = ""; + blif_file = ""; + retime = false; + flatten = true; + nobram = false; + noiopads = false; + } - void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE - { - string run_from, run_to; - clear_flags(); + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + string run_from, run_to; + clear_flags(); - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-family" && argidx+1 < args.size()) { - family_opt = args[++argidx]; - continue; - } - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-vqm" && argidx+1 < args.size()) { - vout_file = args[++argidx]; - continue; - } - if (args[argidx] == "-vpr" && argidx+1 < args.size()) { - blif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if (args[argidx] == "-noiopads") { - noiopads = true; - continue; - } - if (args[argidx] == "-nobram") { - nobram = true; - continue; - } - if (args[argidx] == "-noflatten") { - flatten = false; - continue; - } - if (args[argidx] == "-retime") { - retime = true; - continue; - } - break; - } - extra_args(args, argidx, design); + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-family" && argidx + 1 < args.size()) { + family_opt = args[++argidx]; + continue; + } + if (args[argidx] == "-top" && argidx + 1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if (args[argidx] == "-vqm" && argidx + 1 < args.size()) { + vout_file = args[++argidx]; + continue; + } + if (args[argidx] == "-vpr" && argidx + 1 < args.size()) { + blif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos + 1); + continue; + } + if (args[argidx] == "-noiopads") { + noiopads = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + break; + } + extra_args(args, argidx, design); - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - if (family_opt != "max10" && family_opt !="a10gx" && family_opt != "cyclonev" && family_opt !="cycloneiv" && family_opt !="cycloneive" && family_opt != "cyclone10") - log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str()); + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + if (family_opt != "max10" && family_opt != "a10gx" && family_opt != "cyclonev" && family_opt != "cycloneiv" && + family_opt != "cycloneive" && family_opt != "cyclone10") + log_cmd_error("Invalid or not family specified: '%s'\n", family_opt.c_str()); - log_header(design, "Executing SYNTH_INTEL pass.\n"); - log_push(); + log_header(design, "Executing SYNTH_INTEL pass.\n"); + log_push(); - run_script(design, run_from, run_to); + run_script(design, run_from, run_to); - log_pop(); - } + log_pop(); + } - void script() YS_OVERRIDE - { - if (check_label("begin")) - { - if(check_label("family") && family_opt=="max10") - run("read_verilog -sv -lib +/intel/max10/cells_sim.v"); - else if(check_label("family") && family_opt=="a10gx") - run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v"); - else if(check_label("family") && family_opt=="cyclonev") - run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v"); - else if(check_label("family") && family_opt=="cyclone10") - run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v"); - else if(check_label("family") && family_opt=="cycloneiv") - run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v"); - else - run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v"); - // Misc and common cells - run("read_verilog -sv -lib +/intel/common/m9k_bb.v"); - run("read_verilog -sv -lib +/intel/common/altpll_bb.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); - } + void script() YS_OVERRIDE + { + if (check_label("begin")) { + if (check_label("family") && family_opt == "max10") + run("read_verilog -sv -lib +/intel/max10/cells_sim.v"); + else if (check_label("family") && family_opt == "a10gx") + run("read_verilog -sv -lib +/intel/a10gx/cells_sim.v"); + else if (check_label("family") && family_opt == "cyclonev") + run("read_verilog -sv -lib +/intel/cyclonev/cells_sim.v"); + else if (check_label("family") && family_opt == "cyclone10") + run("read_verilog -sv -lib +/intel/cyclone10/cells_sim.v"); + else if (check_label("family") && family_opt == "cycloneiv") + run("read_verilog -sv -lib +/intel/cycloneiv/cells_sim.v"); + else + run("read_verilog -sv -lib +/intel/cycloneive/cells_sim.v"); + // Misc and common cells + run("read_verilog -sv -lib +/intel/common/m9k_bb.v"); + run("read_verilog -sv -lib +/intel/common/altpll_bb.v"); + run(stringf("hierarchy -check %s", help_mode ? "-top <top>" : top_opt.c_str())); + } - if (flatten && check_label("flatten", "(unless -noflatten)")) - { - run("proc"); - run("flatten"); - run("tribuf -logic"); - run("deminout"); - } + if (flatten && check_label("flatten", "(unless -noflatten)")) { + run("proc"); + run("flatten"); + run("tribuf -logic"); + run("deminout"); + } - if (check_label("coarse")) - { - run("synth -run coarse"); - } + if (check_label("coarse")) { + run("synth -run coarse"); + } - if (!nobram && check_label("bram", "(skip if -nobram)")) - { - run("memory_bram -rules +/intel/common/brams.txt"); - run("techmap -map +/intel/common/brams_map.v"); - } + if (!nobram && check_label("bram", "(skip if -nobram)")) { + run("memory_bram -rules +/intel/common/brams.txt"); + run("techmap -map +/intel/common/brams_map.v"); + } - if (check_label("fine")) - { - run("opt -fast -mux_undef -undriven -fine -full"); - run("memory_map"); - run("opt -undriven -fine"); - run("dffsr2dff"); - run("dff2dffe -direct-match $_DFF_*"); - run("opt -fine"); - run("techmap -map +/techmap.v"); - run("opt -full"); - run("clean -purge"); - run("setundef -undriven -zero"); - if (retime || help_mode) - run("abc -markgroups -dff", "(only if -retime)"); - } + if (check_label("fine")) { + run("opt -fast -mux_undef -undriven -fine -full"); + run("memory_map"); + run("opt -undriven -fine"); + run("dffsr2dff"); + run("dff2dffe -direct-match $_DFF_*"); + run("opt -fine"); + run("techmap -map +/techmap.v"); + run("opt -full"); + run("clean -purge"); + run("setundef -undriven -zero"); + if (retime || help_mode) + run("abc -markgroups -dff", "(only if -retime)"); + } - if (check_label("map_luts")) - { - if(family_opt=="a10gx" || family_opt=="cyclonev") - run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); - else - run("abc -lut 4" + string(retime ? " -dff" : "")); - run("clean"); - } + if (check_label("map_luts")) { + if (family_opt == "a10gx" || family_opt == "cyclonev") + run("abc -luts 2:2,3,6:5" + string(retime ? " -dff" : "")); + else + run("abc -lut 4" + string(retime ? " -dff" : "")); + run("clean"); + } - if (check_label("map_cells")) - { - if (!noiopads) - run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); - if(family_opt=="max10") - run("techmap -map +/intel/max10/cells_map.v"); - else if(family_opt=="a10gx") - run("techmap -map +/intel/a10gx/cells_map.v"); - else if(family_opt=="cyclonev") - run("techmap -map +/intel/cyclonev/cells_map.v"); - else if(family_opt=="cyclone10") - run("techmap -map +/intel/cyclone10/cells_map.v"); - else if(family_opt=="cycloneiv") - run("techmap -map +/intel/cycloneiv/cells_map.v"); - else - run("techmap -map +/intel/cycloneive/cells_map.v"); - run("dffinit -highlow -ff dffeas q power_up"); - run("clean -purge"); - } + if (check_label("map_cells")) { + if (!noiopads) + run("iopadmap -bits -outpad $__outpad I:O -inpad $__inpad O:I", "(unless -noiopads)"); + if (family_opt == "max10") + run("techmap -map +/intel/max10/cells_map.v"); + else if (family_opt == "a10gx") + run("techmap -map +/intel/a10gx/cells_map.v"); + else if (family_opt == "cyclonev") + run("techmap -map +/intel/cyclonev/cells_map.v"); + else if (family_opt == "cyclone10") + run("techmap -map +/intel/cyclone10/cells_map.v"); + else if (family_opt == "cycloneiv") + run("techmap -map +/intel/cycloneiv/cells_map.v"); + else + run("techmap -map +/intel/cycloneive/cells_map.v"); + run("dffinit -highlow -ff dffeas q power_up"); + run("clean -purge"); + } - if (check_label("check")) - { - run("hierarchy -check"); - run("stat"); - run("check -noinit"); - } + if (check_label("check")) { + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + } - if (check_label("vqm")) - { - if (!vout_file.empty() || help_mode) - run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", - help_mode ? "<file-name>" : vout_file.c_str())); - } + if (check_label("vqm")) { + if (!vout_file.empty() || help_mode) + run(stringf("write_verilog -attr2comment -defparam -nohex -decimal -renameprefix syn_ %s", + help_mode ? "<file-name>" : vout_file.c_str())); + } - if (check_label("vpr")) - { - if (!blif_file.empty() || help_mode) - { - run(stringf("opt_clean -purge")); - run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); - } - } - } + if (check_label("vpr")) { + if (!blif_file.empty() || help_mode) { + run(stringf("opt_clean -purge")); + run(stringf("write_blif %s", help_mode ? "<file-name>" : blif_file.c_str())); + } + } + } } SynthIntelPass; PRIVATE_NAMESPACE_END diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 5b8888294..6ad7807d2 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -1,40 +1,54 @@ -// module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule +module \$_DFF_N_ (input D, C, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule module \$_DFF_P_ (input D, C, output Q); - SLE _TECHMAP_REPLACE_ ( - .D(D), - .CLK(C), - .EN(1'b1), - .ALn(1'b1), - .ADn(1'b1), - .SLn(1'b1), - .SD(1'b0), - .LAT(1'b0), - .Q(Q) - ); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); endmodule // module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule // module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -// +// // module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule // module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -// -// module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -// module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -// module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -// module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -// -// module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -// module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -// module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -// module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -// +// // module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule // module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -// +// // module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule // module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule // module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index f967068af..c62748b11 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -1,3 +1,114 @@ +// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf + +module ADD2 ( + + input A, B, + output Y +); + assign Y = A & B; +endmodule + +module ADD3 ( + input A, B, C, + output Y +); + assign Y = A & B & C; +endmodule + +module ADD4 ( + input A, B, C, D, + output Y +); + assign Y = A & B & C & D; +endmodule + +module CFG1 ( + output Y, + input A +); + parameter [1:0] INIT = 2'h0; + assign Y = INIT >> A; +endmodule + +module CFG2 ( + output Y, + input A, + input B +); + parameter [3:0] INIT = 4'h0; + assign Y = INIT >> {B, A}; +endmodule + +module CFG3 ( + output Y, + input A, + input B, + input C +); + parameter [7:0] INIT = 8'h0; + assign Y = INIT >> {C, B, A}; +endmodule + +module CFG4 ( + output Y, + input A, + input B, + input C, + input D +); + parameter [15:0] INIT = 16'h0; + assign Y = INIT >> {D, C, B, A}; +endmodule + +module BUFF ( + input A, + output Y +); + assign Y = A; +endmodule + +module BUFD ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT_PRESERVE ( + input A, + output Y +); + assign Y = A; +endmodule + +module GCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + +module RCLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module RGCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + module SLE ( output Q, input ADn, @@ -36,44 +147,151 @@ module SLE ( assign Q = LAT ? q_latch : q_ff; endmodule -module CFG1 ( - output Y, - input A +// module AR1 +// module FCEND_BUFF +// module FCINIT_BUFF +// module FLASH_FREEZE +// module OSCILLATOR +// module SYSRESET +// module SYSCTRL_RESET_STATUS +// module LIVE_PROBE_FB +// module GCLKBUF +// module GCLKBUF_DIFF +// module GCLKBIBUF +// module DFN1 +// module DFN1C0 +// module DFN1E1 +// module DFN1E1C0 +// module DFN1E1P0 +// module DFN1P0 +// module DLN1 +// module DLN1C0 +// module DLN1P0 + +module INV ( + input A, + output Y ); - parameter [1:0] INIT = 2'h0; - assign Y = INIT >> A; + assign Y = !A; endmodule -module CFG2 ( - output Y, +module INVD ( input A, - input B + output Y ); - parameter [3:0] INIT = 4'h0; - assign Y = INIT >> {B, A}; + assign Y = !A; endmodule -module CFG3 ( - output Y, - input A, - input B, - input C +module MX2 ( + input A, B, S, + output Y ); - parameter [7:0] INIT = 8'h0; - assign Y = INIT >> {C, B, A}; + assign Y = S ? B : A; endmodule -module CFG4 ( - output Y, - input A, - input B, - input C, - input D +module MX4 ( + input D0, D1, D2, D3, S0, S1, + output Y ); - parameter [15:0] INIT = 16'h0; - assign Y = INIT >> {D, C, B, A}; + assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0); +endmodule + +module NAND2 ( + input A, B, + output Y +); + assign Y = !(A & B); +endmodule + +module NAND3 ( + input A, B, C, + output Y +); + assign Y = !(A & B & C); +endmodule + +module NAND4 ( + input A, B, C, D, + output Y +); + assign Y = !(A & B & C & D); +endmodule + +module NOR2 ( + input A, B, + output Y +); + assign Y = !(A | B); +endmodule + +module NOR3 ( + input A, B, C, + output Y +); + assign Y = !(A | B | C); +endmodule + +module NOR4 ( + input A, B, C, D, + output Y +); + assign Y = !(A | B | C | D); endmodule +module OR2 ( + input A, B, + output Y +); + assign Y = A | B; +endmodule + +module OR3 ( + input A, B, C, + output Y +); + assign Y = A | B | C; +endmodule + +module OR4 ( + input A, B, C, D, + output Y +); + assign Y = A | B | C | D; +endmodule + +module XOR2 ( + input A, B, + output Y +); + assign Y = A ^ B; +endmodule + +module XOR3 ( + input A, B, C, + output Y +); + assign Y = A ^ B ^ C; +endmodule + +module XOR4 ( + input A, B, C, D, + output Y +); + assign Y = A ^ B ^ C ^ D; +endmodule + +module XOR8 ( + input A, B, C, D, E, F, G, H, + output Y +); + assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H; +endmodule + +// module UJTAG +// module BIBUF +// module BIBUF_DIFF +// module CLKBIBUF + module CLKBUF ( input PAD, output Y @@ -81,6 +299,8 @@ module CLKBUF ( assign Y = PAD; endmodule +// module CLKBUF_DIFF + module INBUF ( input PAD, output Y @@ -88,9 +308,20 @@ module INBUF ( assign Y = PAD; endmodule +// module INBUF_DIFF + module OUTBUF ( input D, output PAD ); assign PAD = D; endmodule + +// module OUTBUF_DIFF +// module TRIBUFF +// module TRIBUFF_DIFF +// module DDR_IN +// module DDR_OUT +// module RAM1K18 +// module RAM64x18 +// module MACC diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index 27141430c..3d43332e2 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -23,6 +23,136 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static void handle_iobufs(Module *module, bool clkbuf_mode) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + pool<SigBit> handled_io_bits; + dict<SigBit, SigBit> rewrite_bits; + vector<pair<Cell*, SigBit>> pad_bits; + + for (auto cell : module->cells()) + { + if (clkbuf_mode && cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF", + "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF", + "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) { + for (auto bit : sigmap(cell->getPort("\\PAD"))) + handled_io_bits.insert(bit); + } + } + + for (auto wire : vector<Wire*>(module->wires())) + { + if (!wire->port_input && !wire->port_output) + continue; + + for (int index = 0; index < GetSize(wire); index++) + { + SigBit bit(wire, index); + SigBit canonical_bit = sigmap(bit); + + if (handled_io_bits.count(canonical_bit)) + continue; + + if (wire->port_input && wire->port_output) + log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); + + IdString buf_type, buf_port; + + if (wire->port_output) { + buf_type = "\\OUTBUF"; + buf_port = "\\D"; + } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { + buf_type = "\\CLKBUF"; + buf_port = "\\Y"; + } else { + buf_type = "\\INBUF"; + buf_port = "\\Y"; + } + + Cell *c = module->addCell(NEW_ID, buf_type); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort(buf_port, new_bit); + pad_bits.push_back(make_pair(c, bit)); + rewrite_bits[canonical_bit] = new_bit; + + log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + } + } + + auto rewrite_function = [&](SigSpec &s) { + for (auto &bit : s) { + SigBit canonical_bit = sigmap(bit); + if (rewrite_bits.count(canonical_bit)) + bit = rewrite_bits.at(canonical_bit); + } + }; + + module->rewrite_sigspecs(rewrite_function); + + for (auto &it : pad_bits) + it.first->setPort("\\PAD", it.second); +} + +static void handle_clkint(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + vector<SigBit> handled_clk_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF", + "\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) { + for (auto bit : sigmap(cell->getPort("\\Y"))) + handled_clk_bits.push_back(bit); + } + } + + for (auto bit : handled_clk_bits) + clk_bits.erase(bit); + + for (auto cell : vector<Cell*>(module->cells())) + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec sig = conn.second; + bool did_something = false; + + for (auto &bit : sig) { + SigBit canonical_bit = sigmap(bit); + if (clk_bits.count(canonical_bit)) { + Cell *c = module->addCell(NEW_ID, "\\CLKINT"); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort("\\A", new_bit); + c->setPort("\\Y", bit); + log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + clk_bits.erase(canonical_bit); + did_something = true; + bit = new_bit; + } + } + + if (did_something) + cell->setPort(conn.first, sig); + } + + for (auto bit : clk_bits) + log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit)); +} + struct Sf2IobsPass : public Pass { Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { } void help() YS_OVERRIDE @@ -31,20 +161,25 @@ struct Sf2IobsPass : public Pass { log("\n"); log(" sf2_iobs [options] [selection]\n"); log("\n"); - log("Add SF2 I/O buffers to top module IOs as needed.\n"); + log("Add SF2 I/O buffers and global buffers to top module as needed.\n"); + log("\n"); + log(" -clkbuf\n"); + log(" Insert PAD->global_net clock buffers\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + bool clkbuf_mode = false; + log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-singleton") { - // singleton_mode = true; - // continue; - // } + if (args[argidx] == "-clkbuf") { + clkbuf_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -54,76 +189,8 @@ struct Sf2IobsPass : public Pass { if (module == nullptr) log_cmd_error("No top module found.\n"); - SigMap sigmap(module); - - pool<SigBit> clk_bits; - pool<SigBit> handled_io_bits; - dict<SigBit, SigBit> rewrite_bits; - vector<pair<Cell*, SigBit>> pad_bits; - - for (auto cell : module->cells()) - { - if (cell->type == "\\SLE") { - for (auto bit : sigmap(cell->getPort("\\CLK"))) - clk_bits.insert(bit); - } - if (cell->type.in("\\INBUF", "\\OUTBUF", "\\CLKBUF")) { - for (auto bit : sigmap(cell->getPort("\\PAD"))) - handled_io_bits.insert(bit); - } - } - - for (auto wire : vector<Wire*>(module->wires())) - { - if (!wire->port_input && !wire->port_output) - continue; - - for (int index = 0; index < GetSize(wire); index++) - { - SigBit bit(wire, index); - SigBit canonical_bit = sigmap(bit); - - if (handled_io_bits.count(canonical_bit)) - continue; - - if (wire->port_input && wire->port_output) - log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); - - IdString buf_type, buf_port; - - if (wire->port_output) { - buf_type = "\\OUTBUF"; - buf_port = "\\D"; - } else if (clk_bits.count(canonical_bit)) { - buf_type = "\\CLKBUF"; - buf_port = "\\Y"; - } else { - buf_type = "\\INBUF"; - buf_port = "\\Y"; - } - - Cell *c = module->addCell(NEW_ID, buf_type); - SigBit new_bit = module->addWire(NEW_ID); - c->setPort(buf_port, new_bit); - pad_bits.push_back(make_pair(c, bit)); - rewrite_bits[canonical_bit] = new_bit; - - log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - } - } - - auto rewrite_function = [&](SigSpec &s) { - for (auto &bit : s) { - SigBit canonical_bit = sigmap(bit); - if (rewrite_bits.count(canonical_bit)) - bit = rewrite_bits.at(canonical_bit); - } - }; - - module->rewrite_sigspecs(rewrite_function); - - for (auto &it : pad_bits) - it.first->setPort("\\PAD", it.second); + handle_iobufs(module, clkbuf_mode); + handle_clkint(module); } } Sf2IobsPass; diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index bdc20456d..0924df7a6 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass log(" -noiobs\n"); log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); log("\n"); + log(" -clkbuf\n"); + log(" insert direct PAD->global_net buffers\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); @@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass } string top_opt, edif_file, vlog_file, json_file; - bool flatten, retime, iobs; + bool flatten, retime, iobs, clkbuf; void clear_flags() YS_OVERRIDE { @@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass flatten = true; retime = false; iobs = true; + clkbuf = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass iobs = false; continue; } + if (args[argidx] == "-clkbuf") { + clkbuf = true; + continue; + } break; } extra_args(args, argidx, design); @@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { - if (iobs || help_mode) - run("sf2_iobs", "(unless -noiobs)"); + if (help_mode) + run("sf2_iobs [-clkbuf]", "(unless -noiobs)"); + else if (iobs) + run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs"); run("clean"); } diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 887ea27d9..d68f03bb4 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -28,7 +28,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 03719659b..09a5f07e8 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -17,6 +17,9 @@ * */ +// ============================================================================ +// LCU + (* techmap_celltype = "$lcu" *) module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; @@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO); wire _TECHMAP_FAIL_ = WIDTH <= 2; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; + wire [MAX_WIDTH-1:0] C = CO; + + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + wire [WIDTH-1:0] C = {CO, CI}; wire [WIDTH-1:0] S = P & ~G; - genvar i; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), @@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO); .O(CO[i]) ); end endgenerate + +`else + + wire [WIDTH-1:0] C = {CO, CI}; + wire [WIDTH-1:0] S = P & ~G; + + generate for (i = 0; i < WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + end endgenerate +`endif + endmodule + +// ============================================================================ +// ALU + (* techmap_celltype = "$alu" *) module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; @@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + parameter _TECHMAP_CONSTVAL_CI_ = 0; + parameter _TECHMAP_CONSTMSK_CI_ = 0; input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; @@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; - wire [Y_WIDTH-1:0] P = AA ^ BB; - wire [Y_WIDTH-1:0] G = AA & BB; - wire [Y_WIDTH-1:0] C = {CO, CI}; - wire [Y_WIDTH-1:0] S = P & ~G; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; + + wire [MAX_WIDTH-1:0] C = CO; genvar i; + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > Y_WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire CINIT; + // Carry chain. + // + // VPR requires that the carry chain never hit the fabric. The CO input + // to this techmap is the carry outputs for synthesis, e.g. might hit the + // fabric. + // + // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, + // e.g. off fabric dedicated chain. CO is the carry outputs that are + // available to the fabric. + wire [Y_WIDTH-1:0] CO_CHAIN; + wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; + + // If carry chain is being initialized to a constant, techmap the constant + // source. Otherwise techmap the fabric source. + generate for (i = 0; i < 1; i = i + 1) begin:slice + CARRY0 #(.CYINIT_FABRIC(1)) carry( + .CI_INIT(CI), + .DI(DI[0]), + .S(S[0]), + .CO_CHAIN(CO_CHAIN[0]), + .CO_FABRIC(CO[0]), + .O(Y[0]) + ); + end endgenerate + + generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + else + begin + CARRY carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + end endgenerate + + generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + else + begin + CARRY top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide + // a non-congested path to output the top of the carry chain. + // Registering the output of the CARRY block would solve this, but not + // all designs do that. + if((i+1) % 4 == 0) begin + CARRY0 carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + else + begin + CARRY carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + end endgenerate + +`else + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire [Y_WIDTH-1:0] C = {CO, CI}; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), - .DI(G[i]), + .DI(DI[i]), .S(S[i]), .O(CO[i]) ); @@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); ); end endgenerate - assign X = P; +`endif + + assign X = S; endmodule diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0771be0b9..40789ddbe 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -1,86 +1,156 @@ +/* + * 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. + * + */ -module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +// Convert negative-polarity reset to positive-polarity +(* techmap_celltype = "$_DFF_NN0_" *) +module _90_dff_nn0_to_np0 (input D, C, R, output Q); \$_DFF_NP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_PN0_" *) +module _90_dff_pn0_to_pp0 (input D, C, R, output Q); \$_DFF_PP0_ _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* techmap_celltype = "$_DFF_NN1_" *) +module _90_dff_nn1_to_np1 (input D, C, R, output Q); \$_DFF_NP1 _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(~R)); endmodule +(* 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 -module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$__SHREG_ (input C, input D, input E, output Q); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; -module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule + \$__XILINX_SHREG_ #(.DEPTH(DEPTH), .INIT(INIT), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(DEPTH-1), .E(E), .Q(Q)); +endmodule -module \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule +module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, output SO); + parameter DEPTH = 0; + parameter [DEPTH-1:0] INIT = 0; + parameter CLKPOL = 1; + parameter ENPOL = 2; -`ifndef NO_LUT -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; + // shregmap's INIT parameter shifts out LSB first; + // however Xilinx expects MSB first + function [DEPTH-1:0] brev; + input [DEPTH-1:0] din; + integer i; + begin + for (i = 0; i < DEPTH; i=i+1) + brev[i] = din[DEPTH-1-i]; + end + endfunction + localparam [DEPTH-1:0] INIT_R = brev(INIT); - input [WIDTH-1:0] A; - output Y; + parameter _TECHMAP_CONSTMSK_L_ = 0; + parameter _TECHMAP_CONSTVAL_L_ = 0; + wire CE; generate - if (WIDTH == 1) begin - LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0])); - end else - if (WIDTH == 2) begin - LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1])); - end else - if (WIDTH == 3) begin - LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2])); + if (ENPOL == 0) + assign CE = ~E; + else if (ENPOL == 1) + assign CE = E; + else + assign CE = 1'b1; + if (DEPTH == 1) begin + if (CLKPOL) + FDRE #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); + else + FDRE_1 #(.INIT(INIT_R)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(CE), .R(1'b0)); end else - if (WIDTH == 4) begin - LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3])); + if (DEPTH <= 16) begin + SRL16E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A0(L[0]), .A1(L[1]), .A2(L[2]), .A3(L[3]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (WIDTH == 5) begin - LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4])); + if (DEPTH > 17 && DEPTH <= 32) begin + SRLC32E #(.INIT(INIT_R), .IS_CLK_INVERTED(~CLKPOL[0])) _TECHMAP_REPLACE_ (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(Q)); end else - if (WIDTH == 6) begin - LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); + if (DEPTH > 33 && DEPTH <= 64) begin + wire T0, T1, T2; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-32), .INIT(INIT[DEPTH-32-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L), .E(E), .Q(T2)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T2; + else + MUXF7 fpga_mux_0 (.O(Q), .I0(T0), .I1(T2), .S(L[5])); end else - if (WIDTH == 7) begin - wire T0, T1; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); + if (DEPTH > 65 && DEPTH <= 96) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-64), .INIT(INIT[DEPTH-64-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_2 (.C(C), .D(T3), .L(L[4:0]), .E(E), .Q(T4)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T4; + else begin + MUXF7 fpga_mux_0 (.O(T5), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T6), .I0(T4), .I1(1'b0 /* unused */), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T5), .I1(T6), .S(L[6])); + end end else - if (WIDTH == 8) begin - wire T0, T1, T2, T3, T4, T5; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); - MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); - MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); - end else begin - wire _TECHMAP_FAIL_ = 1; + if (DEPTH > 97 && DEPTH < 128) begin + wire T0, T1, T2, T3, T4, T5, T6, T7, T8; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-96), .INIT(INIT[DEPTH-96-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_3 (.C(C), .D(T5), .L(L[4:0]), .E(E), .Q(T6)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else begin + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); + end + end + else if (DEPTH == 128) begin + wire T0, T1, T2, T3, T4, T5, T6; + SRLC32E #(.INIT(INIT_R[32-1:0]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_0 (.A(L[4:0]), .CE(CE), .CLK(C), .D(D), .Q(T0), .Q31(T1)); + SRLC32E #(.INIT(INIT_R[64-1:32]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_1 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T1), .Q(T2), .Q31(T3)); + SRLC32E #(.INIT(INIT_R[96-1:64]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_2 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T3), .Q(T4), .Q31(T5)); + SRLC32E #(.INIT(INIT_R[128-1:96]), .IS_CLK_INVERTED(~CLKPOL[0])) fpga_srl_3 (.A(L[4:0]), .CE(CE), .CLK(C), .D(T5), .Q(T6), .Q31(SO)); + if (&_TECHMAP_CONSTMSK_L_) + assign Q = T6; + else begin + wire T7, T8; + MUXF7 fpga_mux_0 (.O(T7), .I0(T0), .I1(T2), .S(L[5])); + MUXF7 fpga_mux_1 (.O(T8), .I0(T4), .I1(T6), .S(L[5])); + MUXF8 fpga_mux_2 (.O(Q), .I0(T7), .I1(T8), .S(L[6])); + end + end + else if (DEPTH <= 129 && ~&_TECHMAP_CONSTMSK_L_) begin + // Handle cases where fixed-length depth is + // just 1 over a convenient value + \$__XILINX_SHREG_ #(.DEPTH(DEPTH+1), .INIT({INIT,1'b0}), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) _TECHMAP_REPLACE_ (.C(C), .D(D), .L(L), .E(E), .Q(Q)); + end + else begin + localparam lower_clog2 = $clog2((DEPTH+1)/2); + localparam lower_depth = 2 ** lower_clog2; + wire T0, T1, T2, T3; + if (&_TECHMAP_CONSTMSK_L_) begin + \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(lower_depth-1), .E(E), .Q(T0)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T0), .L(DEPTH-lower_depth-1), .E(E), .Q(Q), .SO(T3)); + end + else begin + \$__XILINX_SHREG_ #(.DEPTH(lower_depth), .INIT(INIT[DEPTH-1:DEPTH-lower_depth]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_0 (.C(C), .D(D), .L(L[lower_clog2-1:0]), .E(E), .Q(T0), .SO(T1)); + \$__XILINX_SHREG_ #(.DEPTH(DEPTH-lower_depth), .INIT(INIT[DEPTH-lower_depth-1:0]), .CLKPOL(CLKPOL), .ENPOL(ENPOL)) fpga_srl_1 (.C(C), .D(T1), .L(L[lower_clog2-1:0]), .E(E), .Q(T2), .SO(T3)); + assign Q = L[lower_clog2] ? T2 : T0; + end + if (DEPTH == 2 * lower_depth) + assign SO = T3; end endgenerate endmodule + +`ifndef SRL_ONLY `endif diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index eba17ac9c..3a4540b83 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1,3 +1,21 @@ +/* + * 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. + * + */ // See Xilinx UG953 and UG474 for a description of the cell types below. // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf @@ -12,10 +30,15 @@ module GND(output G); endmodule module IBUF(output O, input I); + parameter IOSTANDARD = "default"; + parameter IBUF_LOW_PWR = 0; assign O = I; endmodule module OBUF(output O, input I); + parameter IOSTANDARD = "default"; + parameter DRIVE = 12; + parameter SLEW = "SLOW"; assign O = I; endmodule @@ -23,6 +46,42 @@ module BUFG(output O, input I); assign O = I; endmodule +module BUFGCTRL( + output O, + input I0, input I1, + input S0, input S1, + input CE0, input CE1, + input IGNORE0, input IGNORE1); + +parameter [0:0] INIT_OUT = 1'b0; +parameter PRESELECT_I0 = "FALSE"; +parameter PRESELECT_I1 = "FALSE"; +parameter [0:0] IS_CE0_INVERTED = 1'b0; +parameter [0:0] IS_CE1_INVERTED = 1'b0; +parameter [0:0] IS_S0_INVERTED = 1'b0; +parameter [0:0] IS_S1_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; +parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; + +wire I0_internal = ((CE0 ^ IS_CE0_INVERTED) ? I0 : INIT_OUT); +wire I1_internal = ((CE1 ^ IS_CE1_INVERTED) ? I1 : INIT_OUT); +wire S0_true = (S0 ^ IS_S0_INVERTED); +wire S1_true = (S1 ^ IS_S1_INVERTED); + +assign O = S0_true ? I0_internal : (S1_true ? I1_internal : INIT_OUT); + +endmodule + +module BUFHCE(output O, input I, input CE); + +parameter [0:0] INIT_OUT = 1'b0; +parameter CE_TYPE = "SYNC"; +parameter [0:0] IS_CE_INVERTED = 1'b0; + +assign O = ((CE ^ IS_CE_INVERTED) ? I : INIT_OUT); + +endmodule + // module OBUFT(output O, input I, T); // assign O = T ? 1'bz : I; // endmodule @@ -80,6 +139,22 @@ module LUT6(output O, input I0, I1, I2, I3, I4, I5); assign O = I0 ? s1[1] : s1[0]; endmodule +module LUT6_2(output O6, output O5, input I0, I1, I2, I3, I4, I5); + parameter [63:0] INIT = 0; + wire [31: 0] s5 = I5 ? INIT[63:32] : INIT[31: 0]; + wire [15: 0] s4 = I4 ? s5[31:16] : s5[15: 0]; + wire [ 7: 0] s3 = I3 ? s4[15: 8] : s4[ 7: 0]; + wire [ 3: 0] s2 = I2 ? s3[ 7: 4] : s3[ 3: 0]; + wire [ 1: 0] s1 = I1 ? s2[ 3: 2] : s2[ 1: 0]; + assign O6 = I0 ? s1[1] : s1[0]; + + wire [15: 0] s5_4 = I4 ? INIT[31:16] : INIT[15: 0]; + wire [ 7: 0] s5_3 = I3 ? s5_4[15: 8] : s5_4[ 7: 0]; + wire [ 3: 0] s5_2 = I2 ? s5_3[ 7: 4] : s5_3[ 3: 0]; + wire [ 1: 0] s5_1 = I1 ? s5_2[ 3: 2] : s5_2[ 1: 0]; + assign O5 = I0 ? s5_1[1] : s5_1[0]; +endmodule + module MUXCY(output O, input CI, DI, S); assign O = S ? CI : DI; endmodule @@ -104,6 +179,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); assign CO[3] = S[3] ? CO[2] : DI[3]; endmodule +`ifdef _EXPLICIT_CARRY + +module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S); + parameter CYINIT_FABRIC = 0; + wire CI_COMBINE; + if(CYINIT_FABRIC) begin + assign CI_COMBINE = CI_INIT; + end else begin + assign CI_COMBINE = CI; + end + assign CO_CHAIN = S ? CI_COMBINE : DI; + assign CO_FABRIC = S ? CI_COMBINE : DI; + assign O = S ^ CI_COMBINE; +endmodule + +module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S); + assign CO_CHAIN = S ? CI : DI; + assign CO_FABRIC = S ? CI : DI; + assign O = S ^ CI; +endmodule + +`endif + module FDRE (output reg Q, input C, CE, D, R); parameter [0:0] INIT = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0; @@ -156,6 +254,30 @@ module FDPE (output reg Q, input C, CE, D, PRE); endcase endgenerate endmodule +module FDRE_1 (output reg Q, input C, CE, D, R); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; +endmodule + +module FDSE_1 (output reg Q, input C, CE, D, S); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; +endmodule + +module FDCE_1 (output reg Q, input C, CE, D, CLR); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; +endmodule + +module FDPE_1 (output reg Q, input C, CE, D, PRE); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; +endmodule + module RAM64X1D ( output DPO, SPO, input D, WCLK, WE, @@ -186,3 +308,42 @@ module RAM128X1D ( wire clk = WCLK ^ IS_WCLK_INVERTED; always @(posedge clk) if (WE) mem[A] <= D; endmodule + +module SRL16E ( + output Q, + input A0, A1, A2, A3, CE, CLK, D +); + parameter [15:0] INIT = 16'h0000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [15:0] r = INIT; + assign Q = r[{A3,A2,A1,A0}]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[14:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[14:0], D }; + endgenerate +endmodule + +module SRLC32E ( + output Q, + output Q31, + input [4:0] A, + input CE, CLK, D +); + parameter [31:0] INIT = 32'h00000000; + parameter [0:0] IS_CLK_INVERTED = 1'b0; + + reg [31:0] r = INIT; + assign Q31 = r[31]; + assign Q = r[A]; + generate + if (IS_CLK_INVERTED) begin + always @(negedge CLK) if (CE) r <= { r[30:0], D }; + end + else + always @(posedge CLK) if (CE) r <= { r[30:0], D }; + endgenerate +endmodule diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 0480410f5..8e39b440d 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -7,6 +7,7 @@ function xtract_cell_decl() { for dir in $libdir/xeclib $libdir/retarget; do [ -f $dir/$1.v ] || continue + [ -z "$2" ] || echo $2 egrep '^\s*((end)?module|parameter|input|inout|output|(end)?function|(end)?task)' $dir/$1.v | sed -re '/UNPLACED/ d; /^\s*function/,/endfunction/ d; /^\s*task/,/endtask/ d; s,//.*,,; s/#?\(.*/(...);/; s/^(input|output|parameter)/ \1/; @@ -27,20 +28,20 @@ function xtract_cell_decl() # xtract_cell_decl BUFG xtract_cell_decl BUFGCE xtract_cell_decl BUFGCE_1 - xtract_cell_decl BUFGCTRL + #xtract_cell_decl BUFGCTRL xtract_cell_decl BUFGMUX xtract_cell_decl BUFGMUX_1 xtract_cell_decl BUFGMUX_CTRL xtract_cell_decl BUFH - xtract_cell_decl BUFHCE + #xtract_cell_decl BUFHCE xtract_cell_decl BUFIO xtract_cell_decl BUFMR xtract_cell_decl BUFMRCE xtract_cell_decl BUFR - xtract_cell_decl CAPTUREE2 + xtract_cell_decl CAPTUREE2 "(* keep *)" # xtract_cell_decl CARRY4 xtract_cell_decl CFGLUT5 - xtract_cell_decl DCIRESET + xtract_cell_decl DCIRESET "(* keep *)" xtract_cell_decl DNA_PORT xtract_cell_decl DSP48E1 xtract_cell_decl EFUSE_USR @@ -67,10 +68,10 @@ function xtract_cell_decl() xtract_cell_decl IBUFDS_GTE2 xtract_cell_decl IBUFDS_IBUFDISABLE xtract_cell_decl IBUFDS_INTERMDISABLE - xtract_cell_decl ICAPE2 + xtract_cell_decl ICAPE2 "(* keep *)" xtract_cell_decl IDDR xtract_cell_decl IDDR_2CLK - xtract_cell_decl IDELAYCTRL + xtract_cell_decl IDELAYCTRL "(* keep *)" xtract_cell_decl IDELAYE2 xtract_cell_decl IN_FIFO xtract_cell_decl IOBUF @@ -91,7 +92,7 @@ function xtract_cell_decl() # xtract_cell_decl LUT4 # xtract_cell_decl LUT5 # xtract_cell_decl LUT6 - xtract_cell_decl LUT6_2 + #xtract_cell_decl LUT6_2 xtract_cell_decl MMCME2_ADV xtract_cell_decl MMCME2_BASE # xtract_cell_decl MUXF7 @@ -112,10 +113,10 @@ function xtract_cell_decl() xtract_cell_decl PHY_CONTROL xtract_cell_decl PLLE2_ADV xtract_cell_decl PLLE2_BASE - xtract_cell_decl PS7 + xtract_cell_decl PS7 "(* keep *)" xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP - # xtract_cell_decl RAM128X1D + xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1S xtract_cell_decl RAM256X1S xtract_cell_decl RAM32M @@ -124,7 +125,7 @@ function xtract_cell_decl() xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X2S xtract_cell_decl RAM64M - # xtract_cell_decl RAM64X1D + xtract_cell_decl RAM64X1D xtract_cell_decl RAM64X1S xtract_cell_decl RAM64X1S_1 xtract_cell_decl RAM64X2S @@ -134,9 +135,9 @@ function xtract_cell_decl() xtract_cell_decl ROM256X1 xtract_cell_decl ROM32X1 xtract_cell_decl ROM64X1 - xtract_cell_decl SRL16E - xtract_cell_decl SRLC32E - xtract_cell_decl STARTUPE2 + #xtract_cell_decl SRL16E + #xtract_cell_decl SRLC32E + xtract_cell_decl STARTUPE2 "(* keep *)" xtract_cell_decl USR_ACCESSE2 xtract_cell_decl XADC } > cells_xtra.new diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 8d8b91ddc..fbcc74682 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -30,29 +30,6 @@ module BUFGCE_1 (...); input CE, I; endmodule -module BUFGCTRL (...); - output O; - input CE0; - input CE1; - input I0; - input I1; - input IGNORE0; - input IGNORE1; - input S0; - input S1; - parameter integer INIT_OUT = 0; - parameter PRESELECT_I0 = "FALSE"; - parameter PRESELECT_I1 = "FALSE"; - parameter [0:0] IS_CE0_INVERTED = 1'b0; - parameter [0:0] IS_CE1_INVERTED = 1'b0; - parameter [0:0] IS_I0_INVERTED = 1'b0; - parameter [0:0] IS_I1_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE0_INVERTED = 1'b0; - parameter [0:0] IS_IGNORE1_INVERTED = 1'b0; - parameter [0:0] IS_S0_INVERTED = 1'b0; - parameter [0:0] IS_S1_INVERTED = 1'b0; -endmodule - module BUFGMUX (...); parameter CLK_SEL_TYPE = "SYNC"; output O; @@ -77,15 +54,6 @@ module BUFH (...); input I; endmodule -module BUFHCE (...); - parameter CE_TYPE = "SYNC"; - parameter integer INIT_OUT = 0; - parameter [0:0] IS_CE_INVERTED = 1'b0; - output O; - input CE; - input I; -endmodule - module BUFIO (...); output O; input I; @@ -114,6 +82,7 @@ module BUFR (...); parameter SIM_DEVICE = "7SERIES"; endmodule +(* keep *) module CAPTUREE2 (...); parameter ONESHOT = "TRUE"; input CAP; @@ -130,6 +99,7 @@ module CFGLUT5 (...); input CDI, CE, CLK; endmodule +(* keep *) module DCIRESET (...); output LOCKED; input RST; @@ -2102,6 +2072,7 @@ module IBUFDS_INTERMDISABLE (...); input INTERMDISABLE; endmodule +(* keep *) module ICAPE2 (...); parameter [31:0] DEVICE_ID = 32'h04244093; parameter ICAP_WIDTH = "X32"; @@ -2149,6 +2120,7 @@ module IDDR_2CLK (...); input S; endmodule +(* keep *) module IDELAYCTRL (...); parameter SIM_DEVICE = "7SERIES"; output RDY; @@ -2416,12 +2388,6 @@ module LDPE (...); input D, G, GE, PRE; endmodule -module LUT6_2 (...); - parameter [63:0] INIT = 64'h0000000000000000; - input I0, I1, I2, I3, I4, I5; - output O5, O6; -endmodule - module MMCME2_ADV (...); parameter BANDWIDTH = "OPTIMIZED"; parameter real CLKFBOUT_MULT_F = 5.000; @@ -3057,6 +3023,7 @@ module PLLE2_BASE (...); input RST; endmodule +(* keep *) module PS7 (...); output DMA0DAVALID; output DMA0DRREADY; @@ -3688,6 +3655,17 @@ module PULLUP (...); output O; endmodule +module RAM128X1D (...); + parameter [127:0] INIT = 128'h00000000000000000000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DPO, SPO; + input [6:0] A; + input [6:0] DPRA; + input D; + input WCLK; + input WE; +endmodule + module RAM128X1S (...); parameter [127:0] INIT = 128'h00000000000000000000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3778,6 +3756,13 @@ module RAM64M (...); input WE; endmodule +module RAM64X1D (...); + parameter [63:0] INIT = 64'h0000000000000000; + parameter [0:0] IS_WCLK_INVERTED = 1'b0; + output DPO, SPO; + input A0, A1, A2, A3, A4, A5, D, DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5, WCLK, WE; +endmodule + module RAM64X1S (...); parameter [63:0] INIT = 64'h0000000000000000; parameter [0:0] IS_WCLK_INVERTED = 1'b0; @@ -3824,22 +3809,7 @@ module ROM64X1 (...); input A0, A1, A2, A3, A4, A5; endmodule -module SRL16E (...); - parameter [15:0] INIT = 16'h0000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output Q; - input A0, A1, A2, A3, CE, CLK, D; -endmodule - -module SRLC32E (...); - parameter [31:0] INIT = 32'h00000000; - parameter [0:0] IS_CLK_INVERTED = 1'b0; - output Q; - output Q31; - input [4:0] A; - input CE, CLK, D; -endmodule - +(* keep *) module STARTUPE2 (...); parameter PROG_USR = "FALSE"; parameter real SIM_CCLK_FREQ = 0.0; diff --git a/techlibs/xilinx/drams.txt b/techlibs/xilinx/drams.txt index e6635d0e2..91632bcee 100644 --- a/techlibs/xilinx/drams.txt +++ b/techlibs/xilinx/drams.txt @@ -26,11 +26,15 @@ bram $__XILINX_RAM128X1D endbram match $__XILINX_RAM64X1D + min bits 5 + min wports 1 make_outreg or_next_if_better endmatch match $__XILINX_RAM128X1D + min bits 9 + min wports 1 make_outreg endmatch diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v new file mode 100644 index 000000000..13beaa6ae --- /dev/null +++ b/techlibs/xilinx/ff_map.v @@ -0,0 +1,42 @@ +/* + * 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. + * + */ + +// ============================================================================ +// FF mapping + +`ifndef _NO_FFS + +module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule + +`endif + diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v deleted file mode 100644 index 061ad2041..000000000 --- a/techlibs/xilinx/lut2lut.v +++ /dev/null @@ -1,65 +0,0 @@ -module LUT1(output O, input I0); - parameter [1:0] INIT = 0; - \$lut #( - .WIDTH(1), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A(I0), - .Y(O) - ); -endmodule - -module LUT2(output O, input I0, I1); - parameter [3:0] INIT = 0; - \$lut #( - .WIDTH(2), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I1, I0}), - .Y(O) - ); -endmodule - -module LUT3(output O, input I0, I1, I2); - parameter [7:0] INIT = 0; - \$lut #( - .WIDTH(3), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT4(output O, input I0, I1, I2, I3); - parameter [15:0] INIT = 0; - \$lut #( - .WIDTH(4), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT5(output O, input I0, I1, I2, I3, I4); - parameter [31:0] INIT = 0; - \$lut #( - .WIDTH(5), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT6(output O, input I0, I1, I2, I3, I4, I5); - parameter [63:0] INIT = 0; - \$lut #( - .WIDTH(6), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I5, I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v new file mode 100644 index 000000000..d07c59dee --- /dev/null +++ b/techlibs/xilinx/lut_map.v @@ -0,0 +1,94 @@ +/* + * 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. + * + */ + +// ============================================================================ +// LUT mapping + +`ifndef _NO_LUTS + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0])); + end else + if (WIDTH == 2) begin + LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1])); + end else + if (WIDTH == 3) begin + LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3])); + end else + if (WIDTH == 5) begin + LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4])); + end else + if (WIDTH == 6) begin + LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + end else + if (WIDTH == 7) begin + wire T0, T1; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); + end else + if (WIDTH == 8) begin + wire T0, T1, T2, T3, T4, T5; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); + MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); + MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule + +`endif + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 6c11d885d..a293081f1 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -25,18 +25,9 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool check_label(bool &active, std::string run_from, std::string run_to, std::string label) +struct SynthXilinxPass : public ScriptPass { - if (label == run_from) - active = true; - if (label == run_to) - active = false; - return active; -} - -struct SynthXilinxPass : public Pass -{ - SynthXilinxPass() : Pass("synth_xilinx", "synthesis for Xilinx FPGAs") { } + SynthXilinxPass() : ScriptPass("synth_xilinx", "synthesis for Xilinx FPGAs") { } void help() YS_OVERRIDE { @@ -51,6 +42,10 @@ struct SynthXilinxPass : public Pass log(" -top <module>\n"); log(" use the specified module as top module\n"); log("\n"); + log(" -arch {xcup|xcu|xc7|xc6s}\n"); + log(" run synthesis for the specified Xilinx architecture\n"); + log(" default: xc7\n"); + log("\n"); log(" -edif <file>\n"); log(" write the design to the specified edif file. writing of an output file\n"); log(" is omitted if this parameter is not specified.\n"); @@ -63,6 +58,15 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); + log(" -nobram\n"); + log(" disable inference of block rams\n"); + log("\n"); + log(" -nodram\n"); + log(" disable inference of distributed rams\n"); + log("\n"); + log(" -nosrl\n"); + log(" disable inference of shift registers\n"); + log("\n"); log(" -run <from_label>:<to_label>\n"); log(" only run the commands between the labels (see below). an empty\n"); log(" from label is synonymous to 'begin', and empty to label is\n"); @@ -76,67 +80,31 @@ struct SynthXilinxPass : public Pass log("\n"); log("\n"); log("The following commands are executed by this synthesis command:\n"); - log("\n"); - log(" begin:\n"); - log(" read_verilog -lib +/xilinx/cells_sim.v\n"); - log(" read_verilog -lib +/xilinx/cells_xtra.v\n"); - log(" read_verilog -lib +/xilinx/brams_bb.v\n"); - log(" hierarchy -check -top <top>\n"); - log("\n"); - log(" flatten: (only if -flatten)\n"); - log(" proc\n"); - log(" flatten\n"); - log("\n"); - log(" coarse:\n"); - log(" synth -run coarse\n"); - log("\n"); - log(" bram:\n"); - log(" memory_bram -rules +/xilinx/brams.txt\n"); - log(" techmap -map +/xilinx/brams_map.v\n"); - log("\n"); - log(" dram:\n"); - log(" memory_bram -rules +/xilinx/drams.txt\n"); - log(" techmap -map +/xilinx/drams_map.v\n"); - log("\n"); - log(" fine:\n"); - log(" opt -fast -full\n"); - log(" memory_map\n"); - log(" dffsr2dff\n"); - log(" dff2dffe\n"); - log(" opt -full\n"); - log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); - log(" opt -fast\n"); - log("\n"); - log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); - log(" clean\n"); - log("\n"); - log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n"); - log(" clean\n"); - log("\n"); - log(" check:\n"); - log(" hierarchy -check\n"); - log(" stat\n"); - log(" check -noinit\n"); - log("\n"); - log(" edif: (only if -edif)\n"); - log(" write_edif <file-name>\n"); - log("\n"); - log(" blif: (only if -blif)\n"); - log(" write_blif <file-name>\n"); + help_script(); log("\n"); } + + std::string top_opt, edif_file, blif_file, arch; + bool flatten, retime, vpr, nobram, nodram, nosrl; + + void clear_flags() YS_OVERRIDE + { + top_opt = "-auto-top"; + edif_file.clear(); + blif_file.clear(); + flatten = false; + retime = false; + vpr = false; + nobram = false; + nodram = false; + nosrl = false; + arch = "xc7"; + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - std::string top_opt = "-auto-top"; - std::string edif_file; - std::string blif_file; std::string run_from, run_to; - bool flatten = false; - bool retime = false; - bool vpr = false; + clear_flags(); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -145,6 +113,10 @@ struct SynthXilinxPass : public Pass top_opt = "-top " + args[++argidx]; continue; } + if (args[argidx] == "-arch" && argidx+1 < args.size()) { + arch = args[++argidx]; + continue; + } if (args[argidx] == "-edif" && argidx+1 < args.size()) { edif_file = args[++argidx]; continue; @@ -173,94 +145,142 @@ struct SynthXilinxPass : public Pass vpr = true; continue; } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-nodram") { + nodram = true; + continue; + } + if (args[argidx] == "-nosrl") { + nosrl = true; + continue; + } break; } extra_args(args, argidx, design); + if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s") + log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str()); + if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - bool active = run_from.empty(); - log_header(design, "Executing SYNTH_XILINX pass.\n"); log_push(); - if (check_label(active, run_from, run_to, "begin")) - { - Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); - Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); - Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); - Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); - } + run_script(design, run_from, run_to); - if (flatten && check_label(active, run_from, run_to, "flatten")) - { - Pass::call(design, "proc"); - Pass::call(design, "flatten"); + log_pop(); + } + + void script() YS_OVERRIDE + { + if (check_label("begin")) { + if (vpr) + run("read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); + else + run("read_verilog -lib +/xilinx/cells_sim.v"); + + run("read_verilog -lib +/xilinx/cells_xtra.v"); + + if (!nobram || help_mode) + run("read_verilog -lib +/xilinx/brams_bb.v", "(skip if '-nobram')"); + + run(stringf("hierarchy -check %s", top_opt.c_str())); } - if (check_label(active, run_from, run_to, "coarse")) - { - Pass::call(design, "synth -run coarse"); + if (check_label("flatten", "(with '-flatten' only)")) { + if (flatten || help_mode) { + run("proc"); + run("flatten"); + } } - if (check_label(active, run_from, run_to, "bram")) - { - Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); - Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + if (check_label("coarse")) { + run("synth -run coarse"); } - if (check_label(active, run_from, run_to, "dram")) - { - Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); - Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + if (check_label("bram", "(skip if '-nobram')")) { + if (!nobram || help_mode) { + run("memory_bram -rules +/xilinx/brams.txt"); + run("techmap -map +/xilinx/brams_map.v"); + } } - if (check_label(active, run_from, run_to, "fine")) - { - Pass::call(design, "opt -fast -full"); - Pass::call(design, "memory_map"); - Pass::call(design, "dffsr2dff"); - Pass::call(design, "dff2dffe"); - Pass::call(design, "opt -full"); - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); - Pass::call(design, "opt -fast"); + if (check_label("dram", "(skip if '-nodram')")) { + if (!nodram || help_mode) { + run("memory_bram -rules +/xilinx/drams.txt"); + run("techmap -map +/xilinx/drams_map.v"); + } } - if (check_label(active, run_from, run_to, "map_luts")) - { - Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); - Pass::call(design, "clean"); + if (check_label("fine")) { + // shregmap -tech xilinx can cope with $shiftx and $mux + // cells for identifiying variable-length shift registers, + // so attempt to convert $pmux-es to the former + if (!nosrl || help_mode) + run("pmux2shiftx", "(skip if '-nosrl')"); + + run("opt -fast -full"); + run("memory_map"); + run("dffsr2dff"); + run("dff2dffe"); + run("opt -full"); + + if (!nosrl || help_mode) { + // shregmap operates on bit-level flops, not word-level, + // so break those down here + run("simplemap t:$dff t:$dffe", "(skip if '-nosrl')"); + // shregmap with '-tech xilinx' infers variable length shift regs + run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')"); + } + + if (!vpr || help_mode) + run("techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + else + run("techmap -map +/techmap.v +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); + + run("opt -fast"); } - if (check_label(active, run_from, run_to, "map_cells")) - { - Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - if (vpr) - Pass::call(design, "techmap -map +/xilinx/lut2lut.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT"); - Pass::call(design, "clean"); + if (check_label("map_cells")) { + run("techmap -map +/techmap.v -map +/xilinx/cells_map.v"); + run("clean"); } - if (check_label(active, run_from, run_to, "check")) - { - Pass::call(design, "hierarchy -check"); - Pass::call(design, "stat"); - Pass::call(design, "check -noinit"); + if (check_label("map_luts")) { + if (help_mode) + run("abc -luts 2:2,3,6:5,10,20 [-dff]"); + else + run("abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); + run("clean"); + // This shregmap call infers fixed length shift registers after abc + // has performed any necessary retiming + if (!nosrl || help_mode) + run("shregmap -minlen 3 -init -params -enpol any_or_none", "(skip if '-nosrl')"); + run("techmap -map +/xilinx/lut_map.v -map +/xilinx/ff_map.v -map +/xilinx/cells_map.v"); + run("dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT " + "-ff FDRE_1 Q INIT -ff FDCE_1 Q INIT -ff FDPE_1 Q INIT -ff FDSE_1 Q INIT"); + run("clean"); } - if (check_label(active, run_from, run_to, "edif")) - { - if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + if (check_label("check")) { + run("hierarchy -check"); + run("stat -tech xilinx"); + run("check -noinit"); } - if (check_label(active, run_from, run_to, "blif")) - { - if (!blif_file.empty()) - Pass::call(design, stringf("write_blif %s", edif_file.c_str())); + + if (check_label("edif")) { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif -pvector bra %s", edif_file.c_str())); } - log_pop(); + if (check_label("blif")) { + if (!blif_file.empty() || help_mode) + run(stringf("write_blif %s", edif_file.c_str())); + } } } SynthXilinxPass; |