diff options
Diffstat (limited to 'techlibs')
| -rw-r--r-- | techlibs/xilinx/cells_map.v | 66 | ||||
| -rw-r--r-- | techlibs/xilinx/mux_map.v | 2 | ||||
| -rw-r--r-- | techlibs/xilinx/synth_xilinx.cc | 68 | 
3 files changed, 82 insertions, 54 deletions
| diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 18c926336..2eb84ce04 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -155,6 +155,7 @@ module \$__XILINX_SHREG_ (input C, input D, input [31:0] L, input E, output Q, o    endgenerate  endmodule +`ifdef MIN_MUX_INPUTS  module \$__XILINX_SHIFTX (A, B, Y);    parameter A_SIGNED = 0;    parameter B_SIGNED = 0; @@ -207,10 +208,10 @@ module \$__XILINX_SHIFTX (A, B, Y);        localparam B_WIDTH_new = $clog2(A_WIDTH_new);        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH_new), .B_WIDTH(B_WIDTH_new), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A[A_WIDTH_new-1:0]), .B(B[B_WIDTH_new-1:0]), .Y(Y));      end -    else if (B_WIDTH < 3 || A_WIDTH <= 4) begin -      \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); +    else if (A_WIDTH < `MIN_MUX_INPUTS) begin +      wire _TECHMAP_FAIL_ = 1;      end -    else if (B_WIDTH == 3) begin +    else if (A_WIDTH <= 2 ** 3) begin        localparam a_width0 = 2 ** 2;        localparam a_widthN = A_WIDTH - a_width0;        wire T0, T1; @@ -219,47 +220,61 @@ module \$__XILINX_SHIFTX (A, B, Y);          \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T1));        else          assign T1 = A[A_WIDTH-1]; -      MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[B_WIDTH-1]), .O(Y)); +      MUXF7 fpga_hard_mux (.I0(T0), .I1(T1), .S(B[2]), .O(Y));      end -    else if (B_WIDTH == 4) begin +    else if (A_WIDTH <= 2 ** 4) begin        localparam a_width0 = 2 ** 2;        localparam num_mux8 = A_WIDTH / a_width0;        localparam a_widthN = A_WIDTH - num_mux8*a_width0;        wire [4-1:0] T; -      for (i = 0; i < 4; i++) +      for (i = 0; i < num_mux8; i++)          if (i < num_mux8) -          \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i])); -        else if (i == num_mux8 && a_widthN > 0) begin -          if (a_widthN > 1) -            \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i])); -          else -            assign T[i] = A[A_WIDTH-1]; -        end +          \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(2), .Y_WIDTH(Y_WIDTH)) fpga_mux (.A(A[i*a_width0+:a_width0]), .B(B[2-1:0]), .Y(T[i])); +      if (a_widthN > 0) begin +        if (a_widthN > 1) +          \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_mux_last (.A(A[A_WIDTH-1:num_mux8*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[num_mux8]));          else -          assign T[i] = 1'bx; +          assign T[num_mux8] = A[A_WIDTH-1]; +      end +      else +        assign T[num_mux8] = 1'bx;        \$__XILINX_MUXF78 fpga_hard_mux (.I0(T[0]), .I1(T[1]), .I2(T[2]), .I3(T[3]), .S0(B[2]), .S1(B[3]), .O(Y));      end      else begin        localparam a_width0 = 2 ** 4;        localparam num_mux16 = A_WIDTH / a_width0;        localparam a_widthN = A_WIDTH - num_mux16*a_width0; -      wire [(2**(B_WIDTH-4))-1:0] T; -      for (i = 0; i < 2 ** (B_WIDTH-4); i++) -        if (i < num_mux16) -          \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux      (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i])); -        else if (i == num_mux16 && a_widthN > 0) begin -          if (a_widthN > 1) -            \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:i*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[i])); -          else -            assign T[i] = A[A_WIDTH-1]; -        end +      wire [num_mux16-1:0] T; +      for (i = 0; i < num_mux16; i++) +        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_width0), .B_WIDTH(4), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux (.A(A[i*a_width0+:a_width0]), .B(B[4-1:0]), .Y(T[i])); +      if (a_widthN > 0) begin +        if (a_widthN > 1) +          \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(a_widthN), .B_WIDTH($clog2(a_widthN)), .Y_WIDTH(Y_WIDTH)) fpga_soft_mux_last (.A(A[A_WIDTH-1:num_mux16*a_width0]), .B(B[$clog2(a_widthN)-1:0]), .Y(T[num_mux16]));          else -          assign T[i] = 1'bx; +          assign T[num_mux16] = A[A_WIDTH-1]; +      end +      else +        assign T[num_mux16] = 1'bx;        \$__XILINX_SHIFTX  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(2**(B_WIDTH-4)), .B_WIDTH(B_WIDTH-4), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(T), .B(B[B_WIDTH-1:4]), .Y(Y));      end    endgenerate  endmodule +(* techmap_celltype = "$__XILINX_SHIFTX" *) +module _90__XILINX_SHIFTX (A, B, Y); +  parameter A_SIGNED = 0; +  parameter B_SIGNED = 0; +  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] Y; + +  \$shiftx  #(.A_SIGNED(A_SIGNED), .B_SIGNED(B_SIGNED), .A_WIDTH(A_WIDTH), .B_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(A), .B(B), .Y(Y)); +endmodule +  module \$_MUX8_ (A, B, C, D, E, F, G, H, S, T, U, Y);  input A, B, C, D, E, F, G, H, S, T, U;  output Y; @@ -271,6 +286,7 @@ input A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, S, T, U, V;  output Y;    \$__XILINX_SHIFTX  #(.A_SIGNED(0), .B_SIGNED(0), .A_WIDTH(16), .B_WIDTH(4), .Y_WIDTH(1)) _TECHMAP_REPLACE_ (.A({P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A}), .B({V,U,T,S}), .Y(Y));  endmodule +`endif  `ifndef _ABC  module \$__XILINX_MUXF78 (O, I0, I1, I2, I3, S0, S1); diff --git a/techlibs/xilinx/mux_map.v b/techlibs/xilinx/mux_map.v index e28070359..91aaf2118 100644 --- a/techlibs/xilinx/mux_map.v +++ b/techlibs/xilinx/mux_map.v @@ -54,7 +54,7 @@ module \$shiftx (A, B, Y);          wire _TECHMAP_FAIL_ = 1;      end      else begin -      if (B_WIDTH < 3 || A_WIDTH <= 4) +      if (((A_WIDTH + Y_WIDTH - 1) / Y_WIDTH) < `MIN_MUX_INPUTS)          wire _TECHMAP_FAIL_ = 1;        else          \$__XILINX_SHIFTX #( diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 9724dff94..2cf28fce1 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -73,8 +73,10 @@ struct SynthXilinxPass : public ScriptPass  		log("    -nosrl\n");  		log("        disable inference of shift registers\n");  		log("\n"); -		log("    -nomux\n"); -		log("        disable inference of wide multiplexers\n"); +		log("    -minmuxf <int>\n"); +		log("        enable inference of hard multiplexer resources (MuxFx) for muxes at or\n"); +		log("        above this number of inputs (minimum value 5).\n"); +		log("        default: 0 (no inference)\n");  		log("\n");  		log("    -run <from_label>:<to_label>\n");  		log("        only run the commands between the labels (see below). an empty\n"); @@ -97,7 +99,8 @@ struct SynthXilinxPass : public ScriptPass  	}  	std::string top_opt, edif_file, blif_file, abc, arch; -	bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl, nomux; +	bool flatten, retime, vpr, nocarry, nobram, nodram, nosrl; +	int minmuxf;  	void clear_flags() YS_OVERRIDE  	{ @@ -112,8 +115,8 @@ struct SynthXilinxPass : public ScriptPass  		nobram = false;  		nodram = false;  		nosrl = false; -		nomux = false;  		arch = "xc7"; +		minmuxf = 0;  	}  	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -176,8 +179,8 @@ struct SynthXilinxPass : public ScriptPass  				nosrl = true;  				continue;  			} -			if (args[argidx] == "-nomux") { -				nomux = true; +			if (args[argidx] == "-minmuxf" && argidx+1 < args.size()) { +				minmuxf = atoi(args[++argidx].c_str());  				continue;  			}  			if (args[argidx] == "-abc9") { @@ -191,6 +194,9 @@ struct SynthXilinxPass : public ScriptPass  		if (arch != "xcup" && arch != "xcu" && arch != "xc7" && arch != "xc6s")  			log_cmd_error("Invalid Xilinx -arch setting: %s\n", arch.c_str()); +		if (minmuxf != 0 && minmuxf < 5) +			log_cmd_error("-minmuxf value must be 0 or >= 5.\n"); +  		if (!design->full_selection())  			log_cmd_error("This command only operates on fully selected designs!\n"); @@ -227,9 +233,9 @@ struct SynthXilinxPass : public ScriptPass  			run("check");  			run("opt");  			if (help_mode) -				run("wreduce [c:* t:$mux %d]", "(no selection if -nomux)"); +				run("wreduce [c:* t:$mux %d]", "(selection for '-minmuxf' only)");  			else -				run("wreduce" + std::string(nomux ? "" : " c:* t:$mux %d")); +				run("wreduce" + std::string(minmuxf > 0 ? " c:* t:$mux %d" : ""));  			run("peepopt");  			run("opt_clean");  			run("alumacc"); @@ -240,15 +246,15 @@ struct SynthXilinxPass : public ScriptPass  			run("memory -nomap");  			run("opt_clean"); -			if (!nomux || help_mode) -				run("muxpack", "    (skip if '-nomux')"); +			if (minmuxf > 0 || help_mode) +				run("muxpack", "    ('-minmuxf' only)");  			// shregmap -tech xilinx can cope with $shiftx and $mux  			//   cells for identifying variable-length shift registers,  			//   so attempt to convert $pmux-es to the former  			// Also: wide multiplexer inference benefits from this too -			if (!(nosrl && nomux) || help_mode) -				run("pmux2shiftx", "(skip if '-nosrl' and '-nomux')"); +			if (!(nosrl && minmuxf == 0) || help_mode) +				run("pmux2shiftx", "(skip if '-nosrl' and '-minmuxf' < 5)");  		}  		if (check_label("bram", "(skip if '-nobram')")) { @@ -270,12 +276,15 @@ struct SynthXilinxPass : public ScriptPass  			run("memory_map");  			run("dffsr2dff");  			run("dff2dffe"); -			if (!nomux || help_mode) { -				run("simplemap t:$mux", "                     (skip if -nomux)"); -				// NB: Cost of mux2 is 100; mux8 should cost between 3 and 4 -				//     of those so that 4:1 muxes and below are implemented -				//     out of mux2s -				run("muxcover -mux8=350 -mux16=400 -dmux=0", "(skip if -nomux)"); +			if (minmuxf > 0 || help_mode) { +				run("simplemap t:$mux", "                        ('-minmuxf' only)"); +				if (minmuxf > 0 || help_mode) { +					// NB: Cost of mux2 is 100; mux8 should cost between 3 and 4 +					//     of those so that 4:1 muxes and below are implemented +					//     out of mux2s +					std::string muxcover_args = " -dmux=0 -mux8=350 -mux16=400"; +					run("muxcover " + muxcover_args, "('-minmuxf' only)"); +				}  			}  			run("opt -full"); @@ -287,26 +296,29 @@ struct SynthXilinxPass : public ScriptPass  				run("shregmap -tech xilinx -minlen 3", "(skip if '-nosrl')");  			} -			std::string techmap_files = " -map +/techmap.v"; +			std::string techmap_args = " -map +/techmap.v";  			if (help_mode) -				techmap_files += " [-map +/xilinx/mux_map.v]"; -			else if (!nomux) -				techmap_files += " -map +/xilinx/mux_map.v"; +				techmap_args += " [-map +/xilinx/mux_map.v]"; +			else if (minmuxf > 0) +				techmap_args += stringf(" -D MIN_MUX_INPUTS=%d -map +/xilinx/mux_map.v", minmuxf);  			if (help_mode) -				techmap_files += " [-map +/xilinx/arith_map.v]"; +				techmap_args += " [-map +/xilinx/arith_map.v]";  			else if (!nocarry) { -				techmap_files += " -map +/xilinx/arith_map.v"; +				techmap_args += " -map +/xilinx/arith_map.v";  				if (vpr) -					techmap_files += " -D _EXPLICIT_CARRY"; +					techmap_args += " -D _EXPLICIT_CARRY";  				else if (abc == "abc9") -					techmap_files += " -D _CLB_CARRY"; +					techmap_args += " -D _CLB_CARRY";  			} -			run("techmap " + techmap_files); +			run("techmap " + techmap_args);  			run("opt -fast");  		}  		if (check_label("map_cells")) { -			run("techmap -map +/techmap.v -D _ABC -map +/xilinx/cells_map.v"); +			std::string techmap_args = "-map +/techmap.v -D _ABC -map +/xilinx/cells_map.v"; +			if (minmuxf > 0) +				techmap_args += stringf(" -D MIN_MUX_INPUTS=%d", minmuxf); +			run("techmap " + techmap_args);  			run("clean");  		} | 
