mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 11:42:30 +00:00 
			
		
		
		
	gowin: dsp: Add basic DSP block inferencing for various MULT cells
This commit is contained in:
		
							parent
							
								
									a80462f27f
								
							
						
					
					
						commit
						5ad9e4cacc
					
				
					 5 changed files with 204 additions and 1 deletions
				
			
		|  | @ -11,3 +11,4 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) | |||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) | ||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) | ||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) | ||||
| $(eval $(call add_share_file,share/gowin,techlibs/gowin/dsp_map.v)) | ||||
|  |  | |||
							
								
								
									
										65
									
								
								techlibs/gowin/dsp_map.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								techlibs/gowin/dsp_map.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| module \$__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; | ||||
| 
 | ||||
| 	wire [8:0] soa; | ||||
| 	wire [8:0] sob; | ||||
| 
 | ||||
| 	MULT9X9 _TECHMAP_REPLACE_ ( | ||||
| 		.A(A), | ||||
| 		.B(B), | ||||
| 		.SIA(8'b0), | ||||
| 		.SIB(8'b0), | ||||
| 		.ASIGN(A_SIGNED), | ||||
| 		.BSIGN(B_SIGNED), | ||||
| 		.ASEL(1'b0), | ||||
| 		.BSEL(1'b0), | ||||
| 		.SOA(soa), | ||||
| 		.SOB(sob), | ||||
| 		.DOUT(Y) | ||||
| 	); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__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; | ||||
| 
 | ||||
| 	wire [17:0] soa; | ||||
| 	wire [17:0] sob; | ||||
| 
 | ||||
| 	MULT18X18 _TECHMAP_REPLACE_ ( | ||||
| 		.A(A), | ||||
| 		.B(B), | ||||
| 		.SIA(18'b0), | ||||
| 		.SIB(18'b0), | ||||
| 		.ASIGN(A_SIGNED), | ||||
| 		.BSIGN(B_SIGNED), | ||||
| 		.ASEL(1'b0), | ||||
| 		.BSEL(1'b0), | ||||
| 		.SOA(soa), | ||||
| 		.SOB(sob), | ||||
| 		.DOUT(Y) | ||||
| 	); | ||||
| endmodule | ||||
| 
 | ||||
| module \$__MUL36X36 (input [35:0] A, input [35:0] B, output [72:0] Y); | ||||
| 	parameter A_WIDTH = 36; | ||||
| 	parameter B_WIDTH = 36; | ||||
| 	parameter Y_WIDTH = 72; | ||||
| 	parameter A_SIGNED = 0; | ||||
| 	parameter B_SIGNED = 0; | ||||
| 
 | ||||
| 	MULT36X36 _TECHMAP_REPLACE_ ( | ||||
| 		.A(A), | ||||
| 		.B(B), | ||||
| 		.ASIGN(A_SIGNED), | ||||
| 		.BSIGN(B_SIGNED), | ||||
| 		.DOUT(Y) | ||||
| 	); | ||||
| endmodule | ||||
|  | @ -91,13 +91,16 @@ struct SynthGowinPass : public ScriptPass | |||
| 		log("		  The following families are supported:\n"); | ||||
| 		log("        'gw1n', 'gw2a', 'gw5a'.\n"); | ||||
| 		log("\n"); | ||||
| 		log("    -nodsp\n"); | ||||
| 		log("        do not infer DSP multipliers.\n"); | ||||
| 		log("\n"); | ||||
| 		log("The following commands are executed by this synthesis command:\n"); | ||||
| 		help_script(); | ||||
| 		log("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	string top_opt, vout_file, json_file, family; | ||||
| 	bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check; | ||||
| 	bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check, nodsp; | ||||
| 
 | ||||
| 	void clear_flags() override | ||||
| 	{ | ||||
|  | @ -115,6 +118,7 @@ struct SynthGowinPass : public ScriptPass | |||
| 		noiopads = false; | ||||
| 		noalu = false; | ||||
| 		no_rw_check = false; | ||||
| 		nodsp = false; | ||||
| 	} | ||||
| 
 | ||||
| 	void execute(std::vector<std::string> args, RTLIL::Design *design) override | ||||
|  | @ -193,6 +197,10 @@ struct SynthGowinPass : public ScriptPass | |||
| 				no_rw_check = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (args[argidx] == "-nodsp") { | ||||
| 				nodsp = true; | ||||
| 				continue; | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		extra_args(args, argidx, design); | ||||
|  | @ -208,6 +216,24 @@ struct SynthGowinPass : public ScriptPass | |||
| 		log_pop(); | ||||
| 	} | ||||
| 
 | ||||
| 	// DSP mapping rules for mul2dsp
 | ||||
| 	struct DSPRule { | ||||
| 		int a_maxwidth; | ||||
| 		int b_maxwidth; | ||||
| 		int a_minwidth; | ||||
| 		int b_minwidth; | ||||
| 		std::string prim; | ||||
| 	}; | ||||
| 
 | ||||
| 	// gw1n and gw2a
 | ||||
| 	const std::vector<DSPRule> dsp_rules = { | ||||
| 		{36, 36, 18, 18, "$__MUL36X36"}, | ||||
| 		{18, 18, 10,  4, "$__MUL18X18"}, | ||||
| 		{18, 18,  4, 10, "$__MUL18X18"}, | ||||
| 		{ 9,  9,  4,  4, "$__MUL9X9"}, | ||||
| 	}; | ||||
| 	// TODO: gw5a (MULT12X12, MULT27x36)
 | ||||
| 
 | ||||
| 	void script() override | ||||
| 	{ | ||||
| 		std::string no_rw_check_opt = ""; | ||||
|  | @ -233,6 +259,23 @@ struct SynthGowinPass : public ScriptPass | |||
| 
 | ||||
| 		if (check_label("coarse")) | ||||
| 		{ | ||||
| 			if (help_mode) | ||||
| 			{ | ||||
| 				run("techmap -map +/mul2dsp.v [...]", "(unless -nodsp)"); | ||||
| 				run("techmap -map +/gowin/dsp_map.v [...]", "(unless -nodsp)"); | ||||
| 			} else if (!nodsp) { | ||||
| 				if (family == "gw1n" || family == "gw2a") | ||||
| 				{ | ||||
| 					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 +/gowin/dsp_map.v"); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			run("synth -run coarse" + no_rw_check_opt); | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										47
									
								
								tests/arch/gowin/mul_gw1n.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tests/arch/gowin/mul_gw1n.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| read_verilog ../common/mul.v | ||||
| chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 | ||||
| hierarchy -top top | ||||
| proc | ||||
| # equivalence checking is somewhat slow (and missing simulation models) | ||||
| synth_gowin -family gw1n | ||||
| 
 | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT9X9 | ||||
| # XXX: Whats's `top/x_IBUF_I_O_MULT9X9_A_A_GND_G` ?? | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT9X9 %% t:* %D | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog ../common/mul.v | ||||
| chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32 | ||||
| hierarchy -top top | ||||
| proc | ||||
| synth_gowin -family gw1n | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT18X18 | ||||
| # XXX: top/x_IBUF_I_O_MULT18X18_A_A_GND_G ??? | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT18X18 %% t:* %D | ||||
| 
 | ||||
| 
 | ||||
| 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_gowin | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT36X36 | ||||
| # XXX: top/x_IBUF_I_O_MULT36X36_A_A_GND_G | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT36X36 %% t:* %D | ||||
| 
 | ||||
| # TODO: We end up with two 18x18 multipliers | ||||
| # 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_gowin | ||||
| # cd top # Constrain all select calls below inside the top module | ||||
| # select -assert-count 2 t:MULT18X18 | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT36X36 %% t:* %D | ||||
							
								
								
									
										47
									
								
								tests/arch/gowin/mul_gw2a.ys
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								tests/arch/gowin/mul_gw2a.ys
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| read_verilog ../common/mul.v | ||||
| chparam -set X_WIDTH 8 -set Y_WIDTH 8 -set A_WIDTH 16 | ||||
| hierarchy -top top | ||||
| proc | ||||
| # equivalence checking is somewhat slow (and missing simulation models) | ||||
| synth_gowin -family gw2a | ||||
| 
 | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT9X9 | ||||
| # XXX: Whats's `top/x_IBUF_I_O_MULT9X9_A_A_GND_G` ?? | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT9X9 %% t:* %D | ||||
| 
 | ||||
| design -reset | ||||
| read_verilog ../common/mul.v | ||||
| chparam -set X_WIDTH 16 -set Y_WIDTH 16 -set A_WIDTH 32 | ||||
| hierarchy -top top | ||||
| proc | ||||
| synth_gowin -family gw2a | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT18X18 | ||||
| # XXX: top/x_IBUF_I_O_MULT18X18_A_A_GND_G ??? | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT18X18 %% t:* %D | ||||
| 
 | ||||
| 
 | ||||
| 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_gowin -family gw2a | ||||
| cd top # Constrain all select calls below inside the top module | ||||
| select -assert-count 1 t:MULT36X36 | ||||
| # XXX: top/x_IBUF_I_O_MULT36X36_A_A_GND_G | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT36X36 %% t:* %D | ||||
| 
 | ||||
| # TODO: We end up with two 18x18 multipliers | ||||
| # 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_gowin -family gw2a | ||||
| # cd top # Constrain all select calls below inside the top module | ||||
| # select -assert-count 2 t:MULT18X18 | ||||
| # select -assert-none t:IBUF t:OBUF t:MULT36X36 %% t:* %D | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue