diff options
author | Xiretza <xiretza@xiretza.xyz> | 2020-04-21 12:51:58 +0200 |
---|---|---|
committer | Xiretza <xiretza@xiretza.xyz> | 2020-05-28 22:59:04 +0200 |
commit | edd8ff2c0778d97808869488cc7394151456c4ca (patch) | |
tree | 797418b87588ae7a69992b7f107dfd5cdfdec08d /techlibs | |
parent | 17163cf43a6b6eec9aac44f6a4463dda54b8ed68 (diff) | |
download | yosys-edd8ff2c0778d97808869488cc7394151456c4ca.tar.gz yosys-edd8ff2c0778d97808869488cc7394151456c4ca.tar.bz2 yosys-edd8ff2c0778d97808869488cc7394151456c4ca.zip |
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.
Diffstat (limited to 'techlibs')
-rw-r--r-- | techlibs/common/simlib.v | 43 | ||||
-rw-r--r-- | techlibs/common/techmap.v | 28 |
2 files changed, 71 insertions, 0 deletions
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 57fc07caa..125b8e013 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -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; @@ -1055,6 +1061,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) //- //- Modulo/remainder of division with floored result (rounded towards negative infinity). diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v index 95223180d..eafe8d4da 100644 --- a/techlibs/common/techmap.v +++ b/techlibs/common/techmap.v @@ -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; |