mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-30 19:22:31 +00:00 
			
		
		
		
	Merge pull request #1648 from YosysHQ/eddie/cmp2lcu
"techmap -map +/cmp2lcu.v" for decomposing arithmetic compares to $lcu
This commit is contained in:
		
						commit
						d61a6b81fc
					
				
					 6 changed files with 173 additions and 13 deletions
				
			
		|  | @ -30,3 +30,4 @@ $(eval $(call add_share_file,share,techlibs/common/cmp2lut.v)) | |||
| $(eval $(call add_share_file,share,techlibs/common/cells.lib)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/mul2dsp.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/abc9_model.v)) | ||||
| $(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v)) | ||||
|  |  | |||
							
								
								
									
										116
									
								
								techlibs/common/cmp2lcu.v
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								techlibs/common/cmp2lcu.v
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | |||
| // This pass performs an optimisation that decomposes wide arithmetic | ||||
| //   comparisons into LUT-size chunks (as guided by the `LUT_WIDTH | ||||
| //   macro) connected to a single lookahead-carry-unit $lcu cell, | ||||
| //   which is typically mapped to dedicated (and fast) FPGA | ||||
| //   carry-chains. | ||||
| (* techmap_celltype = "$lt $le $gt $ge" *) | ||||
| module _80_lcu_cmp_ (A, B, Y); | ||||
| 
 | ||||
| parameter A_SIGNED = 0; | ||||
| parameter B_SIGNED = 0; | ||||
| parameter A_WIDTH = 0; | ||||
| parameter B_WIDTH = 0; | ||||
| parameter Y_WIDTH = 0; | ||||
| 
 | ||||
| input [A_WIDTH-1:0] A; | ||||
| input [B_WIDTH-1:0] B; | ||||
| output [Y_WIDTH-1:0] Y; | ||||
| 
 | ||||
| parameter _TECHMAP_CELLTYPE_ = ""; | ||||
| 
 | ||||
| generate | ||||
|     if (_TECHMAP_CELLTYPE_ == "" || `LUT_WIDTH < 2) | ||||
|         wire _TECHMAP_FAIL_ = 1; | ||||
|     else if (_TECHMAP_CELLTYPE_ == "$lt") begin | ||||
|         // Transform $lt into $gt by swapping A and B | ||||
|         $gt #(.A_SIGNED(B_SIGNED), .B_SIGNED(A_SIGNED), .A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(B), .B(A), .Y(Y)); | ||||
|     end | ||||
|     else if (_TECHMAP_CELLTYPE_ == "$le") begin | ||||
|         // Transform $le into $ge by swapping A and B | ||||
|         $ge #(.A_SIGNED(B_SIGNED), .B_SIGNED(A_SIGNED), .A_WIDTH(B_WIDTH), .B_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) _TECHMAP_REPLACE_ (.A(B), .B(A), .Y(Y)); | ||||
|     end | ||||
|     else begin | ||||
|         // Perform sign extension on A and B | ||||
|         localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH; | ||||
|         wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A}; | ||||
|         wire [WIDTH-1:0] BB = {{(WIDTH-B_WIDTH){B_SIGNED ? B[B_WIDTH-1] : 1'b0}}, B}; | ||||
|         // For $ge operation, start with the assumption that A and B are | ||||
|         //   equal (propagating this equality if A and B turn out to be so) | ||||
|         if (_TECHMAP_CELLTYPE_ == "$ge") | ||||
|             localparam CI = 1'b1; | ||||
|         else | ||||
|             localparam CI = 1'b0; | ||||
|         $__CMP2LCU #(.AB_WIDTH(WIDTH), .AB_SIGNED(A_SIGNED && B_SIGNED), .LCU_WIDTH(1), .BUDGET(`LUT_WIDTH), .CI(CI)) | ||||
|             _TECHMAP_REPLACE_ (.A(AA), .B(BB), .P(1'b1), .G(1'b0), .Y(Y)); | ||||
|     end | ||||
| endgenerate | ||||
| endmodule | ||||
| 
 | ||||
| module $__CMP2LCU (A, B, P, G, Y); | ||||
| 
 | ||||
| parameter AB_WIDTH = 0; | ||||
| parameter AB_SIGNED = 0; | ||||
| parameter LCU_WIDTH = 1; | ||||
| parameter BUDGET = 0; | ||||
| parameter CI = 0; | ||||
| 
 | ||||
| input [AB_WIDTH-1:0] A; // A from original $gt/$ge | ||||
| input [AB_WIDTH-1:0] B; // B from original $gt/$ge | ||||
| input [LCU_WIDTH-1:0] P; // P of $lcu | ||||
| input [LCU_WIDTH-1:0] G; // G of $lcu | ||||
| output Y; | ||||
| 
 | ||||
| parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_A_ = 0; | ||||
| parameter [AB_WIDTH-1:0] _TECHMAP_CONSTMSK_B_ = 0; | ||||
| parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0; | ||||
| 
 | ||||
| generate | ||||
|     if (AB_WIDTH == 0) begin | ||||
|         wire [LCU_WIDTH-1:0] CO; | ||||
|         $lcu #(.WIDTH(LCU_WIDTH)) _TECHMAP_REPLACE_ (.P(P), .G(G), .CI(CI), .CO(CO)); | ||||
|         assign Y = CO[LCU_WIDTH-1]; | ||||
|     end | ||||
|     else begin | ||||
|         if (_TECHMAP_CONSTMSK_A_[AB_WIDTH-1:0] && _TECHMAP_CONSTMSK_B_[AB_WIDTH-1:0]) | ||||
|             localparam COST = 0; | ||||
|         else if (_TECHMAP_CONSTMSK_A_[AB_WIDTH-1:0] || _TECHMAP_CONSTMSK_B_[AB_WIDTH-1:0]) | ||||
|             localparam COST = 1; | ||||
|         else | ||||
|             localparam COST = 2; | ||||
| 
 | ||||
|         if (BUDGET < COST) | ||||
|              $__CMP2LCU #(.AB_WIDTH(AB_WIDTH), .AB_SIGNED(AB_SIGNED), .LCU_WIDTH(LCU_WIDTH+1), .BUDGET(`LUT_WIDTH), .CI(CI)) | ||||
|                 _TECHMAP_REPLACE_ (.A(A), .B(B), .P({P, 1'b1}), .G({G, 1'b0}), .Y(Y)); | ||||
|         else begin | ||||
|             wire PP, GG; | ||||
|             // Bit-wise equality (xnor) of A and B | ||||
|             assign PP = A[AB_WIDTH-1] ^~ B[AB_WIDTH-1]; | ||||
|             if (AB_SIGNED) | ||||
|                 assign GG = ~A[AB_WIDTH-1] & B[AB_WIDTH-1]; | ||||
|             else if (_TECHMAP_CONSTMSK_P_[LCU_WIDTH-1]) // First compare for LUT if P (and G) is constant | ||||
|                 assign GG = A[AB_WIDTH-1] & ~B[AB_WIDTH-1]; | ||||
|             else | ||||
|                 // Priority "encoder" that checks A[i] == 1'b1 && B[i] == 1'b0 | ||||
|                 //   from MSB down, deferring to less significant bits if the | ||||
|                 //   MSBs are equal | ||||
|                 assign GG = P[0] & (A[AB_WIDTH-1] & ~B[AB_WIDTH-1]); | ||||
|             if (LCU_WIDTH == 1) begin | ||||
|                 // Propagate only if all pairs are equal | ||||
|                 //   (inconclusive evidence to say A >= B) | ||||
|                 wire P_ = P[0] & PP; | ||||
|                 // Generate if any comparisons call for it | ||||
|                 wire G_ = G[0] | GG; | ||||
|             end | ||||
|             else begin | ||||
|                 // Propagate only if all pairs are equal | ||||
|                 //   (inconclusive evidence to say A >= B) | ||||
|                 wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP}; | ||||
|                 // Generate if any comparisons call for it | ||||
|                 wire [LCU_WIDTH-1:0] G_ = {G[LCU_WIDTH-1:1], G[0] | GG}; | ||||
|             end | ||||
|             $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI)) | ||||
|                 _TECHMAP_REPLACE_ (.A(A[AB_WIDTH-2:0]), .B(B[AB_WIDTH-2:0]), .P(P_), .G(G_), .Y(Y)); | ||||
|         end | ||||
|     end | ||||
| endgenerate | ||||
| endmodule | ||||
|  | @ -57,10 +57,6 @@ function automatic [(1 << `LUT_WIDTH)-1:0] gen_lut; | |||
| 				o_bit = (lhs >  rhs); | ||||
| 			if (operation == 3) | ||||
| 				o_bit = (lhs >= rhs); | ||||
| 			if (operation == 4) | ||||
| 				o_bit = (lhs == rhs); | ||||
| 			if (operation == 5) | ||||
| 				o_bit = (lhs != rhs); | ||||
| 			gen_lut = gen_lut | (o_bit << n); | ||||
| 		end | ||||
| 	end | ||||
|  | @ -75,10 +71,6 @@ generate | |||
| 		localparam operation = 2; | ||||
| 	if (_TECHMAP_CELLTYPE_ == "$ge") | ||||
| 		localparam operation = 3; | ||||
| 	if (_TECHMAP_CELLTYPE_ == "$eq") | ||||
| 		localparam operation = 4; | ||||
| 	if (_TECHMAP_CELLTYPE_ == "$ne") | ||||
| 		localparam operation = 5; | ||||
| 
 | ||||
| 	if (A_WIDTH > `LUT_WIDTH || B_WIDTH > `LUT_WIDTH || Y_WIDTH != 1) | ||||
| 		wire _TECHMAP_FAIL_ = 1; | ||||
|  |  | |||
|  | @ -225,9 +225,9 @@ struct SynthPass : public ScriptPass | |||
| 			run("peepopt"); | ||||
| 			run("opt_clean"); | ||||
| 			if (help_mode) | ||||
| 				run("techmap -map +/cmp2lut.v", " (if -lut)"); | ||||
| 			else | ||||
| 				run(stringf("techmap -map +/cmp2lut.v -D LUT_WIDTH=%d", lut)); | ||||
| 				run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)"); | ||||
| 			else if (lut) | ||||
| 				run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut)); | ||||
| 			if (!noalumacc) | ||||
| 				run("alumacc", "  (unless -noalumacc)"); | ||||
| 			if (!noshare) | ||||
|  |  | |||
|  | @ -393,8 +393,6 @@ struct SynthXilinxPass : public ScriptPass | |||
| 				run("pmux2shiftx", "(skip if '-nosrl' and '-widemux=0')"); | ||||
| 				run("clean", "      (skip if '-nosrl' and '-widemux=0')"); | ||||
| 			} | ||||
| 
 | ||||
| 			run("techmap -map +/cmp2lut.v -D LUT_WIDTH=" + lut_size_s); | ||||
| 		} | ||||
| 
 | ||||
| 		if (check_label("map_dsp", "(skip if '-nodsp')")) { | ||||
|  | @ -460,6 +458,7 @@ struct SynthXilinxPass : public ScriptPass | |||
| 		} | ||||
| 
 | ||||
| 		if (check_label("coarse")) { | ||||
| 			run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=" + lut_size_s); | ||||
| 			run("alumacc"); | ||||
| 			run("share"); | ||||
| 			run("opt"); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue