Add "sim" command skeleton
[yosys.git] / passes / sat / sim.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 #include "kernel/celltypes.h"
23
24 USING_YOSYS_NAMESPACE
25 PRIVATE_NAMESPACE_BEGIN
26
27 struct SimInstance
28 {
29 Module *module;
30 Cell *instance;
31
32 SimInstance *parent;
33 dict<Cell*, SimInstance*> children;
34
35 SigMap sigmap;
36 dict<SigBit, State> state_nets;
37 dict<SigBit, pool<Cell*>> upd_cells;
38 dict<SigBit, pool<Wire*>> upd_outports;
39
40 pool<SigBit> dirty_bits;
41 dict<SigBit, State> next_state_nets;
42
43 dict<Wire*, int> vcd_netids;
44
45 SimInstance(Module *module, Cell *instance = nullptr, SimInstance *parent = nullptr) :
46 module(module), instance(instance), parent(parent), sigmap(module)
47 {
48 if (parent) {
49 log_assert(parent->children.count(instance) == 0);
50 parent->children[instance] = this;
51 }
52
53 for (auto wire : module->wires())
54 {
55 SigSpec sig = sigmap(wire);
56
57 for (int i = 0; i < GetSize(sig); i++) {
58 if (state_nets.count(sig[i]) == 0)
59 state_nets[sig[i]] = State::Sx;
60 if (wire->port_output) {
61 upd_outports[sig[i]].insert(wire);
62 dirty_bits.insert(sig[i]);
63 }
64 }
65
66 if (wire->attributes.count("\\init")) {
67 Const initval = wire->attributes.at("\\init");
68 for (int i = 0; i < GetSize(sig) && i < GetSize(initval); i++)
69 if (initval[i] == State::S0 || initval[i] == State::S1) {
70 state_nets[sig[i]] = initval[i];
71 dirty_bits.insert(sig[i]);
72 }
73 }
74 }
75
76 for (auto cell : module->cells())
77 {
78 Module *mod = module->design->module(cell->type);
79
80 if (mod != nullptr) {
81 new SimInstance(mod, cell, this);
82 }
83
84 for (auto &port : cell->connections()) {
85 if (cell->input(port.first))
86 for (auto bit : sigmap(port.second))
87 upd_cells[bit].insert(cell);
88 }
89 }
90 }
91
92 IdString name() const
93 {
94 if (instance != nullptr)
95 return instance->name;
96 return module->name;
97 }
98
99 std::string hiername() const
100 {
101 if (instance != nullptr)
102 return parent->hiername() + "." + log_id(instance->name);
103
104 return log_id(module->name);
105 }
106
107 Const get_state(SigSpec sig)
108 {
109 Const value;
110
111 for (auto bit : sigmap(sig))
112 if (state_nets.count(bit))
113 value.bits.push_back(state_nets.at(bit));
114 else
115 value.bits.push_back(State::Sz);
116
117 // log("[%s] get %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
118 return value;
119 }
120
121 void set_state(SigSpec sig, Const value)
122 {
123 sig = sigmap(sig);
124 log_assert(GetSize(sig) == GetSize(value));
125
126 for (int i = 0; i < GetSize(sig); i++)
127 if (state_nets.at(sig[i]) != value[i]) {
128 state_nets.at(sig[i]) = value[i];
129 dirty_bits.insert(sig[i]);
130 }
131
132 // log("[%s] set %s: %s\n", hiername().c_str(), log_signal(sig), log_signal(value));
133 }
134
135 void update_cell(Cell *cell)
136 {
137 if (children.count(cell))
138 {
139 auto child = children.at(cell);
140 for (auto &conn: cell->connections())
141 if (cell->input(conn.first)) {
142 Const value = get_state(conn.second);
143 child->set_state(child->module->wire(conn.first), value);
144 }
145 return;
146 }
147
148 if (yosys_celltypes.cell_evaluable(cell->type))
149 {
150 // log("[%s] eval %s (%s)\n", hiername().c_str(), log_id(cell), log_id(cell->type));
151
152 RTLIL::SigSpec sig_a, sig_b, sig_c, sig_d, sig_s, sig_y;
153 bool has_a, has_b, has_c, has_d, has_s, has_y;
154
155 has_a = cell->hasPort("\\A");
156 has_b = cell->hasPort("\\B");
157 has_c = cell->hasPort("\\C");
158 has_d = cell->hasPort("\\D");
159 has_s = cell->hasPort("\\S");
160 has_y = cell->hasPort("\\Y");
161
162 if (has_a) sig_a = cell->getPort("\\A");
163 if (has_b) sig_b = cell->getPort("\\B");
164 if (has_c) sig_c = cell->getPort("\\C");
165 if (has_d) sig_d = cell->getPort("\\D");
166 if (has_s) sig_s = cell->getPort("\\S");
167 if (has_y) sig_y = cell->getPort("\\Y");
168
169 // Simple (A -> Y) and (A,B -> Y) cells
170 if (has_a && !has_c && !has_d && !has_s && has_y) {
171 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b)));
172 return;
173 }
174
175 // (A,B,C -> Y) cells
176 if (has_a && has_b && has_c && !has_d && !has_s && has_y) {
177 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_c)));
178 return;
179 }
180
181 // (A,B,S -> Y) cells
182 if (has_a && has_b && !has_c && !has_d && has_s && has_y) {
183 set_state(sig_y, CellTypes::eval(cell, get_state(sig_a), get_state(sig_b), get_state(sig_s)));
184 return;
185 }
186
187 log_warning("Unsupported evaluable cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
188 return;
189 }
190
191 // FIXME
192
193 log_warning("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
194 }
195
196 void update()
197 {
198 while (1)
199 {
200 while (!dirty_bits.empty())
201 {
202 SigBit bit = *dirty_bits.begin();
203 dirty_bits.erase(bit);
204
205 if (upd_cells.count(bit))
206 {
207 for (auto cell : upd_cells.at(bit))
208 update_cell(cell);
209 }
210
211 if (upd_outports.count(bit) && parent != nullptr)
212 {
213 for (auto wire : upd_outports.at(bit))
214 if (instance->hasPort(wire->name)) {
215 Const value = get_state(wire);
216 parent->set_state(instance->getPort(wire->name), value);
217 }
218 }
219 }
220
221 for (auto child : children)
222 child.second->update();
223
224 if (dirty_bits.empty())
225 break;
226 }
227 }
228
229 void write_vcd_header(std::ofstream &f, int &id)
230 {
231 f << stringf("$scope module %s $end\n", log_id(name()));
232
233 for (auto wire : module->wires())
234 {
235 if (wire->name[0] == '$')
236 continue;
237
238 f << stringf("$var wire %d n%d %s $end\n", GetSize(wire), id, log_id(wire));
239 vcd_netids[wire] = id++;
240 }
241
242 for (auto child : children)
243 child.second->write_vcd_header(f, id);
244
245 f << stringf("$upscope $end\n");
246 }
247
248 void write_vcd_step(std::ofstream &f)
249 {
250 for (auto it : vcd_netids)
251 {
252 Wire *wire = it.first;
253 Const value = get_state(wire);
254 int id = it.second;
255
256 f << "b";
257 for (int i = GetSize(value)-1; i >= 0; i--) {
258 switch (value[i]) {
259 case State::S0: f << "0"; break;
260 case State::S1: f << "1"; break;
261 case State::Sx: f << "x"; break;
262 default: f << "z";
263 }
264 }
265
266 f << stringf(" n%d\n", id);
267 }
268
269 for (auto child : children)
270 child.second->write_vcd_step(f);
271 }
272 };
273
274 struct SimWorker
275 {
276 SimInstance *top = nullptr;
277 std::ofstream vcdfile;
278
279 void initialize(Module *topmod)
280 {
281 top = new SimInstance(topmod);
282 top->update();
283 }
284
285 void step()
286 {
287 // FIXME
288 }
289
290 void write_vcd_header()
291 {
292 if (!vcdfile.is_open())
293 return;
294
295 int id = 1;
296 top->write_vcd_header(vcdfile, id);
297
298 vcdfile << stringf("$enddefinitions $end\n");
299 }
300
301 void write_vcd_step(int n)
302 {
303 if (!vcdfile.is_open())
304 return;
305
306 vcdfile << stringf("#%d\n", 10*n);
307 top->write_vcd_step(vcdfile);
308 }
309 };
310
311 struct SimPass : public Pass {
312 SimPass() : Pass("sim", "simulate the circuit") { }
313 virtual void help()
314 {
315 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
316 log("\n");
317 log(" sim [options] [top-level]\n");
318 log("\n");
319 log("This command simulates the circuit using the given top-level module.\n");
320 log("\n");
321 log(" -vcd <filename>\n");
322 log(" write the simulation results to the given VCD file\n");
323 log("\n");
324 log(" -n <integer>\n");
325 log(" number of steps to simulate (default: 20)\n");
326 log("\n");
327 }
328 virtual void execute(std::vector<std::string> args, RTLIL::Design *design)
329 {
330 SimWorker worker;
331 int numsteps = 20;
332
333 log_header(design, "Executing SIM pass (simulate the circuit).\n");
334
335 size_t argidx;
336 for (argidx = 1; argidx < args.size(); argidx++) {
337 if (args[argidx] == "-vcd" && argidx+1 < args.size()) {
338 worker.vcdfile.open(args[++argidx].c_str());
339 continue;
340 }
341 if (args[argidx] == "-n" && argidx+1 < args.size()) {
342 numsteps = atoi(args[++argidx].c_str());
343 continue;
344 }
345 break;
346 }
347 extra_args(args, argidx, design);
348
349 Module *top_mod = nullptr;
350
351 if (design->full_selection()) {
352 top_mod = design->top_module();
353 } else {
354 auto mods = design->selected_whole_modules();
355 if (GetSize(mods) != 1)
356 log_cmd_error("Only one top module must be selected.\n");
357 top_mod = mods.front();
358 }
359
360 worker.initialize(top_mod);
361 worker.write_vcd_header();
362 worker.write_vcd_step(0);
363
364 for (int i = 1; i < numsteps; i++) {
365 worker.step();
366 worker.write_vcd_step(i);
367 }
368 }
369 } SimPass;
370
371 PRIVATE_NAMESPACE_END