Merge pull request #1379 from mmicko/sim_models
[yosys.git] / passes / pmgen / ice40_dsp.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 #include "passes/pmgen/ice40_dsp_pm.h"
27
28 void create_ice40_dsp(ice40_dsp_pm &pm)
29 {
30 auto &st = pm.st_ice40_dsp;
31
32 #if 0
33 log("\n");
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, "--"));
41 #endif
42
43 log("Checking %s.%s for iCE40 DSP inference.\n", log_id(pm.module), log_id(st.mul));
44
45 if (GetSize(st.sigA) > 16) {
46 log(" input A (%s) is too large (%d > 16).\n", log_signal(st.sigA), GetSize(st.sigA));
47 return;
48 }
49
50 if (GetSize(st.sigB) > 16) {
51 log(" input B (%s) is too large (%d > 16).\n", log_signal(st.sigB), GetSize(st.sigB));
52 return;
53 }
54
55 if (GetSize(st.sigS) > 32) {
56 log(" accumulator (%s) is too large (%d > 32).\n", log_signal(st.sigS), GetSize(st.sigS));
57 return;
58 }
59
60 if (GetSize(st.sigY) > 32) {
61 log(" output (%s) is too large (%d > 32).\n", log_signal(st.sigY), GetSize(st.sigY));
62 return;
63 }
64
65 bool mul_signed = st.mul->getParam("\\A_SIGNED").as_bool();
66
67 log(" replacing $mul with SB_MAC16 cell.\n");
68
69 Cell *cell = pm.module->addCell(NEW_ID, "\\SB_MAC16");
70 pm.module->swap_names(cell, st.mul);
71
72 // SB_MAC16 Input Interface
73
74 SigSpec A = st.sigA;
75 A.extend_u0(16, mul_signed);
76
77 SigSpec B = st.sigB;
78 B.extend_u0(16, mul_signed);
79
80 SigSpec CD;
81 if (st.muxA)
82 CD = st.muxA->getPort("\\B");
83 if (st.muxB)
84 CD = st.muxB->getPort("\\A");
85 CD.extend_u0(32, mul_signed);
86
87 cell->setPort("\\A", A);
88 cell->setPort("\\B", B);
89 cell->setPort("\\C", CD.extract(0, 16));
90 cell->setPort("\\D", CD.extract(16, 16));
91
92 cell->setParam("\\A_REG", st.ffA ? State::S1 : State::S0);
93 cell->setParam("\\B_REG", st.ffB ? State::S1 : State::S0);
94
95 cell->setPort("\\AHOLD", State::S0);
96 cell->setPort("\\BHOLD", State::S0);
97 cell->setPort("\\CHOLD", State::S0);
98 cell->setPort("\\DHOLD", State::S0);
99
100 cell->setPort("\\IRSTTOP", State::S0);
101 cell->setPort("\\IRSTBOT", State::S0);
102
103 if (st.clock_vld)
104 {
105 cell->setPort("\\CLK", st.clock);
106 cell->setPort("\\CE", State::S1);
107 cell->setParam("\\NEG_TRIGGER", st.clock_pol ? State::S0 : State::S1);
108
109 log(" clock: %s (%s)", log_signal(st.clock), st.clock_pol ? "posedge" : "negedge");
110
111 if (st.ffA)
112 log(" ffA:%s", log_id(st.ffA));
113
114 if (st.ffB)
115 log(" ffB:%s", log_id(st.ffB));
116
117 if (st.ffY)
118 log(" ffY:%s", log_id(st.ffY));
119
120 if (st.ffS)
121 log(" ffS:%s", log_id(st.ffS));
122
123 log("\n");
124 }
125 else
126 {
127 cell->setPort("\\CLK", State::S0);
128 cell->setPort("\\CE", State::S0);
129 cell->setParam("\\NEG_TRIGGER", State::S0);
130 }
131
132 // SB_MAC16 Cascade Interface
133
134 cell->setPort("\\SIGNEXTIN", State::Sx);
135 cell->setPort("\\SIGNEXTOUT", pm.module->addWire(NEW_ID));
136
137 cell->setPort("\\CI", State::Sx);
138 cell->setPort("\\CO", pm.module->addWire(NEW_ID));
139
140 cell->setPort("\\ACCUMCI", State::Sx);
141 cell->setPort("\\ACCUMCO", pm.module->addWire(NEW_ID));
142
143 // SB_MAC16 Output Interface
144
145 SigSpec O = st.ffS ? st.sigS : st.sigY;
146 if (GetSize(O) < 32)
147 O.append(pm.module->addWire(NEW_ID, 32-GetSize(O)));
148
149 cell->setPort("\\O", O);
150
151 if (st.addAB) {
152 log(" accumulator %s (%s)\n", log_id(st.addAB), log_id(st.addAB->type));
153 cell->setPort("\\ADDSUBTOP", st.addAB->type == "$add" ? State::S0 : State::S1);
154 cell->setPort("\\ADDSUBBOT", st.addAB->type == "$add" ? State::S0 : State::S1);
155 } else {
156 cell->setPort("\\ADDSUBTOP", State::S0);
157 cell->setPort("\\ADDSUBBOT", State::S0);
158 }
159
160 cell->setPort("\\ORSTTOP", State::S0);
161 cell->setPort("\\ORSTBOT", State::S0);
162
163 cell->setPort("\\OHOLDTOP", State::S0);
164 cell->setPort("\\OHOLDBOT", State::S0);
165
166 SigSpec acc_reset = State::S0;
167 if (st.muxA)
168 acc_reset = st.muxA->getPort("\\S");
169 if (st.muxB)
170 acc_reset = pm.module->Not(NEW_ID, st.muxB->getPort("\\S"));
171
172 cell->setPort("\\OLOADTOP", acc_reset);
173 cell->setPort("\\OLOADBOT", acc_reset);
174
175 // SB_MAC16 Remaining Parameters
176
177 cell->setParam("\\C_REG", State::S0);
178 cell->setParam("\\D_REG", State::S0);
179
180 cell->setParam("\\TOP_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
181 cell->setParam("\\BOT_8x8_MULT_REG", st.ffY ? State::S1 : State::S0);
182 cell->setParam("\\PIPELINE_16x16_MULT_REG1", st.ffY ? State::S1 : State::S0);
183 cell->setParam("\\PIPELINE_16x16_MULT_REG2", State::S0);
184
185 cell->setParam("\\TOPOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
186 cell->setParam("\\TOPADDSUB_LOWERINPUT", Const(2, 2));
187 cell->setParam("\\TOPADDSUB_UPPERINPUT", State::S0);
188 cell->setParam("\\TOPADDSUB_CARRYSELECT", Const(3, 2));
189
190 cell->setParam("\\BOTOUTPUT_SELECT", Const(st.ffS ? 1 : 3, 2));
191 cell->setParam("\\BOTADDSUB_LOWERINPUT", Const(2, 2));
192 cell->setParam("\\BOTADDSUB_UPPERINPUT", State::S0);
193 cell->setParam("\\BOTADDSUB_CARRYSELECT", Const(0, 2));
194
195 cell->setParam("\\MODE_8x8", State::S0);
196 cell->setParam("\\A_SIGNED", mul_signed ? State::S1 : State::S0);
197 cell->setParam("\\B_SIGNED", mul_signed ? State::S1 : State::S0);
198
199 pm.autoremove(st.mul);
200 pm.autoremove(st.ffY);
201 pm.autoremove(st.ffS);
202 }
203
204 struct Ice40DspPass : public Pass {
205 Ice40DspPass() : Pass("ice40_dsp", "iCE40: map multipliers") { }
206 void help() YS_OVERRIDE
207 {
208 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
209 log("\n");
210 log(" ice40_dsp [options] [selection]\n");
211 log("\n");
212 log("Map multipliers and multiply-accumulate blocks to iCE40 DSP resources.\n");
213 log("\n");
214 }
215 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
216 {
217 log_header(design, "Executing ICE40_DSP pass (map multipliers).\n");
218
219 size_t argidx;
220 for (argidx = 1; argidx < args.size(); argidx++)
221 {
222 // if (args[argidx] == "-singleton") {
223 // singleton_mode = true;
224 // continue;
225 // }
226 break;
227 }
228 extra_args(args, argidx, design);
229
230 for (auto module : design->selected_modules())
231 ice40_dsp_pm(module, module->selected_cells()).run_ice40_dsp(create_ice40_dsp);
232 }
233 } Ice40DspPass;
234
235 PRIVATE_NAMESPACE_END