Working for unsigned
[yosys.git] / techlibs / common / mul2dsp.v
1 // From Eddie Hung
2 // extracted from: https://github.com/eddiehung/vtr-with-yosys/blob/vtr7-with-yosys/vtr_flow/misc/yosys_models.v#L220
3 // revised by Andre DeHon
4 // further revised by David Shah
5 `ifndef DSP_A_MAXWIDTH
6 $error("Macro DSP_A_MAXWIDTH must be defined");
7 `endif
8 `ifndef DSP_A_SIGNEDONLY
9 `define DSP_A_SIGNEDONLY 0
10 `endif
11 `ifndef DSP_B_MAXWIDTH
12 $error("Macro DSP_B_MAXWIDTH must be defined");
13 `endif
14 `ifndef DSP_B_SIGNEDONLY
15 `define DSP_B_SIGNEDONLY 0
16 `endif
17
18 `ifndef DSP_NAME
19 $error("Macro DSP_NAME must be defined");
20 `endif
21
22 `define MAX(a,b) (a > b ? a : b)
23 `define MIN(a,b) (a < b ? a : b)
24
25 module \$mul (A, B, Y);
26 parameter A_SIGNED = 0;
27 parameter B_SIGNED = 0;
28 parameter A_WIDTH = 1;
29 parameter B_WIDTH = 1;
30 parameter Y_WIDTH = 1;
31
32 input [A_WIDTH-1:0] A;
33 input [B_WIDTH-1:0] B;
34 output [Y_WIDTH-1:0] Y;
35
36 generate
37 if (`DSP_SIGNEDONLY && !A_SIGNED) begin
38 wire [1:0] dummy;
39 \$mul #(
40 .A_SIGNED(1),
41 .B_SIGNED(1),
42 .A_WIDTH(A_WIDTH + 1),
43 .B_WIDTH(B_WIDTH + 1),
44 .Y_WIDTH(Y_WIDTH + 2)
45 ) _TECHMAP_REPLACE_ (
46 .A({1'b0, A}),
47 .B({1'b0, B}),
48 .Y({dummy, Y})
49 );
50 end
51 // NB: A_SIGNED == B_SIGNED == 0 from here
52 else if (A_WIDTH >= B_WIDTH)
53 \$__mul_gen #(
54 .A_SIGNED(A_SIGNED),
55 .B_SIGNED(B_SIGNED),
56 .A_WIDTH(A_WIDTH),
57 .B_WIDTH(B_WIDTH),
58 .Y_WIDTH(Y_WIDTH)
59 ) _TECHMAP_REPLACE_ (
60 .A(A),
61 .B(B),
62 .Y(Y)
63 );
64 else
65 \$__mul_gen #(
66 .A_SIGNED(B_SIGNED),
67 .B_SIGNED(A_SIGNED),
68 .A_WIDTH(B_WIDTH),
69 .B_WIDTH(A_WIDTH),
70 .Y_WIDTH(Y_WIDTH)
71 ) _TECHMAP_REPLACE_ (
72 .A(B),
73 .B(A),
74 .Y(Y)
75 );
76 endgenerate
77 endmodule
78
79 module \$__mul_gen (A, B, Y);
80 parameter A_SIGNED = 0;
81 parameter B_SIGNED = 0;
82 parameter A_WIDTH = 1;
83 parameter B_WIDTH = 1;
84 parameter Y_WIDTH = 1;
85
86 input [A_WIDTH-1:0] A;
87 input [B_WIDTH-1:0] B;
88 output [Y_WIDTH-1:0] Y;
89
90 wire [1023:0] _TECHMAP_DO_ = "proc; clean";
91
92 `ifdef DSP_SIGNEDONLY
93 localparam sign_headroom = 1;
94 `else
95 localparam sign_headroom = 0;
96 `endif
97
98 genvar i;
99 generate
100 if (A_WIDTH > `DSP_A_MAXWIDTH) begin
101 localparam n = (A_WIDTH + `DSP_A_MAXWIDTH - sign_headroom - 1)/(`DSP_A_MAXWIDTH - sign_headroom);
102 localparam partial_Y_WIDTH = `MIN(Y_WIDTH, B_WIDTH+`DSP_A_MAXWIDTH);
103 wire [partial_Y_WIDTH-1:0] partial [n-1:1];
104 wire [Y_WIDTH-1:0] partial_sum [n-1:0];
105
106 \$__mul_gen #(
107 .A_SIGNED(0),
108 .B_SIGNED(0),
109 .A_WIDTH(`DSP_A_MAXWIDTH),
110 .B_WIDTH(B_WIDTH),
111 .Y_WIDTH(partial_Y_WIDTH)
112 ) mul_slice_first (
113 .A({{sign_headroom{1'b0}}, A[`DSP_A_MAXWIDTH-sign_headroom-1:0]}),
114 .B(B),
115 .Y(partial[0])
116 );
117 assign partial_sum[0] = partial[0];
118
119 for (i = 1; i < n-1; i=i+1) begin:slice
120 \$__mul_gen #(
121 .A_SIGNED(0),
122 .B_SIGNED(0),
123 .A_WIDTH(`DSP_A_MAXWIDTH),
124 .B_WIDTH(B_WIDTH),
125 .Y_WIDTH(partial_Y_WIDTH)
126 ) mul_slice (
127 .A({{sign_headroom{1'b0}}, A[i*(`DSP_A_MAXWIDTH-sign_headroom) +: `DSP_A_MAXWIDTH-sign_headroom]}),
128 .B(B),
129 .Y(partial[i])
130 );
131 assign partial_sum[i] = (partial[i] << i*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[i-1];
132 end
133
134 \$__mul_gen #(
135 .A_SIGNED(A_SIGNED),
136 .B_SIGNED(B_SIGNED),
137 .A_WIDTH(A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom)),
138 .B_WIDTH(B_WIDTH),
139 .Y_WIDTH(A_WIDTH-(n-1)*(`DSP_A_MAXWIDTH-sign_headroom) + B_WIDTH),
140 ) mul_slice_last (
141 .A(A[A_WIDTH-1:(n-1)*(`DSP_A_MAXWIDTH-sign_headroom)]),
142 .B(B),
143 .Y(partial[n-1])
144 );
145 assign Y = (partial[n-1] << (n-1)*(`DSP_A_MAXWIDTH-sign_headroom)) + partial_sum[n-2];
146 end
147 else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
148 `ifdef DSP_B_SIGNEDONLY
149 localparam sign_headroom = 1;
150 `else
151 localparam sign_headroom = 0;
152 `endif
153 localparam n = (B_WIDTH + `DSP_B_MAXWIDTH - sign_headroom - 1)/(`DSP_B_MAXWIDTH - sign_headroom);
154 localparam partial_Y_WIDTH = `MIN(Y_WIDTH, A_WIDTH+`DSP_B_MAXWIDTH);
155 wire [partial_Y_WIDTH-1:0] partial [n-1:1];
156 wire [Y_WIDTH-1:0] partial_sum [n-1:0];
157
158 \$__mul_gen #(
159 .A_SIGNED(A_SIGNED),
160 .B_SIGNED(0),
161 .A_WIDTH(A_WIDTH),
162 .B_WIDTH(`DSP_B_MAXWIDTH),
163 .Y_WIDTH(partial_Y_WIDTH)
164 ) mul_first (
165 .A(A),
166 .B({{sign_headroom{1'b0}}, B[`DSP_B_MAXWIDTH-sign_headroom-1:0]}),
167 .Y(partial[0])
168 );
169 assign partial_sum[0] = partial[0];
170
171 for (i = 1; i < n-1; i=i+1) begin:slice
172 \$__mul_gen #(
173 .A_SIGNED(A_SIGNED),
174 .B_SIGNED(0),
175 .A_WIDTH(A_WIDTH),
176 .B_WIDTH(`DSP_B_MAXWIDTH),
177 .Y_WIDTH(partial_Y_WIDTH)
178 ) mul (
179 .A(A),
180 .B({{sign_headroom{1'b0}}, B[i*(`DSP_B_MAXWIDTH-sign_headroom) +: `DSP_B_MAXWIDTH-sign_headroom]}),
181 .Y(partial[i])
182 );
183 assign partial_sum[i] = (partial[i] << i*(`DSP_B_MAXWIDTH - sign_headroom)) + partial_sum[i-1];
184 end
185
186 \$__mul_gen #(
187 .A_SIGNED(A_SIGNED),
188 .B_SIGNED(B_SIGNED),
189 .A_WIDTH(A_WIDTH),
190 .B_WIDTH(B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH - sign_headroom)),
191 .Y_WIDTH(A_WIDTH + B_WIDTH-(n-1)*(`DSP_B_MAXWIDTH - sign_headroom))
192 ) mul_last (
193 .A(A),
194 .B(B[B_WIDTH-1:(n-1)*(`DSP_B_MAXWIDTH - sign_headroom)]),
195 .Y(partial[n-1])
196 );
197 assign Y = (partial[n-1] << (n-1)*(`DSP_B_MAXWIDTH - sign_headroom)) + partial_sum[n-2];
198 end
199 else begin
200 if (A_SIGNED)
201 wire signed [`DSP_A_MAXWIDTH-1:0] Aext = $signed(A);
202 else
203 wire [`DSP_A_MAXWIDTH-1:0] Aext = A;
204 if (B_SIGNED)
205 wire signed [`DSP_B_MAXWIDTH-1:0] Bext = $signed(B);
206 else
207 wire [`DSP_B_MAXWIDTH-1:0] Bext = B;
208
209 `DSP_NAME _TECHMAP_REPLACE_ (
210 .A(Aext),
211 .B(Bext),
212 .Y(Y)
213 );
214 end
215 endgenerate
216 endmodule
217
218