mirror of
https://github.com/YosysHQ/yosys
synced 2025-06-20 12:53:39 +00:00
Add flooring modulo 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 $modfloor cell provides this flooring modulo (also known as "remainder" in several languages, but this name is ambiguous). This commit also fixes the handling of $mod in opt_expr, which was previously optimized as if it was $modfloor.
This commit is contained in:
parent
0d99522b3c
commit
17163cf43a
23 changed files with 280 additions and 37 deletions
|
@ -1021,6 +1021,14 @@ endmodule
|
|||
|
||||
// --------------------------------------------------------
|
||||
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
//-
|
||||
//- $mod (A, B, Y)
|
||||
//-
|
||||
//- Modulo/remainder of division with truncated result (rounded towards 0).
|
||||
//-
|
||||
//- Invariant: $div(A, B) * B + $mod(A, B) == A
|
||||
//-
|
||||
module \$mod (A, B, Y);
|
||||
|
||||
parameter A_SIGNED = 0;
|
||||
|
@ -1043,6 +1051,46 @@ endgenerate
|
|||
|
||||
endmodule
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
|
||||
//-
|
||||
//- $modfloor (A, B, Y)
|
||||
//-
|
||||
//- Modulo/remainder of division with floored result (rounded towards negative infinity).
|
||||
//-
|
||||
//- Invariant: $divfloor(A, B) * B + $modfloor(A, B) == A
|
||||
//-
|
||||
module \$modfloor (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 = B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
|
||||
wire [WIDTH-1:0] B_buf, Y_trunc;
|
||||
assign B_buf = $signed(B);
|
||||
assign Y_trunc = $signed(A) % $signed(B);
|
||||
// flooring mod is the same as truncating mod for positive division results (A and B have
|
||||
// the same sign), as well as when there's no remainder.
|
||||
// For all other cases, they behave as `floor - trunc = B`
|
||||
assign Y = (A[A_WIDTH-1] == B[B_WIDTH-1]) || Y_trunc == 0 ? Y_trunc : $signed(B_buf) + $signed(Y_trunc);
|
||||
end else begin:BLOCK2
|
||||
// no difference between truncating and flooring for unsigned
|
||||
assign Y = A % B;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
// --------------------------------------------------------
|
||||
`ifndef SIMLIB_NOPOW
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue