aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs
diff options
context:
space:
mode:
authorXiretza <xiretza@xiretza.xyz>2020-04-21 12:51:58 +0200
committerXiretza <xiretza@xiretza.xyz>2020-05-28 22:59:04 +0200
commitedd8ff2c0778d97808869488cc7394151456c4ca (patch)
tree797418b87588ae7a69992b7f107dfd5cdfdec08d /techlibs
parent17163cf43a6b6eec9aac44f6a4463dda54b8ed68 (diff)
downloadyosys-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.v43
-rw-r--r--techlibs/common/techmap.v28
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;