2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
24 PRIVATE_NAMESPACE_BEGIN
26 #include "passes/pmgen/ice40_dsp_pm.h"
28 void create_ice40_dsp(ice40_dsp_pm
&pm
)
30 auto &st
= pm
.st_ice40_dsp
;
34 log("ffA: %s\n", log_id(st
.ffA
, "--"));
35 log("ffB: %s\n", log_id(st
.ffB
, "--"));
36 log("mul: %s\n", log_id(st
.mul
, "--"));
37 log("ffY: %s\n", log_id(st
.ffY
, "--"));
38 log("addAB: %s\n", log_id(st
.addAB
, "--"));
39 log("muxAB: %s\n", log_id(st
.muxAB
, "--"));
40 log("ffS: %s\n", log_id(st
.ffS
, "--"));
43 log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm
.module
), log_id(st
.mul
));
45 if (GetSize(st
.sigA
) > 16) {
46 log(" input A (%s) is too large (%d > 16).\n", log_signal(st
.sigA
), GetSize(st
.sigA
));
50 if (GetSize(st
.sigB
) > 16) {
51 log(" input B (%s) is too large (%d > 16).\n", log_signal(st
.sigB
), GetSize(st
.sigB
));
55 if (GetSize(st
.sigS
) > 32) {
56 log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st
.sigS
), GetSize(st
.sigS
));
60 if (GetSize(st
.sigY
) > 32) {
61 log(" output (%s) is too large (%d > 32).\n", log_signal(st
.sigY
), GetSize(st
.sigY
));
65 bool mul_signed
= st
.mul
->getParam("\\A_SIGNED").as_bool();
68 log(" inference of signed iCE40 DSP arithmetic is currently not supported.\n");
72 log(" replacing $mul with SB_MAC16 cell.\n");
74 Cell
*cell
= pm
.module
->addCell(NEW_ID
, "\\SB_MAC16");
75 pm
.module
->swap_names(cell
, st
.mul
);
77 // SB_MAC16 Input Interface
80 A
.extend_u0(16, mul_signed
);
83 B
.extend_u0(16, mul_signed
);
87 CD
= st
.muxA
->getPort("\\B");
89 CD
= st
.muxB
->getPort("\\A");
90 CD
.extend_u0(32, mul_signed
);
92 cell
->setPort("\\A", A
);
93 cell
->setPort("\\B", B
);
94 cell
->setPort("\\C", CD
.extract(0, 16));
95 cell
->setPort("\\D", CD
.extract(16, 16));
97 cell
->setParam("\\A_REG", st
.ffA
? State::S1
: State::S0
);
98 cell
->setParam("\\B_REG", st
.ffB
? State::S1
: State::S0
);
100 cell
->setPort("\\AHOLD", State::S0
);
101 cell
->setPort("\\BHOLD", State::S0
);
102 cell
->setPort("\\CHOLD", State::S0
);
103 cell
->setPort("\\DHOLD", State::S0
);
105 cell
->setPort("\\IRSTTOP", State::S0
);
106 cell
->setPort("\\IRSTBOT", State::S0
);
110 cell
->setPort("\\CLK", st
.clock
);
111 cell
->setPort("\\CE", State::S1
);
112 cell
->setParam("\\NEG_TRIGGER", st
.clock_pol
? State::S0
: State::S1
);
114 log(" clock: %s (%s)", log_signal(st
.clock
), st
.clock_pol
? "posedge" : "negedge");
117 log(" ffA:%s", log_id(st
.ffA
));
120 log(" ffB:%s", log_id(st
.ffB
));
123 log(" ffY:%s", log_id(st
.ffY
));
126 log(" ffS:%s", log_id(st
.ffS
));
132 cell
->setPort("\\CLK", State::S0
);
133 cell
->setPort("\\CE", State::S0
);
134 cell
->setParam("\\NEG_TRIGGER", State::S0
);
137 // SB_MAC16 Cascade Interface
139 cell
->setPort("\\SIGNEXTIN", State::Sx
);
140 cell
->setPort("\\SIGNEXTOUT", pm
.module
->addWire(NEW_ID
));
142 cell
->setPort("\\CI", State::Sx
);
143 cell
->setPort("\\CO", pm
.module
->addWire(NEW_ID
));
145 cell
->setPort("\\ACCUMCI", State::Sx
);
146 cell
->setPort("\\ACCUMCO", pm
.module
->addWire(NEW_ID
));
148 // SB_MAC16 Output Interface
150 SigSpec O
= st
.ffS
? st
.sigS
: st
.sigY
;
152 O
.append(pm
.module
->addWire(NEW_ID
, 32-GetSize(O
)));
154 cell
->setPort("\\O", O
);
157 log(" accumulator %s (%s)\n", log_id(st
.addAB
), log_id(st
.addAB
->type
));
158 cell
->setPort("\\ADDSUBTOP", st
.addAB
->type
== "$add" ? State::S0
: State::S1
);
159 cell
->setPort("\\ADDSUBBOT", st
.addAB
->type
== "$add" ? State::S0
: State::S1
);
161 cell
->setPort("\\ADDSUBTOP", State::S0
);
162 cell
->setPort("\\ADDSUBBOT", State::S0
);
165 cell
->setPort("\\ORSTTOP", State::S0
);
166 cell
->setPort("\\ORSTBOT", State::S0
);
168 cell
->setPort("\\OHOLDTOP", State::S0
);
169 cell
->setPort("\\OHOLDBOT", State::S0
);
171 SigSpec acc_reset
= State::S0
;
173 acc_reset
= st
.muxA
->getPort("\\S");
175 acc_reset
= pm
.module
->Not(NEW_ID
, st
.muxB
->getPort("\\S"));
177 cell
->setPort("\\OLOADTOP", acc_reset
);
178 cell
->setPort("\\OLOADBOT", acc_reset
);
180 // SB_MAC16 Remaining Parameters
182 cell
->setParam("\\C_REG", State::S0
);
183 cell
->setParam("\\D_REG", State::S0
);
185 cell
->setParam("\\TOP_8x8_MULT_REG", st
.ffY
? State::S1
: State::S0
);
186 cell
->setParam("\\BOT_8x8_MULT_REG", st
.ffY
? State::S1
: State::S0
);
187 cell
->setParam("\\PIPELINE_16x16_MULT_REG1", st
.ffY
? State::S1
: State::S0
);
188 cell
->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0
);
190 cell
->setParam("\\TOPOUTPUT_SELECT", Const(st
.ffS
? 1 : 3, 2));
191 cell
->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
192 cell
->setParam("\\TOPADDSUB_UPPERINPUT", State::S0
);
193 cell
->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
195 cell
->setParam("\\BOTOUTPUT_SELECT", Const(st
.ffS
? 1 : 3, 2));
196 cell
->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
197 cell
->setParam("\\BOTADDSUB_UPPERINPUT", State::S0
);
198 cell
->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
200 cell
->setParam("\\MODE_8x8", State::S0
);
201 cell
->setParam("\\A_SIGNED", mul_signed
? State::S1
: State::S0
);
202 cell
->setParam("\\B_SIGNED", mul_signed
? State::S1
: State::S0
);
204 pm
.autoremove(st
.mul
);
205 pm
.autoremove(st
.ffY
);
206 pm
.autoremove(st
.ffS
);
209 struct Ice40DspPass
: public Pass
{
210 Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { }
211 void help() YS_OVERRIDE
213 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
215 log(" ice40_dsp [options] [selection]\n");
217 log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n");
220 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
222 log_header(design
, "Executing ICE40_DSP pass (map multipliers).\n");
225 for (argidx
= 1; argidx
< args
.size(); argidx
++)
227 // if (args[argidx] == "-singleton") {
228 // singleton_mode = true;
233 extra_args(args
, argidx
, design
);
235 for (auto module
: design
->selected_modules())
236 ice40_dsp_pm(module
, module
->selected_cells()).run_ice40_dsp(create_ice40_dsp
);
240 PRIVATE_NAMESPACE_END