mul2dsp: Fix indentation
[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 `define DSP_A_MAXWIDTH 18
7 `endif
8 `ifndef DSP_A_MAXWIDTH
9 `define DSP_B_MAXWIDTH 25
10 `endif
11
12 `ifndef ADDER_MINWIDTH
13 `define ADDER_MINWIDTH AAA
14 `endif
15
16 `ifndef DSP_NAME
17 `define DSP_NAME M18x25
18 `endif
19
20 `define MAX(a,b) (a > b ? a : b)
21 `define MIN(a,b) (a < b ? a : b)
22
23 (* techmap_celltype = "$mul" *)
24 module \$mul (A, B, Y);
25 parameter A_SIGNED = 0;
26 parameter B_SIGNED = 0;
27 parameter A_WIDTH = 1;
28 parameter B_WIDTH = 1;
29 parameter Y_WIDTH = 1;
30
31 input [A_WIDTH-1:0] A;
32 input [B_WIDTH-1:0] B;
33 output [Y_WIDTH-1:0] Y;
34
35 generate
36 if (B_WIDTH < A_WIDTH)
37 \$__mul_gen #(
38 .A_SIGNED(A_SIGNED),
39 .B_SIGNED(B_SIGNED),
40 .A_WIDTH(A_WIDTH),
41 .B_WIDTH(B_WIDTH),
42 .Y_WIDTH(Y_WIDTH)
43 ) mul_slice (
44 .A(A),
45 .B(B),
46 .Y(Y)
47 );
48 else
49 \$__mul_gen #(
50 .A_SIGNED(B_SIGNED),
51 .B_SIGNED(A_SIGNED),
52 .A_WIDTH(B_WIDTH),
53 .B_WIDTH(A_WIDTH),
54 .Y_WIDTH(Y_WIDTH)
55 ) mul_slice (
56 .A(B),
57 .B(A),
58 .Y(Y)
59 );
60 endgenerate
61 endmodule
62
63 module \$__mul_gen (A, B, Y);
64 parameter A_SIGNED = 0;
65 parameter B_SIGNED = 0;
66 parameter A_WIDTH = 1;
67 parameter B_WIDTH = 1;
68 parameter Y_WIDTH = 1;
69
70 input [A_WIDTH-1:0] A;
71 input [B_WIDTH-1:0] B;
72 output [Y_WIDTH-1:0] Y;
73
74 wire [1023:0] _TECHMAP_DO_ = "proc; clean";
75
76 genvar i;
77 generate
78 if (A_WIDTH > `DSP_A_MAXWIDTH) begin
79 localparam n_floored = A_WIDTH/`DSP_A_MAXWIDTH;
80 localparam n = n_floored + (n_floored*`DSP_A_MAXWIDTH < A_WIDTH ? 1 : 0);
81 wire [`DSP_A_MAXWIDTH+B_WIDTH-1:0] partial [n-1:1];
82 wire [Y_WIDTH-1:0] partial_sum [n-2:0];
83
84 \$__mul_gen #(
85 .A_SIGNED(A_SIGNED),
86 .B_SIGNED(B_SIGNED),
87 .A_WIDTH(`DSP_A_MAXWIDTH),
88 .B_WIDTH(B_WIDTH),
89 .Y_WIDTH(B_WIDTH+`DSP_A_MAXWIDTH)
90 ) mul_slice_first (
91 .A(A[`DSP_A_MAXWIDTH-1:0]),
92 .B(B),
93 .Y(partial_sum[0][B_WIDTH+`DSP_A_MAXWIDTH-1:0])
94 );
95 assign partial_sum[0][Y_WIDTH-1:B_WIDTH+`DSP_A_MAXWIDTH]=0;
96
97 for (i = 1; i < n-1; i=i+1) begin:slice
98 \$__mul_gen #(
99 .A_SIGNED(A_SIGNED),
100 .B_SIGNED(B_SIGNED),
101 .A_WIDTH(`DSP_A_MAXWIDTH),
102 .B_WIDTH(B_WIDTH),
103 .Y_WIDTH(B_WIDTH+`DSP_A_MAXWIDTH)
104 ) mul_slice (
105 .A(A[(i+1)*`DSP_A_MAXWIDTH-1:i*`DSP_A_MAXWIDTH]),
106 .B(B),
107 .Y(partial[i][B_WIDTH+`DSP_A_MAXWIDTH-1:0])
108 );
109 //assign partial_sum[i] = (partial[i] << i*`DSP_A_MAXWIDTH) + partial_sum[i-1];
110 assign partial_sum[i] = {
111 partial[i][B_WIDTH+`DSP_A_MAXWIDTH-1:0]
112 + partial_sum[i-1][Y_WIDTH-1:(i*`DSP_A_MAXWIDTH)],
113 partial_sum[i-1][(i*`DSP_A_MAXWIDTH)-1:0]
114 };
115 end
116
117 \$__mul_gen #(
118 .A_SIGNED(A_SIGNED),
119 .B_SIGNED(B_SIGNED),
120 .A_WIDTH(A_WIDTH-(n-1)*`DSP_A_MAXWIDTH),
121 .B_WIDTH(B_WIDTH),
122 .Y_WIDTH(A_WIDTH-(n-1)*`DSP_A_MAXWIDTH+B_WIDTH),
123 ) mul_slice_last (
124 .A(A[A_WIDTH-1:(n-1)*`DSP_A_MAXWIDTH]),
125 .B(B),
126 .Y(partial[n-1][A_WIDTH-(n-1)*`DSP_A_MAXWIDTH+B_WIDTH-1:0])
127 );
128 //assign Y = (partial[n-1] << (n-1)*`DSP_A_MAXWIDTH) + partial_sum[n-2];
129 assign Y = {
130 partial[n-1][A_WIDTH-(n-1)*`DSP_A_MAXWIDTH+B_WIDTH:0]
131 + partial_sum[n-2][Y_WIDTH-1:((n-1)*`DSP_A_MAXWIDTH)],
132 partial_sum[n-2][((n-1)*`DSP_A_MAXWIDTH)-1:0]
133 };
134 end
135 else if (B_WIDTH > `DSP_B_MAXWIDTH) begin
136 localparam n_floored = B_WIDTH/`DSP_B_MAXWIDTH;
137 localparam n = n_floored + (n_floored*`DSP_B_MAXWIDTH < B_WIDTH ? 1 : 0);
138 wire [A_WIDTH+`DSP_B_MAXWIDTH-1:0] partial [n-1:1];
139 wire [Y_WIDTH-1:0] partial_sum [n-2:0];
140
141 \$__mul_gen #(
142 .A_SIGNED(A_SIGNED),
143 .B_SIGNED(B_SIGNED),
144 .A_WIDTH(A_WIDTH),
145 .B_WIDTH(`DSP_B_MAXWIDTH),
146 .Y_WIDTH(A_WIDTH+`DSP_B_MAXWIDTH)
147 ) mul_first (
148 .A(A),
149 .B(B[`DSP_B_MAXWIDTH-1:0]),
150 .Y(partial_sum[0][A_WIDTH+`DSP_B_MAXWIDTH-1:0])
151 );
152 assign partial_sum[0][Y_WIDTH-1:A_WIDTH+`DSP_B_MAXWIDTH]=0;
153
154 for (i = 1; i < n-1; i=i+1) begin:slice
155 \$__mul_gen #(
156 .A_SIGNED(A_SIGNED),
157 .B_SIGNED(B_SIGNED),
158 .A_WIDTH(A_WIDTH),
159 .B_WIDTH(`DSP_B_MAXWIDTH),
160 .Y_WIDTH(A_WIDTH+`DSP_B_MAXWIDTH)
161 ) mul (
162 .A(A),
163 .B(B[(i+1)*`DSP_B_MAXWIDTH-1:i*`DSP_B_MAXWIDTH]),
164 .Y(partial[i][A_WIDTH+`DSP_B_MAXWIDTH-1:0])
165 );
166 //assign partial_sum[i] = (partial[i] << i*`DSP_B_MAXWIDTH) + partial_sum[i-1];
167 // was:
168 //assign partial_sum[i] = {
169 // partial[i][A_WIDTH+`DSP_B_MAXWIDTH-1:`DSP_B_MAXWIDTH],
170 // partial[i][`DSP_B_MAXWIDTH-1:0] + partial_sum[i-1][A_WIDTH+(i*`DSP_B_MAXWIDTH)-1:A_WIDTH+((i-1)*`DSP_B_MAXWIDTH)],
171 // partial_sum[i-1][A_WIDTH+((i-1)*`DSP_B_MAXWIDTH):0]
172 assign partial_sum[i] = {
173 partial[i][A_WIDTH+`DSP_B_MAXWIDTH-1:0]
174 + partial_sum[i-1][Y_WIDTH-1:(i*`DSP_B_MAXWIDTH)],
175 partial_sum[i-1][(i*`DSP_B_MAXWIDTH)-1:0]
176 };
177 end
178
179 \$__mul_gen #(
180 .A_SIGNED(A_SIGNED),
181 .B_SIGNED(B_SIGNED),
182 .A_WIDTH(A_WIDTH),
183 .B_WIDTH(B_WIDTH-(n-1)*`DSP_B_MAXWIDTH),
184 .Y_WIDTH(A_WIDTH+B_WIDTH-(n-1)*`DSP_B_MAXWIDTH)
185 ) mul_last (
186 .A(A),
187 .B(B[B_WIDTH-1:(n-1)*`DSP_B_MAXWIDTH]),
188 .Y(partial[n-1][A_WIDTH+B_WIDTH-(n-1)*`DSP_B_MAXWIDTH-1:0])
189 );
190 // AMD: this came comment out -- looks closer to right answer
191 //assign Y = (partial[n-1] << (n-1)*`DSP_B_MAXWIDTH) + partial_sum[n-2];
192 // was (looks broken)
193 //assign Y = {
194 // partial[n-1][A_WIDTH+`DSP_B_MAXWIDTH-1:`DSP_B_MAXWIDTH],
195 // partial[n-1][`DSP_B_MAXWIDTH-1:0] + partial_sum[n-2][A_WIDTH+((n-1)*`DSP_B_MAXWIDTH)-1:A_WIDTH+((n-2)*`DSP_B_MAXWIDTH)],
196 // partial_sum[n-2][A_WIDTH+((n-2)*`DSP_B_MAXWIDTH):0]
197 assign Y = {
198 partial[n-1][A_WIDTH+B_WIDTH-(n-1)*`DSP_B_MAXWIDTH-1:0]
199 + partial_sum[n-2][Y_WIDTH-1:((n-1)*`DSP_B_MAXWIDTH)],
200 partial_sum[n-2][((n-1)*`DSP_B_MAXWIDTH)-1:0]
201 };
202 end
203 else begin
204 wire [A_WIDTH+B_WIDTH-1:0] out;
205 wire [(`DSP_A_MAXWIDTH+`DSP_B_MAXWIDTH)-(A_WIDTH+B_WIDTH)-1:0] dummy;
206 wire Asign, Bsign;
207 assign Asign = (A_SIGNED ? A[A_WIDTH-1] : 1'b0);
208 assign Bsign = (B_SIGNED ? B[B_WIDTH-1] : 1'b0);
209 `DSP_NAME _TECHMAP_REPLACE_ (
210 .A({ {{`DSP_A_MAXWIDTH-A_WIDTH}{Asign}}, A }),
211 .B({ {{`DSP_B_MAXWIDTH-B_WIDTH}{Bsign}}, B }),
212 .OUT({dummy, out})
213 );
214 if (Y_WIDTH < A_WIDTH+B_WIDTH)
215 assign Y = out[Y_WIDTH-1:0];
216 else begin
217 wire Ysign = (A_SIGNED || B_SIGNED ? out[A_WIDTH+B_WIDTH-1] : 1'b0);
218 assign Y = { {{Y_WIDTH-(A_WIDTH+B_WIDTH)}{Ysign}}, out[A_WIDTH+B_WIDTH-1:0] };
219 end
220 end
221 endgenerate
222 endmodule
223
224