diff options
| author | David Shah <dave@ds0.me> | 2020-11-20 08:26:58 +0000 | 
|---|---|---|
| committer | David Shah <dave@ds0.me> | 2020-11-20 08:45:55 +0000 | 
| commit | 9f241c9a42d9380164a9df8f16cf9dffb10bc8ad (patch) | |
| tree | 29d45faf9380a5cd5144d2334cca41febc6ebe4d | |
| parent | 5b35d953f749beafeceecc67862419221e91fe84 (diff) | |
| download | yosys-9f241c9a42d9380164a9df8f16cf9dffb10bc8ad.tar.gz yosys-9f241c9a42d9380164a9df8f16cf9dffb10bc8ad.tar.bz2 yosys-9f241c9a42d9380164a9df8f16cf9dffb10bc8ad.zip | |
nexus: DSP inference support
Signed-off-by: David Shah <dave@ds0.me>
| -rw-r--r-- | techlibs/nexus/Makefile.inc | 1 | ||||
| -rw-r--r-- | techlibs/nexus/dsp_map.v | 79 | ||||
| -rw-r--r-- | techlibs/nexus/synth_nexus.cc | 38 | ||||
| -rw-r--r-- | tests/arch/nexus/mul.ys | 46 | 
4 files changed, 151 insertions, 13 deletions
| diff --git a/techlibs/nexus/Makefile.inc b/techlibs/nexus/Makefile.inc index e0ff40e15..c9a9ad4ff 100644 --- a/techlibs/nexus/Makefile.inc +++ b/techlibs/nexus/Makefile.inc @@ -11,4 +11,5 @@ $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams_map.v))  $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams.txt))  $(eval $(call add_share_file,share/nexus,techlibs/nexus/arith_map.v))  $(eval $(call add_share_file,share/nexus,techlibs/nexus/latches_map.v)) +$(eval $(call add_share_file,share/nexus,techlibs/nexus/dsp_map.v)) diff --git a/techlibs/nexus/dsp_map.v b/techlibs/nexus/dsp_map.v new file mode 100644 index 000000000..b12528309 --- /dev/null +++ b/techlibs/nexus/dsp_map.v @@ -0,0 +1,79 @@ +module \$__NX_MUL36X36 (input [35:0] A, input [35:0] B, output [71:0] Y); + +	parameter A_WIDTH = 36; +	parameter B_WIDTH = 36; +	parameter Y_WIDTH = 72; +	parameter A_SIGNED = 0; +	parameter B_SIGNED = 0; + +	MULT36X36 #( +		.REGINPUTA("BYPASS"), +		.REGINPUTB("BYPASS"), +		.REGOUTPUT("BYPASS") +	) _TECHMAP_REPLACE_ ( +		.A(A), .B(B), +		.SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), +		.SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), +		.Z(Y) +	); +endmodule + +module \$__NX_MUL36X18 (input [35:0] A, input [17:0] B, output [53:0] Y); + +	parameter A_WIDTH = 36; +	parameter B_WIDTH = 18; +	parameter Y_WIDTH = 54; +	parameter A_SIGNED = 0; +	parameter B_SIGNED = 0; + +	MULT18X36 #( +		.REGINPUTA("BYPASS"), +		.REGINPUTB("BYPASS"), +		.REGOUTPUT("BYPASS") +	) _TECHMAP_REPLACE_ ( +		.A(B), .B(A), +		.SIGNEDA(B_SIGNED ? 1'b1 : 1'b0), +		.SIGNEDB(A_SIGNED ? 1'b1 : 1'b0), +		.Z(Y) +	); +endmodule + +module \$__NX_MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); + +	parameter A_WIDTH = 18; +	parameter B_WIDTH = 18; +	parameter Y_WIDTH = 36; +	parameter A_SIGNED = 0; +	parameter B_SIGNED = 0; + +	MULT18X18 #( +		.REGINPUTA("BYPASS"), +		.REGINPUTB("BYPASS"), +		.REGOUTPUT("BYPASS") +	) _TECHMAP_REPLACE_ ( +		.A(A), .B(B), +		.SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), +		.SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), +		.Z(Y) +	); +endmodule + +module \$__NX_MUL9X9 (input [8:0] A, input [8:0] B, output [17:0] Y); + +	parameter A_WIDTH = 9; +	parameter B_WIDTH = 9; +	parameter Y_WIDTH = 18; +	parameter A_SIGNED = 0; +	parameter B_SIGNED = 0; + +	MULT9X9 #( +		.REGINPUTA("BYPASS"), +		.REGINPUTB("BYPASS"), +		.REGOUTPUT("BYPASS") +	) _TECHMAP_REPLACE_ ( +		.A(A), .B(B), +		.SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), +		.SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), +		.Z(Y) +	); +endmodule diff --git a/techlibs/nexus/synth_nexus.cc b/techlibs/nexus/synth_nexus.cc index 7e2185ab6..9eabbace7 100644 --- a/techlibs/nexus/synth_nexus.cc +++ b/techlibs/nexus/synth_nexus.cc @@ -89,6 +89,9 @@ struct SynthNexusPass : public ScriptPass  		log("    -noiopad\n");  		log("        do not insert IO buffers\n");  		log("\n"); +		log("    -nodsp\n"); +		log("        do not infer DSP multipliers\n"); +		log("\n");  		log("    -abc9\n");  		log("        use new ABC9 flow (EXPERIMENTAL)\n");  		log("\n"); @@ -98,7 +101,7 @@ struct SynthNexusPass : public ScriptPass  	}  	string top_opt, json_file, vm_file, family; -	bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, flatten, dff, retime, abc9; +	bool noccu2, nodffe, nobram, nolutram, nowidelut, noiopad, nodsp, flatten, dff, retime, abc9;  	void clear_flags() override  	{ @@ -112,6 +115,7 @@ struct SynthNexusPass : public ScriptPass  		nolutram = false;  		nowidelut = false;  		noiopad = false; +		nodsp = false;  		flatten = true;  		dff = false;  		retime = false; @@ -161,6 +165,10 @@ struct SynthNexusPass : public ScriptPass  				dff = true;  				continue;  			} +			if (args[argidx] == "-nodsp") { +				nodsp = true; +				continue; +			}  			if (args[argidx] == "-retime") {  				retime = true;  				continue; @@ -211,6 +219,22 @@ struct SynthNexusPass : public ScriptPass  		log_pop();  	} +	struct DSPRule { +		int a_maxwidth; +		int b_maxwidth; +		int a_minwidth; +		int b_minwidth; +		std::string prim; +	}; + +	const std::vector<DSPRule> dsp_rules = { +		{36, 36, 22, 22, "$__NX_MUL36X36"}, +		{36, 18, 22, 10, "$__NX_MUL36X18"}, +		{18, 18, 10,  4, "$__NX_MUL18X18"}, +		{18, 18,  4, 10, "$__NX_MUL18X18"}, +		{ 9,  9,  4,  4, "$__NX_MUL9X9"}, +	}; +  	void script() override  	{ @@ -244,6 +268,18 @@ struct SynthNexusPass : public ScriptPass  			run("opt_expr");  			run("opt_clean"); +			if (help_mode) { +				run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); +				run("techmap -map +/nexus/dsp_map.v", "(unless -nodsp)"); +			} else if (!nodsp) { +				for (const auto &rule : dsp_rules) { +					run(stringf("techmap -map +/mul2dsp.v -D DSP_A_MAXWIDTH=%d -D DSP_B_MAXWIDTH=%d -D DSP_A_MINWIDTH=%d -D DSP_B_MINWIDTH=%d -D DSP_NAME=%s", +						rule.a_maxwidth, rule.b_maxwidth, rule.a_minwidth, rule.b_minwidth, rule.prim.c_str())); +					run("chtype -set $mul t:$__soft_mul"); +				} +				run("techmap -map +/nexus/dsp_map.v"); +			} +  			run("alumacc");  			run("opt");  			run("memory -nomap"); diff --git a/tests/arch/nexus/mul.ys b/tests/arch/nexus/mul.ys index 27ea3e04e..65a2fd8c3 100644 --- a/tests/arch/nexus/mul.ys +++ b/tests/arch/nexus/mul.ys @@ -1,4 +1,5 @@  read_verilog ../common/mul.v +chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16  hierarchy -top top  proc @@ -7,22 +8,43 @@ design -save read  equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus  design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design)  cd top # Constrain all select calls below inside the top module -select -assert-count 7 t:CCU2 -select -assert-max 5 t:WIDEFN9 -select -assert-max 62 t:LUT4 +select -assert-count 1 t:MULT9X9 -select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:CCU2 t:WIDEFN9 %% t:* %D +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT9X9 %% t:* %D -design -load read -equiv_opt -assert -map +/nexus/cells_sim.v synth_nexus -abc9 -design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_nexus +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT18X18 +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT18X18 %% t:* %D + + +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 16 -set A_WIDTH 48 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_nexus  cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT18X36 +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT18X36 %% t:* %D -stat -select -assert-count 7 t:CCU2 -select -assert-max 12 t:WIDEFN9 -select -assert-max 58 t:LUT4 +design -reset +read_verilog ../common/mul.v +chparam -set X_WIDTH 32 -set Y_WIDTH 32 -set A_WIDTH 64 +hierarchy -top top +proc +# equivalence checking is too slow here +synth_nexus +cd top # Constrain all select calls below inside the top module +select -assert-count 1 t:MULT36X36 -select -assert-none t:IB t:OB t:VLO t:VHI t:LUT4 t:CCU2 t:WIDEFN9 %% t:* %D +select -assert-none t:IB t:OB t:VLO t:VHI t:MULT36X36 %% t:* %D | 
