mirror of
				https://github.com/YosysHQ/yosys
				synced 2025-10-31 03:32:29 +00:00 
			
		
		
		
	Add flooring division operator
The $div and $mod cells use truncating division semantics (rounding towards 0), as defined by e.g. Verilog. Another rounding mode, flooring (rounding towards negative infinity), can be used in e.g. VHDL. The new $divfloor cell provides this flooring division. This commit also fixes the handling of $div in opt_expr, which was previously optimized as if it was $divfloor.
This commit is contained in:
		
							parent
							
								
									17163cf43a
								
							
						
					
					
						commit
						edd8ff2c07
					
				
					 19 changed files with 213 additions and 24 deletions
				
			
		|  | @ -997,6 +997,12 @@ endmodule | |||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| //  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||||
| //- | ||||
| //-     $div (A, B, Y) | ||||
| //- | ||||
| //- Division with truncated result (rounded towards 0). | ||||
| //- | ||||
| module \$div (A, B, Y); | ||||
| 
 | ||||
| parameter A_SIGNED = 0; | ||||
|  | @ -1053,6 +1059,43 @@ endmodule | |||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| //  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||||
| //- | ||||
| //-     $divfloor (A, B, Y) | ||||
| //- | ||||
| //- Division with floored result (rounded towards negative infinity). | ||||
| //- | ||||
| module \$divfloor (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; | ||||
| 
 | ||||
| generate | ||||
| 	if (A_SIGNED && B_SIGNED) begin:BLOCK1 | ||||
| 		localparam WIDTH = | ||||
| 				A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH : | ||||
| 				B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH; | ||||
| 		wire [WIDTH:0] A_buf, B_buf, N_buf; | ||||
| 		assign A_buf = $signed(A); | ||||
| 		assign B_buf = $signed(B); | ||||
| 		assign N_buf = (A[A_WIDTH-1] == B[B_WIDTH-1]) || A == 0 ? A_buf : $signed(A_buf - (B[B_WIDTH-1] ? B_buf+1 : B_buf-1)); | ||||
| 		assign Y = $signed(N_buf) / $signed(B_buf); | ||||
| 	end else begin:BLOCK2 | ||||
| 		assign Y = A / B; | ||||
| 	end | ||||
| endgenerate | ||||
| 
 | ||||
| endmodule | ||||
| 
 | ||||
| // -------------------------------------------------------- | ||||
| 
 | ||||
| //  |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| | ||||
| //- | ||||
| //-     $modfloor (A, B, Y) | ||||
|  |  | |||
|  | @ -506,6 +506,34 @@ module \$__div_mod_floor (A, B, Y, R); | |||
| 	assign R = (R_s != 0) && A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? $signed(B_buf) + $signed(R_s) : R_s; | ||||
| endmodule | ||||
| 
 | ||||
| (* techmap_celltype = "$divfloor" *) | ||||
| module _90_divfloor (A, B, Y); | ||||
| 	parameter A_SIGNED = 0; | ||||
| 	parameter B_SIGNED = 0; | ||||
| 	parameter A_WIDTH = 1; | ||||
| 	parameter B_WIDTH = 1; | ||||
| 	parameter Y_WIDTH = 1; | ||||
| 
 | ||||
| 	(* force_downto *) | ||||
| 	input [A_WIDTH-1:0] A; | ||||
| 	(* force_downto *) | ||||
| 	input [B_WIDTH-1:0] B; | ||||
| 	(* force_downto *) | ||||
| 	output [Y_WIDTH-1:0] Y; | ||||
| 
 | ||||
| 	\$__div_mod_floor #( | ||||
| 		.A_SIGNED(A_SIGNED), | ||||
| 		.B_SIGNED(B_SIGNED), | ||||
| 		.A_WIDTH(A_WIDTH), | ||||
| 		.B_WIDTH(B_WIDTH), | ||||
| 		.Y_WIDTH(Y_WIDTH) | ||||
| 	) div_mod ( | ||||
| 		.A(A), | ||||
| 		.B(B), | ||||
| 		.Y(Y) | ||||
| 	); | ||||
| endmodule | ||||
| 
 | ||||
| (* techmap_celltype = "$modfloor" *) | ||||
| module _90_modfloor (A, B, Y); | ||||
| 	parameter A_SIGNED = 0; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue