aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/common
diff options
context:
space:
mode:
Diffstat (limited to 'techlibs/common')
-rw-r--r--techlibs/common/Makefile.inc2
-rw-r--r--techlibs/common/abc9_map.v27
-rw-r--r--techlibs/common/abc9_model.v23
-rw-r--r--techlibs/common/abc9_unmap.v11
-rw-r--r--techlibs/common/adff2dff.v3
-rw-r--r--techlibs/common/cmp2lcu.v20
-rw-r--r--techlibs/common/cmp2lut.v3
-rw-r--r--techlibs/common/dff2ff.v2
-rw-r--r--techlibs/common/mul2dsp.v18
-rw-r--r--techlibs/common/simlib.v91
-rw-r--r--techlibs/common/techmap.v159
11 files changed, 347 insertions, 12 deletions
diff --git a/techlibs/common/Makefile.inc b/techlibs/common/Makefile.inc
index 7b1e4b430..607e772a2 100644
--- a/techlibs/common/Makefile.inc
+++ b/techlibs/common/Makefile.inc
@@ -30,4 +30,6 @@ $(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/abc9_map.v))
+$(eval $(call add_share_file,share,techlibs/common/abc9_unmap.v))
$(eval $(call add_share_file,share,techlibs/common/cmp2lcu.v))
diff --git a/techlibs/common/abc9_map.v b/techlibs/common/abc9_map.v
new file mode 100644
index 000000000..6ed90b5f5
--- /dev/null
+++ b/techlibs/common/abc9_map.v
@@ -0,0 +1,27 @@
+`ifdef DFF
+(* techmap_celltype = "$_DFF_N_ $_DFF_P_" *)
+module $_DFF_x_(input C, D, output Q);
+ parameter [0:0] _TECHMAP_WIREINIT_Q_ = 1'bx;
+ parameter _TECHMAP_CELLTYPE_ = "";
+ wire D_;
+ generate if (_TECHMAP_CELLTYPE_ == "$_DFF_N_") begin
+ if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin
+ $__DFF_N__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_));
+ $_DFF_N_ ff (.C(C), .D(D_), .Q(Q));
+ end
+ else
+ (* abc9_keep *) $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
+ end
+ else if (_TECHMAP_CELLTYPE_ == "$_DFF_P_") begin
+ if (_TECHMAP_WIREINIT_Q_ === 1'b0) begin
+ $__DFF_P__$abc9_flop _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q), .n1(D_));
+ $_DFF_P_ ff (.C(C), .D(D_), .Q(Q));
+ end
+ else
+ (* abc9_keep *) $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
+ end
+ else if (_TECHMAP_CELLTYPE_ != "")
+ $error("Unrecognised _TECHMAP_CELLTYPE_");
+ endgenerate
+endmodule
+`endif
diff --git a/techlibs/common/abc9_model.v b/techlibs/common/abc9_model.v
index c0c5dc2fd..4fee60f75 100644
--- a/techlibs/common/abc9_model.v
+++ b/techlibs/common/abc9_model.v
@@ -1,10 +1,25 @@
-module \$__ABC9_FF_ (input D, output Q);
-endmodule
-
(* abc9_box *)
-module \$__ABC9_DELAY (input I, output O);
+module $__ABC9_DELAY (input I, output O);
parameter DELAY = 0;
specify
(I => O) = DELAY;
endspecify
endmodule
+
+(* abc9_flop, abc9_box, lib_whitebox *)
+module $__DFF_N__$abc9_flop (input C, D, Q, output n1);
+ assign n1 = D;
+ specify
+ $setup(D, posedge C, 0);
+ (posedge C => (n1:D)) = 0;
+ endspecify
+endmodule
+
+(* abc9_flop, abc9_box, lib_whitebox *)
+module $__DFF_P__$abc9_flop (input C, D, Q, output n1);
+ assign n1 = D;
+ specify
+ $setup(D, posedge C, 0);
+ (posedge C => (n1:D)) = 0;
+ endspecify
+endmodule
diff --git a/techlibs/common/abc9_unmap.v b/techlibs/common/abc9_unmap.v
new file mode 100644
index 000000000..bcbe91477
--- /dev/null
+++ b/techlibs/common/abc9_unmap.v
@@ -0,0 +1,11 @@
+(* techmap_celltype = "$__DFF_N__$abc9_flop $__DFF_P__$abc9_flop" *)
+module $__DFF_x__$abc9_flop (input C, D, Q, output n1);
+ parameter _TECHMAP_CELLTYPE_ = "";
+ generate if (_TECHMAP_CELLTYPE_ == "$__DFF_N__$abc9_flop")
+ $_DFF_N_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
+ else if (_TECHMAP_CELLTYPE_ == "$__DFF_P__$abc9_flop")
+ $_DFF_P_ _TECHMAP_REPLACE_ (.C(C), .D(D), .Q(Q));
+ else if (_TECHMAP_CELLTYPE_ != "")
+ $error("Unrecognised _TECHMAP_CELLTYPE_");
+ endgenerate
+endmodule
diff --git a/techlibs/common/adff2dff.v b/techlibs/common/adff2dff.v
index 86744d415..eca0110eb 100644
--- a/techlibs/common/adff2dff.v
+++ b/techlibs/common/adff2dff.v
@@ -6,8 +6,11 @@ module adff2dff (CLK, ARST, D, Q);
parameter ARST_VALUE = 0;
input CLK, ARST;
+ (* force_downto *)
input [WIDTH-1:0] D;
+ (* force_downto *)
output reg [WIDTH-1:0] Q;
+ (* force_downto *)
wire reg [WIDTH-1:0] NEXT_Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;";
diff --git a/techlibs/common/cmp2lcu.v b/techlibs/common/cmp2lcu.v
index b6f4aeed6..a221727e7 100644
--- a/techlibs/common/cmp2lcu.v
+++ b/techlibs/common/cmp2lcu.v
@@ -12,8 +12,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
+(* force_downto *)
input [A_WIDTH-1:0] A;
+(* force_downto *)
input [B_WIDTH-1:0] B;
+(* force_downto *)
output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = "";
@@ -32,7 +35,9 @@ generate
else begin
// Perform sign extension on A and B
localparam WIDTH = A_WIDTH > B_WIDTH ? A_WIDTH : B_WIDTH;
+ (* force_downto *)
wire [WIDTH-1:0] AA = {{(WIDTH-A_WIDTH){A_SIGNED ? A[A_WIDTH-1] : 1'b0}}, A};
+ (* force_downto *)
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)
@@ -54,9 +59,13 @@ parameter LCU_WIDTH = 1;
parameter BUDGET = 0;
parameter CI = 0;
+(* force_downto *)
input [AB_WIDTH-1:0] A; // A from original $gt/$ge
+(* force_downto *)
input [AB_WIDTH-1:0] B; // B from original $gt/$ge
+(* force_downto *)
input [LCU_WIDTH-1:0] P; // P of $lcu
+(* force_downto *)
input [LCU_WIDTH-1:0] G; // G of $lcu
output Y;
@@ -66,6 +75,7 @@ parameter [LCU_WIDTH-1:0] _TECHMAP_CONSTMSK_P_ = 0;
generate
if (AB_WIDTH == 0) begin
+ (* force_downto *)
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];
@@ -104,12 +114,18 @@ generate
else begin
// Propagate only if all pairs are equal
// (inconclusive evidence to say A >= B)
+ (* force_downto *)
wire [LCU_WIDTH-1:0] P_ = {P[LCU_WIDTH-1:1], P[0] & PP};
// Generate if any comparisons call for it
+ (* force_downto *)
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));
+ if (AB_WIDTH == 1)
+ $__CMP2LCU #(.AB_WIDTH(AB_WIDTH-1), .AB_SIGNED(1'b0), .LCU_WIDTH(LCU_WIDTH), .BUDGET(BUDGET-COST), .CI(CI))
+ _TECHMAP_REPLACE_ (.A(), .B(), .P(P_), .G(G_), .Y(Y));
+ else
+ $__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
diff --git a/techlibs/common/cmp2lut.v b/techlibs/common/cmp2lut.v
index 8ecd356cc..ec8f98e8d 100644
--- a/techlibs/common/cmp2lut.v
+++ b/techlibs/common/cmp2lut.v
@@ -16,8 +16,11 @@ parameter A_WIDTH = 0;
parameter B_WIDTH = 0;
parameter Y_WIDTH = 0;
+(* force_downto *)
input [A_WIDTH-1:0] A;
+(* force_downto *)
input [B_WIDTH-1:0] B;
+(* force_downto *)
output [Y_WIDTH-1:0] Y;
parameter _TECHMAP_CELLTYPE_ = "";
diff --git a/techlibs/common/dff2ff.v b/techlibs/common/dff2ff.v
index 2dc4d20d3..33a79ffff 100644
--- a/techlibs/common/dff2ff.v
+++ b/techlibs/common/dff2ff.v
@@ -4,7 +4,9 @@ module dff2ff (CLK, D, Q);
parameter CLK_POLARITY = 1;
input CLK;
+ (* force_downto *)
input [WIDTH-1:0] D;
+ (* force_downto *)
output reg [WIDTH-1:0] Q;
wire [1023:0] _TECHMAP_DO_ = "proc;;";
diff --git a/techlibs/common/mul2dsp.v b/techlibs/common/mul2dsp.v
index 4cabb4453..bec47d01f 100644
--- a/techlibs/common/mul2dsp.v
+++ b/techlibs/common/mul2dsp.v
@@ -57,8 +57,11 @@ module _80_mul (A, B, Y);
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;
parameter _TECHMAP_CELLTYPE_ = "";
@@ -119,13 +122,19 @@ module _80_mul (A, B, Y);
localparam last_A_WIDTH = A_WIDTH-n*(`DSP_A_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = B_WIDTH+last_A_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
@@ -170,13 +179,19 @@ module _80_mul (A, B, Y);
localparam last_B_WIDTH = B_WIDTH-n*(`DSP_B_MAXWIDTH_PARTIAL-sign_headroom);
localparam last_Y_WIDTH = A_WIDTH+last_B_WIDTH;
if (A_SIGNED && B_SIGNED) begin
+ (* force_downto *)
wire signed [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire signed [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire signed [Y_WIDTH-1:0] partial_sum [n:0];
end
else begin
+ (* force_downto *)
wire [partial_Y_WIDTH-1:0] partial [n-1:0];
+ (* force_downto *)
wire [last_Y_WIDTH-1:0] last_partial;
+ (* force_downto *)
wire [Y_WIDTH-1:0] partial_sum [n:0];
end
@@ -249,8 +264,11 @@ module _90_soft_mul (A, B, Y);
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;
// Indirection necessary since mapping
diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v
index 2cdddeabb..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;
@@ -1021,6 +1027,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;
@@ -1044,6 +1058,83 @@ endgenerate
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).
+//-
+//- 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
module \$pow (A, B, Y);
diff --git a/techlibs/common/techmap.v b/techlibs/common/techmap.v
index ecf4d5dc5..eafe8d4da 100644
--- a/techlibs/common/techmap.v
+++ b/techlibs/common/techmap.v
@@ -85,8 +85,11 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
localparam shift_left = _TECHMAP_CELLTYPE_ == "$shl" || _TECHMAP_CELLTYPE_ == "$sshl";
localparam sign_extend = A_SIGNED && _TECHMAP_CELLTYPE_ == "$sshr";
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y;
localparam WIDTH = `MAX(A_WIDTH, Y_WIDTH);
@@ -96,6 +99,7 @@ module _90_shift_ops_shr_shl_sshl_sshr (A, B, Y);
wire [1023:0] _TECHMAP_DO_01_ = "RECURSION; CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i;
+ (* force_downto *)
reg [WIDTH-1:0] buffer;
reg overflow;
@@ -125,8 +129,11 @@ module _90_shift_shiftx (A, B, Y);
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;
parameter _TECHMAP_CELLTYPE_ = "";
@@ -173,6 +180,7 @@ module _90_shift_shiftx (A, B, Y);
wire [1023:0] _TECHMAP_DO_01_ = "CONSTMAP; opt_muxtree; opt_expr -mux_undef -mux_bool -fine;;;";
integer i;
+ (* force_downto *)
reg [WIDTH-1:0] buffer;
reg overflow;
@@ -216,9 +224,12 @@ endmodule
module _90_fa (A, B, C, X, Y);
parameter WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A, B, C;
+ (* force_downto *)
output [WIDTH-1:0] X, Y;
+ (* force_downto *)
wire [WIDTH-1:0] t1, t2, t3;
assign t1 = A ^ B, t2 = A & B, t3 = C & t1;
@@ -229,12 +240,15 @@ endmodule
module _90_lcu (P, G, CI, CO);
parameter WIDTH = 2;
+ (* force_downto *)
input [WIDTH-1:0] P, G;
input CI;
+ (* force_downto *)
output [WIDTH-1:0] CO;
integer i, j;
+ (* force_downto *)
reg [WIDTH-1:0] p, g;
wire [1023:0] _TECHMAP_DO_ = "proc; opt -fast";
@@ -278,20 +292,27 @@ module _90_alu (A, B, CI, BI, X, Y, CO);
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] X, Y;
input CI, BI;
+ (* force_downto *)
output [Y_WIDTH-1:0] CO;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] AA = A_buf;
+ (* force_downto *)
+ wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
+
+ (* force_downto *)
wire [Y_WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));
- wire [Y_WIDTH-1:0] AA = A_buf;
- wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
-
\$lcu #(.WIDTH(Y_WIDTH)) lcu (.P(X), .G(AA & BB), .CI(CI), .CO(CO));
assign X = AA ^ BB;
@@ -316,15 +337,19 @@ endmodule
module \$__div_mod_u (A, B, Y, R);
parameter WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A, B;
+ (* force_downto *)
output [WIDTH-1:0] Y, R;
+ (* force_downto *)
wire [WIDTH*WIDTH-1:0] chaindata;
assign R = chaindata[WIDTH*WIDTH-1:WIDTH*(WIDTH-1)];
genvar i;
generate begin
for (i = 0; i < WIDTH; i=i+1) begin:stage
+ (* force_downto *)
wire [WIDTH-1:0] stage_in;
if (i == 0) begin:cp
@@ -339,7 +364,8 @@ module \$__div_mod_u (A, B, Y, R);
end endgenerate
endmodule
-module \$__div_mod (A, B, Y, R);
+// truncating signed division/modulo
+module \$__div_mod_trunc (A, B, Y, R);
parameter A_SIGNED = 0;
parameter B_SIGNED = 0;
parameter A_WIDTH = 1;
@@ -350,14 +376,19 @@ module \$__div_mod (A, B, Y, R);
A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
+ (* force_downto *)
input [A_WIDTH-1:0] A;
+ (* force_downto *)
input [B_WIDTH-1:0] B;
+ (* force_downto *)
output [Y_WIDTH-1:0] Y, R;
+ (* force_downto *)
wire [WIDTH-1:0] A_buf, B_buf;
\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+ (* force_downto *)
wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u;
assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
@@ -383,11 +414,14 @@ module _90_div (A, B, Y);
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 #(
+ \$__div_mod_trunc #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
@@ -408,11 +442,114 @@ module _90_mod (A, B, Y);
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_trunc #(
+ .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),
+ .R(Y)
+ );
+endmodule
+
+// flooring signed division/modulo
+module \$__div_mod_floor (A, B, Y, R);
+ parameter A_SIGNED = 0;
+ parameter B_SIGNED = 0;
+ parameter A_WIDTH = 1;
+ parameter B_WIDTH = 1;
+ parameter Y_WIDTH = 1;
+
+ localparam WIDTH =
+ A_WIDTH >= B_WIDTH && A_WIDTH >= Y_WIDTH ? A_WIDTH :
+ B_WIDTH >= A_WIDTH && B_WIDTH >= Y_WIDTH ? B_WIDTH : Y_WIDTH;
+
+ input [A_WIDTH-1:0] A;
+ input [B_WIDTH-1:0] B;
+ output [Y_WIDTH-1:0] Y, R;
+
+ wire [WIDTH-1:0] A_buf, B_buf;
+ \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(WIDTH)) A_conv (.A(A), .Y(A_buf));
+ \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(WIDTH)) B_conv (.A(B), .Y(B_buf));
+
+ wire [WIDTH-1:0] A_buf_u, B_buf_u, Y_u, R_u, R_s;
+ assign A_buf_u = A_SIGNED && A_buf[WIDTH-1] ? -A_buf : A_buf;
+ assign B_buf_u = B_SIGNED && B_buf[WIDTH-1] ? -B_buf : B_buf;
+
+ \$__div_mod_u #(
+ .WIDTH(WIDTH)
+ ) div_mod_u (
+ .A(A_buf_u),
+ .B(B_buf_u),
+ .Y(Y_u),
+ .R(R_u)
+ );
+
+ // For negative results, if there was a remainder, subtract one to turn
+ // the round towards 0 into a round towards -inf
+ assign Y = A_SIGNED && B_SIGNED && (A_buf[WIDTH-1] != B_buf[WIDTH-1]) ? (R_u == 0 ? -Y_u : -Y_u-1) : Y_u;
+
+ // truncating modulo
+ assign R_s = A_SIGNED && B_SIGNED && A_buf[WIDTH-1] ? -R_u : R_u;
+ // Flooring modulo differs from truncating modulo only if it is nonzero and
+ // A and B have different signs - then `floor - trunc = B`
+ 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;
+ 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 #(
+ \$__div_mod_floor #(
.A_SIGNED(A_SIGNED),
.B_SIGNED(B_SIGNED),
.A_WIDTH(A_WIDTH),
@@ -438,8 +575,11 @@ module _90_pow (A, B, Y);
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;
wire _TECHMAP_FAIL_ = 1;
@@ -455,20 +595,27 @@ module _90_pmux (A, B, S, Y);
parameter WIDTH = 1;
parameter S_WIDTH = 1;
+ (* force_downto *)
input [WIDTH-1:0] A;
+ (* force_downto *)
input [WIDTH*S_WIDTH-1:0] B;
+ (* force_downto *)
input [S_WIDTH-1:0] S;
+ (* force_downto *)
output [WIDTH-1:0] Y;
+ (* force_downto *)
wire [WIDTH-1:0] Y_B;
genvar i, j;
generate
+ (* force_downto *)
wire [WIDTH*S_WIDTH-1:0] B_AND_S;
for (i = 0; i < S_WIDTH; i = i + 1) begin:B_AND
assign B_AND_S[WIDTH*(i+1)-1:WIDTH*i] = B[WIDTH*(i+1)-1:WIDTH*i] & {WIDTH{S[i]}};
end:B_AND
for (i = 0; i < WIDTH; i = i + 1) begin:B_OR
+ (* force_downto *)
wire [S_WIDTH-1:0] B_AND_BITS;
for (j = 0; j < S_WIDTH; j = j + 1) begin:B_AND_BITS_COLLECT
assign B_AND_BITS[j] = B_AND_S[WIDTH*j+i];