1 /*
2 * Copyright (c) 2002-2020 Stephen Williams (steve@icarus.com)
3 *
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 # include "config.h"
21
22 # include "functor.h"
23 # include "netlist.h"
24 # include "netvector.h"
25 # include "netmisc.h"
26 # include "compiler.h"
27 # include "ivl_assert.h"
28
29 using namespace std;
30
31 /* General notes on enables and bitmasks.
32 *
33 * When synthesising an asynchronous process that contains conditional
34 * statements (if/case statements), we need to determine the conditions
35 * that cause each nexus driven by that process to be updated. If a
36 * nexus is not updated under all circumstances, we must infer a latch.
37 * To this end, we generate an enable signal for each output nexus. As
38 * we walk the statement tree for the process, for each substatement we
39 * pass the enable signals generated so far into the synth_async method,
40 * and on return from the synth_async method, the enable signals will be
41 * updated to reflect any conditions introduced by that substatement.
42 * Once we have synthesised all the statements for that process, if an
43 * enable signal is not tied high, we must infer a latch for that nexus.
44 *
45 * When synthesising a synchronous process, we use the synth_async method
46 * to synthesise the combinatorial inputs to the D pins of the flip-flops
47 * we infer for that process. In this case the enable signal can be used
48 * as a clock enable for the flip-flop. This saves us explicitly feeding
49 * back the flip-flop output to undriven inputs of any synthesised muxes.
50 *
51 * The strategy described above is not sufficient when not all bits in
52 * a nexus are treated identically (i.e. different conditional clauses
53 * drive differing parts of the same vector). To handle this properly,
54 * we would (potentially) need to generate a separate enable signal for
55 * each bit in the vector. This would be a lot of work, particularly if
56 * we wanted to eliminate duplicates. For now, the strategy employed is
57 * to maintain a bitmask for each output nexus that identifies which bits
58 * in the nexus are unconditionally driven (driven by every clause). When
59 * we finish synthesising an asynchronous process, if the bitmask is not
60 * all ones, we must infer a latch. This currently results in an error,
61 * because to safely synthesise such a latch we would need the bit-level
62 * gate enables. When we finish synthesising a synchronous process, if
63 * the bitmask is not all ones, we explicitly feed the flip-flop outputs
64 * back to undriven inputs of any synthesised muxes to ensure undriven
65 * parts of the vector retain their previous state when the flip-flop is
66 * clocked.
67 *
68 * The enable signals are passed as links to the current output nexus
69 * for each signal. If an enable signal is not linked, this is treated
70 * as if the signal was tied low.
71 *
72 * The bitmasks are passed as bool vectors. 'true' indicates a bit is
73 * unconditionally driven. An empty vector (size = 0) indicates that
74 * the current substatement doesn't drive any bits in the nexus.
75 */
76
qualify_enable(Design * des,NetScope * scope,NetNet * qualifier,bool active_state,NetLogic::TYPE gate_type,Link & enable_i,Link & enable_o)77 static void qualify_enable(Design*des, NetScope*scope, NetNet*qualifier,
78 bool active_state, NetLogic::TYPE gate_type,
79 Link&enable_i, Link&enable_o)
80 {
81 if (enable_i.is_linked(scope->tie_lo())) {
82 connect(enable_o, scope->tie_lo());
83 return;
84 }
85
86 if (active_state == false) {
87 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
88 2, NetLogic::NOT, 1);
89 des->add_node(gate);
90 connect(gate->pin(1), qualifier->pin(0));
91
92 NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
93 &netvector_t::scalar_logic);
94 sig->local_flag(true);
95 connect(sig->pin(0), gate->pin(0));
96
97 qualifier = sig;
98 }
99
100 if (enable_i.is_linked(scope->tie_hi())) {
101 connect(enable_o, qualifier->pin(0));
102 return;
103 }
104
105 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
106 3, gate_type, 1);
107 des->add_node(gate);
108 connect(gate->pin(1), qualifier->pin(0));
109 connect(gate->pin(2), enable_i);
110 connect(enable_o, gate->pin(0));
111
112 NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
113 &netvector_t::scalar_logic);
114 sig->local_flag(true);
115 connect(sig->pin(0), gate->pin(0));
116 }
117
multiplex_enables(Design * des,NetScope * scope,NetNet * select,Link & enable_1,Link & enable_0,Link & enable_o)118 static void multiplex_enables(Design*des, NetScope*scope, NetNet*select,
119 Link&enable_1, Link&enable_0, Link&enable_o)
120 {
121 if (!enable_1.is_linked() &&
122 !enable_0.is_linked() )
123 return;
124
125 if ( enable_1.is_linked(scope->tie_hi()) &&
126 enable_0.is_linked(scope->tie_hi()) ) {
127 connect(enable_o, scope->tie_hi());
128 return;
129 }
130
131 if (enable_1.is_linked(scope->tie_lo()) || !enable_1.is_linked()) {
132 qualify_enable(des, scope, select, false, NetLogic::AND,
133 enable_0, enable_o);
134 return;
135 }
136 if (enable_0.is_linked(scope->tie_lo()) || !enable_0.is_linked()) {
137 qualify_enable(des, scope, select, true, NetLogic::AND,
138 enable_1, enable_o);
139 return;
140 }
141 if (enable_1.is_linked(scope->tie_hi())) {
142 qualify_enable(des, scope, select, true, NetLogic::OR,
143 enable_0, enable_o);
144 return;
145 }
146 if (enable_0.is_linked(scope->tie_hi())) {
147 qualify_enable(des, scope, select, false, NetLogic::OR,
148 enable_1, enable_o);
149 return;
150 }
151
152 NetMux*mux = new NetMux(scope, scope->local_symbol(), 1, 2, 1);
153 des->add_node(mux);
154 connect(mux->pin_Sel(), select->pin(0));
155 connect(mux->pin_Data(1), enable_1);
156 connect(mux->pin_Data(0), enable_0);
157 connect(enable_o, mux->pin_Result());
158
159 NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
160 &netvector_t::scalar_logic);
161 sig->local_flag(true);
162 connect(sig->pin(0), mux->pin_Result());
163 }
164
merge_sequential_enables(Design * des,NetScope * scope,Link & top_enable,Link & sub_enable)165 static void merge_sequential_enables(Design*des, NetScope*scope,
166 Link&top_enable, Link&sub_enable)
167 {
168 if (!sub_enable.is_linked())
169 return;
170
171 if (top_enable.is_linked(scope->tie_hi()))
172 return;
173
174 if (sub_enable.is_linked(scope->tie_hi()))
175 top_enable.unlink();
176
177 if (top_enable.is_linked()) {
178 NetLogic*gate = new NetLogic(scope, scope->local_symbol(),
179 3, NetLogic::OR, 1);
180 des->add_node(gate);
181 connect(gate->pin(1), sub_enable);
182 connect(gate->pin(2), top_enable);
183 top_enable.unlink();
184 connect(top_enable, gate->pin(0));
185
186 NetNet*sig = new NetNet(scope, scope->local_symbol(), NetNet::WIRE,
187 &netvector_t::scalar_logic);
188 sig->local_flag(true);
189 connect(sig->pin(0), gate->pin(0));
190 } else {
191 connect(top_enable, sub_enable);
192 }
193 }
194
merge_sequential_masks(NetProc::mask_t & top_mask,NetProc::mask_t & sub_mask)195 static void merge_sequential_masks(NetProc::mask_t&top_mask, NetProc::mask_t&sub_mask)
196 {
197 if (sub_mask.size() == 0)
198 return;
199
200 if (top_mask.size() == 0) {
201 top_mask = sub_mask;
202 return;
203 }
204
205 assert(top_mask.size() == sub_mask.size());
206 for (unsigned idx = 0 ; idx < top_mask.size() ; idx += 1) {
207 if (sub_mask[idx] == true)
208 top_mask[idx] = true;
209 }
210 }
211
merge_parallel_masks(NetProc::mask_t & top_mask,NetProc::mask_t & sub_mask)212 static void merge_parallel_masks(NetProc::mask_t&top_mask, NetProc::mask_t&sub_mask)
213 {
214 if (sub_mask.size() == 0)
215 return;
216
217 if (top_mask.size() == 0) {
218 top_mask = sub_mask;
219 return;
220 }
221
222 assert(top_mask.size() == sub_mask.size());
223 for (unsigned idx = 0 ; idx < top_mask.size() ; idx += 1) {
224 if (sub_mask[idx] == false)
225 top_mask[idx] = false;
226 }
227 }
228
all_bits_driven(NetProc::mask_t & mask)229 static bool all_bits_driven(NetProc::mask_t&mask)
230 {
231 if (mask.size() == 0)
232 return false;
233
234 for (unsigned idx = 0 ; idx < mask.size() ; idx += 1) {
235 if (mask[idx] == false)
236 return false;
237 }
238 return true;
239 }
240
tie_off_floating_inputs_(Design * des,NexusSet & nex_map,NetBus & nex_in,vector<NetProc::mask_t> & bitmasks,bool is_ff_input)241 bool NetProcTop::tie_off_floating_inputs_(Design*des,
242 NexusSet&nex_map, NetBus&nex_in,
243 vector<NetProc::mask_t>&bitmasks,
244 bool is_ff_input)
245 {
246 bool flag = true;
247 for (unsigned idx = 0 ; idx < nex_in.pin_count() ; idx += 1) {
248 if (nex_in.pin(idx).nexus()->has_floating_input()) {
249 if (all_bits_driven(bitmasks[idx])) {
250 // If all bits are unconditionally driven, we can
251 // use the enable signal to prevent the flip-flop/
252 // latch from updating when an undriven mux input
253 // is selected, so we can just tie off the input.
254 unsigned width = nex_map[idx].wid;
255 NetLogic*gate = new NetLogic(scope(), scope()->local_symbol(),
256 1, NetLogic::PULLDOWN, width);
257 des->add_node(gate);
258 connect(nex_in.pin(idx), gate->pin(0));
259
260 if (nex_in.pin(idx).nexus()->pick_any_net())
261 continue;
262
263 ivl_variable_type_t data_type = IVL_VT_LOGIC;
264 netvector_t*tmp_vec = new netvector_t(data_type, width-1,0);
265 NetNet*sig = new NetNet(scope(), scope()->local_symbol(),
266 NetNet::WIRE, tmp_vec);
267 sig->local_flag(true);
268 connect(sig->pin(0), gate->pin(0));
269 } else if (is_ff_input) {
270 // For a flip-flop, we can feed back the output
271 // to ensure undriven bits hold their last value.
272 connect(nex_in.pin(idx), nex_map[idx].lnk);
273 } else {
274 // This infers a latch, but without generating
275 // gate enable signals at the bit-level, we
276 // can't safely latch the undriven bits (we
277 // shouldn't generate combinatorial loops).
278 cerr << get_fileline() << ": warning: A latch "
279 << "has been inferred for some bits of '"
280 << nex_map[idx].lnk.nexus()->pick_any_net()->name()
281 << "'." << endl;
282
283 cerr << get_fileline() << ": sorry: Bit-level "
284 "latch gate enables are not currently "
285 "supported in synthesis." << endl;
286 des->errors += 1;
287 flag = false;
288 }
289 }
290 }
291 return flag;
292 }
293
synth_async(Design *,NetScope *,NexusSet &,NetBus &,NetBus &,vector<mask_t> &)294 bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&, vector<mask_t>&)
295 {
296 return false;
297 }
298
299 /*
300 * Async synthesis of assignments is done by synthesizing the rvalue
301 * expression, then connecting the l-value directly to the output of
302 * the r-value.
303 *
304 * The nex_map is the O-set for the statement, and lists the positions
305 * of the outputs as the caller wants results linked up. The nex_out,
306 * however, is the set of nexa that are to actually get linked to the
307 * r-value.
308 */
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)309 bool NetAssignBase::synth_async(Design*des, NetScope*scope,
310 NexusSet&nex_map, NetBus&nex_out,
311 NetBus&enables, vector<mask_t>&bitmasks)
312 {
313 if (dynamic_cast<NetCAssign*>(this) || dynamic_cast<NetDeassign*>(this) ||
314 dynamic_cast<NetForce*>(this) || dynamic_cast<NetRelease*>(this)) {
315 cerr << get_fileline() << ": sorry: Procedural continuous "
316 "assignment is not currently supported in synthesis."
317 << endl;
318 des->errors += 1;
319 return false;
320 }
321
322 /* If the lval is a concatenation, synthesise each part
323 separately. */
324 if (lval_->more ) {
325 /* Temporarily set the lval_ and rval_ fields for each
326 part in turn and recurse. Restore them when done. */
327 NetAssign_*full_lval = lval_;
328 NetExpr*full_rval = rval_;
329 unsigned offset = 0;
330 bool flag = true;
331 while (lval_) {
332 unsigned width = lval_->lwidth();
333 NetEConst*base = new NetEConst(verinum(offset));
334 base->set_line(*this);
335 rval_ = new NetESelect(full_rval->dup_expr(), base, width);
336 rval_->set_line(*this);
337 eval_expr(rval_, width);
338 NetAssign_*more = lval_->more;
339 lval_->more = 0;
340 if (!synth_async(des, scope, nex_map, nex_out, enables, bitmasks))
341 flag = false;
342 lval_ = lval_->more = more;
343 offset += width;
344 }
345 lval_ = full_lval;
346 rval_ = full_rval;
347 return flag;
348 }
349
350 assert(rval_);
351 NetNet*rsig = rval_->synthesize(des, scope, rval_);
352 assert(rsig);
353
354 if (lval_->word() && ! dynamic_cast<NetEConst*>(lval_->word())) {
355 cerr << get_fileline() << ": sorry: Assignment to variable "
356 "location in memory is not currently supported in "
357 "synthesis." << endl;
358 des->errors += 1;
359 return false;
360 }
361
362 NetNet*lsig = lval_->sig();
363 if (!lsig) {
364 cerr << get_fileline() << ": error: "
365 "NetAssignBase::synth_async on unsupported lval ";
366 dump_lval(cerr);
367 cerr << endl;
368 des->errors += 1;
369 return false;
370 }
371
372 if (debug_synth2) {
373 cerr << get_fileline() << ": NetAssignBase::synth_async: "
374 << "l-value signal is " << lsig->vector_width() << " bits, "
375 << "r-value signal is " << rsig->vector_width() << " bits." << endl;
376 cerr << get_fileline() << ": NetAssignBase::synth_async: "
377 << "lval_->lwidth()=" << lval_->lwidth() << endl;
378 cerr << get_fileline() << ": NetAssignBase::synth_async: "
379 << "lsig = " << scope_path(scope) << "." << lsig->name() << endl;
380 if (const NetExpr*base = lval_->get_base()) {
381 cerr << get_fileline() << ": NetAssignBase::synth_async: "
382 << "base_=" << *base << endl;
383 }
384 cerr << get_fileline() << ": NetAssignBase::synth_async: "
385 << "nex_map.size()==" << nex_map.size()
386 << ", nex_out.pin_count()==" << nex_out.pin_count() << endl;
387 }
388
389 unsigned ptr = 0;
390 if (nex_out.pin_count() > 1) {
391 NexusSet tmp_set;
392 nex_output(tmp_set);
393 ivl_assert(*this, tmp_set.size() == 1);
394 ptr = nex_map.find_nexus(tmp_set[0]);
395 ivl_assert(*this, nex_out.pin_count() > ptr);
396 ivl_assert(*this, enables.pin_count() > ptr);
397 ivl_assert(*this, bitmasks.size() > ptr);
398 } else {
399 ivl_assert(*this, nex_out.pin_count() == 1);
400 ivl_assert(*this, enables.pin_count() == 1);
401 ivl_assert(*this, bitmasks.size() == 1);
402 }
403
404 unsigned lval_width = lval_->lwidth();
405 unsigned lsig_width = lsig->vector_width();
406 ivl_assert(*this, nex_map[ptr].wid == lsig_width);
407
408 // Here we note if the l-value is actually a bit/part
409 // select. If so, generate a NetPartSelect to perform the select.
410 bool is_part_select = lval_width != lsig_width;
411
412 long base_off = 0;
413 if (is_part_select && !scope->loop_index_tmp.empty()) {
414 // If we are within a NetForLoop, there may be an index
415 // value. That is collected from the scope member
416 // loop_index_tmp, and the evaluate_function method
417 // knows how to apply it.
418 ivl_assert(*this, !scope->loop_index_tmp.empty());
419 ivl_assert(*this, lval_width < lsig_width);
420
421 // Evaluate the index expression to a constant.
422 const NetExpr*base_expr_raw = lval_->get_base();
423 ivl_assert(*this, base_expr_raw);
424 NetExpr*base_expr = base_expr_raw->evaluate_function(*this, scope->loop_index_tmp);
425 if (! eval_as_long(base_off, base_expr)) {
426 ivl_assert(*this, 0);
427 }
428 ivl_assert(*this, base_off >= 0);
429
430 ivl_variable_type_t tmp_data_type = rsig->data_type();
431 netvector_t*tmp_type = new netvector_t(tmp_data_type, lsig_width-1,0);
432
433 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
434 NetNet::WIRE, NetNet::not_an_array, tmp_type);
435 tmp->local_flag(true);
436 tmp->set_line(*this);
437
438 NetPartSelect*ps = new NetPartSelect(tmp, base_off, lval_width, NetPartSelect::PV);
439 ps->set_line(*this);
440 des->add_node(ps);
441
442 connect(ps->pin(0), rsig->pin(0));
443 rsig = tmp;
444
445 } else if (is_part_select) {
446 // In this case, there is no loop_index_tmp, so we are
447 // not within a NetForLoop. Generate a NetSubstitute
448 // object to handle the bit/part-select in the l-value.
449 ivl_assert(*this, scope->loop_index_tmp.empty());
450 ivl_assert(*this, lval_width < lsig_width);
451
452 const NetExpr*base_expr_raw = lval_->get_base();
453 ivl_assert(*this, base_expr_raw);
454 NetExpr*base_expr = base_expr_raw->evaluate_function(*this, scope->loop_index_tmp);
455 if (! eval_as_long(base_off, base_expr)) {
456 cerr << get_fileline() << ": sorry: assignment to variable "
457 "bit location is not currently supported in "
458 "synthesis." << endl;
459 des->errors += 1;
460 return false;
461 }
462 ivl_assert(*this, base_off >= 0);
463
464 ivl_variable_type_t tmp_data_type = rsig->data_type();
465 netvector_t*tmp_type = new netvector_t(tmp_data_type, lsig_width-1,0);
466
467 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
468 NetNet::WIRE, NetNet::not_an_array, tmp_type);
469 tmp->local_flag(true);
470 tmp->set_line(*this);
471
472 NetNet*isig = nex_out.pin(ptr).nexus()->pick_any_net();
473 if (isig) {
474 if (debug_synth2) {
475 cerr << get_fileline() << ": NetAssignBase::synth_async: "
476 << " Found an isig:" << endl;
477 nex_out.pin(ptr).dump_link(cerr, 8);
478 }
479 } else {
480 if (debug_synth2) {
481 cerr << get_fileline() << ": NetAssignBase::synth_async: "
482 << " Found no isig, resorting to lsig." << endl;
483 }
484 isig = new NetNet(scope, scope->local_symbol(),
485 NetNet::WIRE, NetNet::not_an_array, tmp_type);
486 isig->local_flag(true);
487 isig->set_line(*this);
488 connect(isig->pin(0), nex_out.pin(ptr));
489 }
490 ivl_assert(*this, isig);
491 NetSubstitute*ps = new NetSubstitute(isig, rsig, lsig_width, base_off);
492 ps->set_line(*this);
493 des->add_node(ps);
494
495 connect(ps->pin(0), tmp->pin(0));
496 rsig = tmp;
497 }
498
499 rsig = crop_to_width(des, rsig, lsig_width);
500
501 ivl_assert(*this, rsig->pin_count()==1);
502 nex_out.pin(ptr).unlink();
503 enables.pin(ptr).unlink();
504 connect(nex_out.pin(ptr), rsig->pin(0));
505 connect(enables.pin(ptr), scope->tie_hi());
506
507 mask_t&bitmask = bitmasks[ptr];
508 if (is_part_select) {
509 if (bitmask.size() == 0) {
510 bitmask = mask_t (lsig_width, false);
511 }
512 ivl_assert(*this, bitmask.size() == lsig_width);
513 for (unsigned idx = 0; idx < lval_width; idx += 1) {
514 bitmask[base_off + idx] = true;
515 }
516 } else if (bitmask.size() > 0) {
517 for (unsigned idx = 0; idx < bitmask.size(); idx += 1) {
518 bitmask[idx] = true;
519 }
520 } else {
521 bitmask = mask_t (lsig_width, true);
522 }
523
524 /* This lval_ represents a reg that is a WIRE in the
525 synthesized results. This function signals the destructor
526 to change the REG that this l-value refers to into a
527 WIRE. It is done then, at the last minute, so that pending
528 synthesis can continue to work with it as a REG. */
529 lval_->turn_sig_to_wire_on_release();
530
531 return true;
532 }
533
synth_async_block_substatement_(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks,NetProc * substmt)534 bool NetProc::synth_async_block_substatement_(Design*des, NetScope*scope,
535 NexusSet&nex_map,
536 NetBus&nex_out,
537 NetBus&enables,
538 vector<mask_t>&bitmasks,
539 NetProc*substmt)
540 {
541 ivl_assert(*this, nex_map.size() == nex_out.pin_count());
542 ivl_assert(*this, nex_map.size() == enables.pin_count());
543 ivl_assert(*this, nex_map.size() == bitmasks.size());
544
545 // Create a temporary map of the output only from this statement.
546 NexusSet tmp_map;
547 substmt->nex_output(tmp_map);
548 if (debug_synth2) {
549 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: "
550 << "tmp_map.size()==" << tmp_map.size()
551 << " for statement at " << substmt->get_fileline()
552 << endl;
553 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
554 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: "
555 << "incoming nex_out[" << idx << "] dump link" << endl;
556 nex_out.pin(idx).dump_link(cerr, 8);
557 }
558 }
559
560 // Create temporary variables to collect the output from the synthesis.
561 NetBus tmp_out (scope, tmp_map.size());
562 NetBus tmp_ena (scope, tmp_map.size());
563 vector<mask_t> tmp_masks (tmp_map.size());
564
565 // Map (and move) the accumulated nex_out for this block
566 // to the version that we can pass to the next statement.
567 // We will move the result back later.
568 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
569 unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
570 ivl_assert(*this, ptr < nex_out.pin_count());
571 connect(tmp_out.pin(idx), nex_out.pin(ptr));
572 nex_out.pin(ptr).unlink();
573 }
574
575 if (debug_synth2) {
576 for (unsigned idx = 0 ; idx < nex_map.size() ; idx += 1) {
577 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: nex_map[" << idx << "] dump link, base=" << nex_map[idx].base << ", wid=" << nex_map[idx].wid << endl;
578 nex_map[idx].lnk.dump_link(cerr, 8);
579 }
580 for (unsigned idx = 0 ; idx < tmp_map.size() ; idx += 1) {
581 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: tmp_map[" << idx << "] dump link, base=" << tmp_map[idx].base << ", wid=" << tmp_map[idx].wid << endl;
582 tmp_map[idx].lnk.dump_link(cerr, 8);
583 }
584 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
585 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: tmp_out[" << idx << "] dump link" << endl;
586 tmp_out.pin(idx).dump_link(cerr, 8);
587 }
588 }
589
590
591 bool flag = substmt->synth_async(des, scope, tmp_map, tmp_out, tmp_ena, tmp_masks);
592
593 if (debug_synth2) {
594 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: "
595 "substmt->synch_async(...) --> " << (flag? "true" : "false")
596 << " for statement at " << substmt->get_fileline() << "." << endl;
597 }
598
599 if (!flag) return false;
600
601 // Now map the output from the substatement back to the
602 // outputs for this block.
603 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
604 unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
605 ivl_assert(*this, ptr < nex_out.pin_count());
606 if (debug_synth2) {
607 cerr << get_fileline() << ": NetProc::synth_async_block_substatement_: "
608 << "tmp_out.pin(" << idx << "):" << endl;
609 tmp_out.pin(idx).dump_link(cerr, 8);
610 }
611 connect(nex_out.pin(ptr), tmp_out.pin(idx));
612
613 merge_sequential_enables(des, scope, enables.pin(ptr), tmp_ena.pin(idx));
614
615 merge_sequential_masks(bitmasks[ptr], tmp_masks[idx]);
616 }
617
618 return true;
619 }
620
621 /*
622 * Sequential blocks are translated to asynchronous logic by
623 * translating each statement of the block, in order, into gates.
624 * The nex_out for the block is the union of the nex_out for all
625 * the substatements.
626 */
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)627 bool NetBlock::synth_async(Design*des, NetScope*scope,
628 NexusSet&nex_map, NetBus&nex_out,
629 NetBus&enables, vector<mask_t>&bitmasks)
630 {
631 if (last_ == 0) {
632 return true;
633 }
634
635 bool flag = true;
636 NetProc*cur = last_;
637 do {
638 cur = cur->next_;
639
640 bool sub_flag = synth_async_block_substatement_(des, scope, nex_map, nex_out,
641 enables, bitmasks, cur);
642 flag = flag && sub_flag;
643
644 } while (cur != last_);
645
646 return flag;
647 }
648
649 /*
650 * This function is used to fix up a MUX selector to be no longer than
651 * it needs to be. The general idea is that if the selector needs to
652 * be only N bits, but is actually M bits, we translate it to this:
653 *
654 * osig = { |esig[M-1:N-1], esig[N-2:0] }
655 *
656 * This obviously implies that (N >= 2) and (M >= N). In the code
657 * below, N is sel_need, and M is sel_got (= esig->vector_width()).
658 */
mux_selector_reduce_width(Design * des,NetScope * scope,const LineInfo & loc,NetNet * esig,unsigned sel_need)659 static NetNet* mux_selector_reduce_width(Design*des, NetScope*scope,
660 const LineInfo&loc,
661 NetNet*esig, unsigned sel_need)
662 {
663 const unsigned sel_got = esig->vector_width();
664
665 ivl_assert(*esig, sel_got >= sel_need);
666
667 // If the actual width matches the desired width (M==N) then
668 // osig is esig itself. We're done.
669 if (sel_got == sel_need)
670 return esig;
671
672 if (debug_synth2) {
673 cerr << loc.get_fileline() << ": mux_selector_reduce_width: "
674 << "Reduce selector width=" << sel_got
675 << " to " << sel_need << " bits." << endl;
676 }
677
678 ivl_assert(*esig, sel_need >= 2);
679
680 // This is the output signal, osig.
681 ivl_variable_type_t osig_data_type = IVL_VT_LOGIC;
682 netvector_t*osig_vec = new netvector_t(osig_data_type, sel_need-1, 0);
683 NetNet*osig = new NetNet(scope, scope->local_symbol(),
684 NetNet::TRI, osig_vec);
685 osig->local_flag(true);
686 osig->set_line(loc);
687
688 // Create the concat: osig = {...,...}
689 NetConcat*osig_cat = new NetConcat(scope, scope->local_symbol(),
690 sel_need, 2, !disable_concatz_generation);
691 osig_cat->set_line(loc);
692 des->add_node(osig_cat);
693 connect(osig_cat->pin(0), osig->pin(0));
694
695 // Create the part select esig[N-2:0]...
696 NetPartSelect*ps0 = new NetPartSelect(esig, 0, sel_need-1,
697 NetPartSelect::VP);
698 ps0->set_line(loc);
699 des->add_node(ps0);
700 connect(ps0->pin(1), esig->pin(0));
701
702 netvector_t*ps0_vec = new netvector_t(osig_data_type, sel_need-2, 0);
703 NetNet*ps0_sig = new NetNet(scope, scope->local_symbol(),
704 NetNet::TRI, ps0_vec);
705 ps0_sig->local_flag(true);
706 ps0_sig->set_line(loc);
707 connect(ps0_sig->pin(0), ps0->pin(0));
708
709 // osig = {..., esig[N-2:0]}
710 connect(osig_cat->pin(1), ps0_sig->pin(0));
711
712 // Create the part select esig[M-1:N-1]
713 NetPartSelect*ps1 = new NetPartSelect(esig, sel_need-1,
714 sel_got-sel_need+1,
715 NetPartSelect::VP);
716 ps1->set_line(loc);
717 des->add_node(ps1);
718 connect(ps1->pin(1), esig->pin(0));
719
720 netvector_t*ps1_vec = new netvector_t(osig_data_type, sel_got-sel_need, 0);
721 NetNet*ps1_sig = new NetNet(scope, scope->local_symbol(),
722 NetNet::TRI, ps1_vec);
723 ps1_sig->local_flag(true);
724 ps1_sig->set_line(loc);
725 connect(ps1_sig->pin(0), ps1->pin(0));
726
727 // Create the reduction OR: | esig[M-1:N-1]
728 NetUReduce*ered = new NetUReduce(scope, scope->local_symbol(),
729 NetUReduce::OR, sel_got-sel_need+1);
730 ered->set_line(loc);
731 des->add_node(ered);
732 connect(ered->pin(1), ps1_sig->pin(0));
733
734 NetNet*ered_sig = new NetNet(scope, scope->local_symbol(),
735 NetNet::TRI, &netvector_t::scalar_logic);
736 ered_sig->local_flag(true);
737 ered_sig->set_line(loc);
738 connect(ered->pin(0), ered_sig->pin(0));
739
740 // osig = { |esig[M-1:N-1], esig[N-2:0] }
741 connect(osig_cat->pin(2), ered_sig->pin(0));
742
743 return osig;
744 }
745
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)746 bool NetCase::synth_async(Design*des, NetScope*scope,
747 NexusSet&nex_map, NetBus&nex_out,
748 NetBus&enables, vector<mask_t>&bitmasks)
749 {
750 if (type()==NetCase::EQZ || type()==NetCase::EQX)
751 return synth_async_casez_(des, scope, nex_map, nex_out,
752 enables, bitmasks);
753
754 // Special case: If the case expression is constant, then this
755 // is a pattern where the guards are non-constant and tested
756 // against a constant case. Handle this as chained conditions
757 // instead.
758 if (dynamic_cast<NetEConst*> (expr_))
759 return synth_async_casez_(des, scope, nex_map, nex_out,
760 enables, bitmasks);
761
762 ivl_assert(*this, nex_map.size() == nex_out.pin_count());
763 ivl_assert(*this, nex_map.size() == enables.pin_count());
764 ivl_assert(*this, nex_map.size() == bitmasks.size());
765
766 if (debug_synth2) {
767 cerr << get_fileline() << ": NetCase::synth_async: "
768 << "Selector expression: " << *expr_ << endl;
769 }
770
771 /* Synthesize the select expression. */
772 NetNet*esig = expr_->synthesize(des, scope, expr_);
773
774 unsigned sel_width = esig->vector_width();
775 ivl_assert(*this, sel_width > 0);
776
777 if (debug_synth2) {
778 cerr << get_fileline() << ": NetCase::synth_async: "
779 << "selector width (sel_width) = " << sel_width << endl;
780 }
781
782 vector<unsigned> mux_width (nex_out.pin_count());
783 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
784 mux_width[idx] = nex_map[idx].wid;
785 if (debug_synth2) {
786 cerr << get_fileline() << ": NetCase::synth_async: "
787 << "idx=" << idx
788 << ", mux_width[idx]=" << mux_width[idx] << endl;
789 }
790 }
791
792 // The incoming nex_out is taken as the input for this
793 // statement. Since there are collection of statements
794 // that start at this same point, we save all these
795 // inputs and reuse them for each statement. Unlink the
796 // nex_out now, so we can hook up the mux outputs.
797 NetBus statement_input (scope, nex_out.pin_count());
798 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
799 connect(statement_input.pin(idx), nex_out.pin(idx));
800 nex_out.pin(idx).unlink();
801 if (debug_synth2) {
802 cerr << get_fileline() << ": NetCase::synth_async: "
803 << "statement_input.pin(" << idx << "):" << endl;
804 statement_input.pin(idx).dump_link(cerr, 8);
805 }
806 }
807
808 /* Collect all the statements into a map of index to statement.
809 The guard expression it evaluated to be the index of the mux
810 value, and the statement is bound to that index. */
811
812 unsigned long max_guard_value = 0;
813 map<unsigned long,NetProc*>statement_map;
814 NetProc*default_statement = 0;
815
816 for (size_t item = 0 ; item < items_.size() ; item += 1) {
817 if (items_[item].guard == 0) {
818 default_statement = items_[item].statement;
819 continue;
820 }
821
822 NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
823 if (ge == 0) {
824 cerr << items_[item].guard->get_fileline() << ": sorry: "
825 << "variable case item expressions with a variable "
826 << "case select expression are not supported in "
827 << "synthesis. " << endl;
828 des->errors += 1;
829 return false;
830 }
831 ivl_assert(*this, ge);
832 verinum gval = ge->value();
833
834 unsigned long sel_idx = gval.as_ulong();
835
836 if (statement_map[sel_idx]) {
837 cerr << ge->get_fileline() << ": warning: duplicate case "
838 << "value '" << sel_idx << "' detected. This case is "
839 << "unreachable." << endl;
840 delete items_[item].statement;
841 items_[item].statement = 0;
842 continue;
843 }
844
845 if (sel_idx > max_guard_value)
846 max_guard_value = sel_idx;
847
848 if (items_[item].statement) {
849 statement_map[sel_idx] = items_[item].statement;
850 continue;
851 }
852
853 // Handle the special case of an empty statement.
854 statement_map[sel_idx] = this;
855 }
856
857 // The minimum selector width is the number of inputs that
858 // are selected, rounded up to the nearest power of 2.
859 unsigned sel_need = max(ceil(log2(max_guard_value + 1)), 1.0);
860
861 // If the sel_width can select more than just the explicit
862 // guard values, and there is a default statement, then adjust
863 // the sel_need to allow for the implicit selections.
864 if (default_statement && (sel_width > sel_need))
865 sel_need += 1;
866
867 // The mux size is always an exact power of 2.
868 if (sel_need >= 8*sizeof(unsigned)) {
869 cerr << get_fileline() << ": sorry: mux select width of "
870 << sel_need << " bits is too large for synthesis." << endl;
871 des->errors += 1;
872 return false;
873 }
874 unsigned mux_size = 1U << sel_need;
875
876 if (debug_synth2) {
877 cerr << get_fileline() << ": NetCase::synth_async: "
878 << "Adjusted mux_size is " << mux_size
879 << " (max_guard_value=" << max_guard_value
880 << ", sel_need=" << sel_need
881 << ", sel_width=" << sel_width << ")." << endl;
882 }
883
884 if (sel_width > sel_need) {
885 if (debug_synth2) {
886 cerr << get_fileline() << ": NetCase::synth_async: "
887 << "Selector is " << sel_width << " bits, "
888 << "need only " << sel_need << " bits." << endl;
889 }
890 esig = mux_selector_reduce_width(des, scope, *this, esig, sel_need);
891 }
892
893 /* If there is a default clause, synthesize it once and we'll
894 link it in wherever it is needed. If there isn't, create
895 a dummy default to pass on the accumulated nex_out from
896 preceding statements. */
897 NetBus default_out (scope, nex_out.pin_count());
898 NetBus default_ena (scope, nex_out.pin_count());
899 vector<mask_t> default_masks (nex_out.pin_count());
900
901 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
902 connect(default_out.pin(idx), statement_input.pin(idx));
903 connect(default_ena.pin(idx), scope->tie_lo());
904 }
905
906 if (default_statement) {
907
908 bool flag = synth_async_block_substatement_(des, scope, nex_map, default_out,
909 default_ena, default_masks,
910 default_statement);
911 if (!flag) return false;
912
913 if (debug_synth2) {
914 cerr << get_fileline() << ": NetCase::synth_async: "
915 << "synthesize default clause at " << default_statement->get_fileline()
916 << " is done." << endl;
917 }
918 }
919
920 vector<NetMux*> out_mux (nex_out.pin_count());
921 vector<NetMux*> ena_mux (nex_out.pin_count());
922 vector<bool> full_case (nex_out.pin_count());
923 for (size_t mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
924 out_mux[mdx] = new NetMux(scope, scope->local_symbol(),
925 mux_width[mdx], mux_size, sel_need);
926 des->add_node(out_mux[mdx]);
927
928 // The select signal is already synthesized, and is
929 // common for every mux of this case statement. Simply
930 // hook it up.
931 connect(out_mux[mdx]->pin_Sel(), esig->pin(0));
932
933 // The outputs are in the nex_out, and connected to the
934 // mux Result pins.
935 connect(out_mux[mdx]->pin_Result(), nex_out.pin(mdx));
936
937 // Make sure the output is now connected to a net. If
938 // not, then create a fake one to carry the net-ness of
939 // the pin.
940 if (out_mux[mdx]->pin_Result().nexus()->pick_any_net() == 0) {
941 ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
942 netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1,0);
943 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
944 NetNet::WIRE, tmp_vec);
945 tmp->local_flag(true);
946 ivl_assert(*this, tmp->vector_width() != 0);
947 connect(out_mux[mdx]->pin_Result(), tmp->pin(0));
948 }
949
950 // Create a mux for the enables, but don't hook it up
951 // until we know we need it.
952 ena_mux[mdx] = new NetMux(scope, scope->local_symbol(),
953 1, mux_size, sel_need);
954
955 // Assume a full case to start with. We'll check this as
956 // we synthesise each clause.
957 full_case[mdx] = true;
958 }
959
960 for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
961
962 NetProc*stmt = statement_map[idx];
963 if (stmt==0) {
964 ivl_assert(*this, default_out.pin_count() == out_mux.size());
965 for (unsigned mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
966 connect(out_mux[mdx]->pin_Data(idx), default_out.pin(mdx));
967 connect(ena_mux[mdx]->pin_Data(idx), default_ena.pin(mdx));
968 merge_parallel_masks(bitmasks[mdx], default_masks[mdx]);
969 if (!default_ena.pin(mdx).is_linked(scope->tie_hi()))
970 full_case[mdx] = false;
971 }
972 continue;
973 }
974 ivl_assert(*this, stmt);
975 if (stmt == this) {
976 // Handle the special case of an empty statement.
977 ivl_assert(*this, statement_input.pin_count() == out_mux.size());
978 for (unsigned mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
979 connect(out_mux[mdx]->pin_Data(idx), statement_input.pin(mdx));
980 connect(ena_mux[mdx]->pin_Data(idx), scope->tie_lo());
981 bitmasks[mdx] = mask_t (mux_width[mdx], false);
982 full_case[mdx] = false;
983 }
984 continue;
985 }
986
987 NetBus tmp_out (scope, nex_out.pin_count());
988 NetBus tmp_ena (scope, nex_out.pin_count());
989 for (unsigned mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
990 connect(tmp_out.pin(mdx), statement_input.pin(mdx));
991 connect(tmp_ena.pin(mdx), scope->tie_lo());
992 }
993 vector<mask_t> tmp_masks (nex_out.pin_count());
994 bool flag = synth_async_block_substatement_(des, scope, nex_map, tmp_out,
995 tmp_ena, tmp_masks, stmt);
996 if (!flag) return false;
997
998 for (size_t mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
999 connect(out_mux[mdx]->pin_Data(idx), tmp_out.pin(mdx));
1000 connect(ena_mux[mdx]->pin_Data(idx), tmp_ena.pin(mdx));
1001 merge_parallel_masks(bitmasks[mdx], tmp_masks[mdx]);
1002 if (!tmp_ena.pin(mdx).is_linked(scope->tie_hi()))
1003 full_case[mdx] = false;
1004 }
1005 }
1006
1007 for (unsigned mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
1008 // Optimize away the enable mux if we have a full case,
1009 // otherwise hook it up.
1010 if (full_case[mdx]) {
1011 connect(enables.pin(mdx), scope->tie_hi());
1012 delete ena_mux[mdx];
1013 continue;
1014 }
1015
1016 des->add_node(ena_mux[mdx]);
1017
1018 connect(ena_mux[mdx]->pin_Sel(), esig->pin(0));
1019
1020 connect(enables.pin(mdx), ena_mux[mdx]->pin_Result());
1021
1022 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1023 NetNet::WIRE, &netvector_t::scalar_logic);
1024 tmp->local_flag(true);
1025 connect(ena_mux[mdx]->pin_Result(), tmp->pin(0));
1026 }
1027 return true;
1028 }
1029
1030 /*
1031 * casez statements are hard to implement as a single wide mux because
1032 * the test doesn't really map to a select input. Instead, implement
1033 * it as a chain of binary muxes. This gives the synthesizer more
1034 * flexibility, and is more typically what is desired from a casez anyhow.
1035 */
synth_async_casez_(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)1036 bool NetCase::synth_async_casez_(Design*des, NetScope*scope,
1037 NexusSet&nex_map, NetBus&nex_out,
1038 NetBus&enables, vector<mask_t>&bitmasks)
1039 {
1040 ivl_assert(*this, nex_map.size() == nex_out.pin_count());
1041 ivl_assert(*this, nex_map.size() == enables.pin_count());
1042 ivl_assert(*this, nex_map.size() == bitmasks.size());
1043
1044 /* Synthesize the select expression. */
1045 NetNet*esig = expr_->synthesize(des, scope, expr_);
1046
1047 unsigned sel_width = esig->vector_width();
1048 ivl_assert(*this, sel_width > 0);
1049
1050 vector<unsigned>mux_width (nex_out.pin_count());
1051 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1052 mux_width[idx] = nex_map[idx].wid;
1053 if (debug_synth2) {
1054 cerr << get_fileline() << ": NetCase::synth_async_casez_: "
1055 << "idx=" << idx
1056 << ", mux_width[idx]=" << mux_width[idx] << endl;
1057 }
1058 }
1059
1060 // The incoming nex_out is taken as the input for this
1061 // statement. Since there are collection of statements
1062 // that start at this same point, we save all these
1063 // inputs and reuse them for each statement. Unlink the
1064 // nex_out now, so we can hook up the mux outputs.
1065 NetBus statement_input (scope, nex_out.pin_count());
1066 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1067 connect(statement_input.pin(idx), nex_out.pin(idx));
1068 nex_out.pin(idx).unlink();
1069 if (debug_synth2) {
1070 cerr << get_fileline() << ": NetCase::synth_async_casez_: "
1071 << "statement_input.pin(" << idx << "):" << endl;
1072 statement_input.pin(idx).dump_link(cerr, 8);
1073 }
1074
1075 }
1076
1077 // Look for a default statement.
1078 NetProc*default_statement = 0;
1079 for (size_t item = 0 ; item < items_.size() ; item += 1) {
1080 if (items_[item].guard != 0)
1081 continue;
1082
1083 ivl_assert(*this, default_statement==0);
1084 default_statement = items_[item].statement;
1085 }
1086
1087 /* If there is a default clause, synthesize it once and we'll
1088 link it in wherever it is needed. If there isn't, create
1089 a dummy default to pass on the accumulated nex_out from
1090 preceding statements. */
1091 NetBus default_out (scope, nex_out.pin_count());
1092
1093 for (unsigned idx = 0 ; idx < default_out.pin_count() ; idx += 1)
1094 connect(default_out.pin(idx), statement_input.pin(idx));
1095
1096 if (default_statement) {
1097 bool flag = synth_async_block_substatement_(des, scope, nex_map, default_out,
1098 enables, bitmasks, default_statement);
1099 if (!flag) return false;
1100
1101 if (debug_synth2) {
1102 cerr << get_fileline() << ": NetCase::synth_async_casez_: "
1103 << "synthesize default clause at " << default_statement->get_fileline()
1104 << " is done." << endl;
1105 }
1106 }
1107
1108 netvector_t*condit_type = new netvector_t(IVL_VT_LOGIC, 0, 0);
1109
1110 NetCaseCmp::kind_t case_kind = NetCaseCmp::EEQ;
1111 switch (type()) {
1112 case NetCase::EQ:
1113 case_kind = NetCaseCmp::EEQ;
1114 break;
1115 case NetCase::EQX:
1116 case_kind = NetCaseCmp::XEQ;
1117 break;
1118 case NetCase::EQZ:
1119 case_kind = NetCaseCmp::ZEQ;
1120 break;
1121 default:
1122 assert(0);
1123 }
1124
1125 // Process the items from last to first. We generate a
1126 // true/false mux, with the select being the comparison of
1127 // the case select with the guard expression. The true input
1128 // (data1) is the current statement, and the false input is
1129 // the result of a later statement.
1130 vector<NetMux*>prev_mux (nex_out.pin_count());
1131 for (size_t idx = 0 ; idx < items_.size() ; idx += 1) {
1132 size_t item = items_.size()-idx-1;
1133 if (items_[item].guard == 0)
1134 continue;
1135
1136 NetProc*stmt = items_[item].statement;
1137 ivl_assert(*this, stmt);
1138
1139 NetExpr*guard_expr = items_[item].guard;
1140 NetNet*guard = guard_expr->synthesize(des, scope, guard_expr);
1141
1142 NetCaseCmp*condit_dev = new NetCaseCmp(scope, scope->local_symbol(),
1143 sel_width, case_kind);
1144 des->add_node(condit_dev);
1145 condit_dev->set_line(*this);
1146 // Note that the expression that may have wildcards must
1147 // go in the pin(2) input. This is the definition of the
1148 // NetCaseCmp statement.
1149 connect(condit_dev->pin(1), esig->pin(0));
1150 connect(condit_dev->pin(2), guard->pin(0));
1151
1152 NetNet*condit = new NetNet(scope, scope->local_symbol(),
1153 NetNet::TRI, condit_type);
1154 condit->set_line(*this);
1155 condit->local_flag(true);
1156 connect(condit_dev->pin(0), condit->pin(0));
1157
1158 // Synthesize the guarded statement.
1159 NetBus tmp_out (scope, nex_out.pin_count());
1160 NetBus tmp_ena (scope, nex_out.pin_count());
1161 vector<mask_t> tmp_masks (nex_out.pin_count());
1162
1163 for (unsigned pdx = 0 ; pdx < nex_out.pin_count() ; pdx += 1)
1164 connect(tmp_out.pin(pdx), statement_input.pin(pdx));
1165
1166 synth_async_block_substatement_(des, scope, nex_map, tmp_out,
1167 tmp_ena, tmp_masks, stmt);
1168
1169 NetBus prev_ena (scope, nex_out.pin_count());
1170 for (unsigned mdx = 0 ; mdx < nex_out.pin_count() ; mdx += 1) {
1171 NetMux*mux = new NetMux(scope, scope->local_symbol(),
1172 mux_width[mdx], 2, 1);
1173 des->add_node(mux);
1174 mux->set_line(*this);
1175 connect(mux->pin_Sel(), condit->pin(0));
1176
1177 connect(mux->pin_Data(1), tmp_out.pin(mdx));
1178
1179 // If there is a previous mux, then use that as the
1180 // false clause input. Otherwise, use the default.
1181 if (prev_mux[mdx])
1182 connect(mux->pin_Data(0), prev_mux[mdx]->pin_Result());
1183 else
1184 connect(mux->pin_Data(0), default_out.pin(mdx));
1185
1186 // Make a NetNet for the result.
1187 ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
1188 netvector_t*tmp_vec = new netvector_t(mux_data_type, mux_width[mdx]-1,0);
1189 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1190 NetNet::WIRE, tmp_vec);
1191 tmp->local_flag(true);
1192 tmp->set_line(*this);
1193 ivl_assert(*this, tmp->vector_width() != 0);
1194 connect(mux->pin_Result(), tmp->pin(0));
1195
1196 // This mux becomes the "false" input to the next mux.
1197 prev_mux[mdx] = mux;
1198
1199 connect(prev_ena.pin(mdx), enables.pin(mdx));
1200 enables.pin(mdx).unlink();
1201
1202 multiplex_enables(des, scope, condit, tmp_ena.pin(mdx),
1203 prev_ena.pin(mdx), enables.pin(mdx));
1204
1205 merge_parallel_masks(bitmasks[mdx], tmp_masks[mdx]);
1206 }
1207 }
1208
1209 // Connect the last mux to the output.
1210 for (size_t mdx = 0 ; mdx < prev_mux.size() ; mdx += 1)
1211 connect(prev_mux[mdx]->pin_Result(), nex_out.pin(mdx));
1212
1213 return true;
1214 }
1215
1216 /*
1217 * A condit statement (if (cond) ... else ... ;) infers an A-B mux,
1218 * with the cond expression acting as a select input. If the cond
1219 * expression is true, the if_ clause is selected, and if false, the
1220 * else_ clause is selected.
1221 */
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)1222 bool NetCondit::synth_async(Design*des, NetScope*scope,
1223 NexusSet&nex_map, NetBus&nex_out,
1224 NetBus&enables, vector<mask_t>&bitmasks)
1225 {
1226 // Handle the unlikely case that both clauses are empty.
1227 if ((if_ == 0) && (else_ == 0))
1228 return true;
1229
1230 ivl_assert(*this, nex_map.size() == nex_out.pin_count());
1231 ivl_assert(*this, nex_map.size() == enables.pin_count());
1232 ivl_assert(*this, nex_map.size() == bitmasks.size());
1233
1234 // Synthesize the condition. This will act as a select signal
1235 // for a binary mux.
1236 NetNet*ssig = expr_->synthesize(des, scope, expr_);
1237 ivl_assert(*this, ssig);
1238
1239 // The incoming nex_out is taken as the input for this
1240 // statement. Since there are two statements that start
1241 // at this same point, we save all these inputs and reuse
1242 // them for both statements. Unlink the nex_out now, so
1243 // we can hook up the mux outputs.
1244 NetBus statement_input (scope, nex_out.pin_count());
1245 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1246 connect(statement_input.pin(idx), nex_out.pin(idx));
1247 nex_out.pin(idx).unlink();
1248 if (debug_synth2) {
1249 cerr << get_fileline() << ": NetCondit::synth_async: "
1250 << "statement_input.pin(" << idx << "):" << endl;
1251 statement_input.pin(idx).dump_link(cerr, 8);
1252 }
1253 }
1254
1255 NetBus a_out (scope, nex_out.pin_count());
1256 NetBus a_ena (scope, nex_out.pin_count());
1257 vector<mask_t> a_masks (nex_out.pin_count());
1258 if (if_) {
1259 if (debug_synth2) {
1260 cerr << get_fileline() << ": NetCondit::synth_async: "
1261 << "Synthesize if clause at " << if_->get_fileline()
1262 << endl;
1263 }
1264
1265 for (unsigned idx = 0 ; idx < a_out.pin_count() ; idx += 1) {
1266 connect(a_out.pin(idx), statement_input.pin(idx));
1267 }
1268
1269 bool flag = synth_async_block_substatement_(des, scope, nex_map, a_out,
1270 a_ena, a_masks, if_);
1271 if (!flag) return false;
1272
1273 } else {
1274 for (unsigned idx = 0 ; idx < a_out.pin_count() ; idx += 1) {
1275 connect(a_out.pin(idx), statement_input.pin(idx));
1276 connect(a_ena.pin(idx), scope->tie_lo());
1277 }
1278 }
1279
1280 NetBus b_out(scope, nex_out.pin_count());
1281 NetBus b_ena(scope, nex_out.pin_count());
1282 vector<mask_t> b_masks (nex_out.pin_count());
1283 if (else_) {
1284 if (debug_synth2) {
1285 cerr << get_fileline() << ": NetCondit::synth_async: "
1286 << "Synthesize else clause at " << else_->get_fileline()
1287 << endl;
1288 }
1289
1290 for (unsigned idx = 0 ; idx < b_out.pin_count() ; idx += 1) {
1291 connect(b_out.pin(idx), statement_input.pin(idx));
1292 }
1293
1294 bool flag = synth_async_block_substatement_(des, scope, nex_map, b_out,
1295 b_ena, b_masks, else_);
1296 if (!flag) return false;
1297
1298 } else {
1299 for (unsigned idx = 0 ; idx < b_out.pin_count() ; idx += 1) {
1300 connect(b_out.pin(idx), statement_input.pin(idx));
1301 connect(b_ena.pin(idx), scope->tie_lo());
1302 }
1303 }
1304
1305 /* The nex_out output, a_out input, and b_out input all have the
1306 same pin count (usually, but not always 1) because they are
1307 net arrays of the same dimension. The for loop below creates
1308 a NetMux for each pin of the output. (Note that pins may
1309 be, in fact usually are, vectors.) */
1310
1311 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1312
1313 bool a_driven = a_out.pin(idx).nexus()->pick_any_net();
1314 bool b_driven = b_out.pin(idx).nexus()->pick_any_net();
1315 if (!a_driven && !b_driven) {
1316 connect(nex_out.pin(idx), statement_input.pin(idx));
1317 continue;
1318 }
1319
1320 merge_parallel_masks(bitmasks[idx], a_masks[idx]);
1321 merge_parallel_masks(bitmasks[idx], b_masks[idx]);
1322
1323 // If one clause is empty and the other clause unconditionally
1324 // drives all bits of the vector, we can rely on the enable
1325 // to prevent the flip-flop or latch updating when the empty
1326 // clause is selected, and hence don't need a mux.
1327 if (!a_driven && all_bits_driven(b_masks[idx])) {
1328 connect(nex_out.pin(idx), b_out.pin(idx));
1329 continue;
1330 }
1331 if (!b_driven && all_bits_driven(a_masks[idx])) {
1332 connect(nex_out.pin(idx), a_out.pin(idx));
1333 continue;
1334 }
1335
1336 // Guess the mux type from the type of the output.
1337 ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
1338 if (NetNet*tmp = nex_out.pin(idx).nexus()->pick_any_net()) {
1339 mux_data_type = tmp->data_type();
1340 }
1341
1342 unsigned mux_off = 0;
1343 unsigned mux_width = nex_map[idx].wid;
1344
1345 if (debug_synth2) {
1346 cerr << get_fileline() << ": NetCondit::synth_async: "
1347 << "Calculated mux_width=" << mux_width
1348 << endl;
1349 }
1350
1351 NetPartSelect*apv = detect_partselect_lval(a_out.pin(idx));
1352 if (debug_synth2 && apv) {
1353 cerr << get_fileline() << ": NetCondit::synth_async: "
1354 << "Assign-to-part apv base=" << apv->base()
1355 << ", width=" << apv->width() << endl;
1356 }
1357
1358 NetPartSelect*bpv = detect_partselect_lval(b_out.pin(idx));
1359 if (debug_synth2 && bpv) {
1360 cerr << get_fileline() << ": NetCondit::synth_async: "
1361 << "Assign-to-part bpv base=" << bpv->base()
1362 << ", width=" << bpv->width() << endl;
1363 }
1364
1365 unsigned mux_lwidth = mux_width;
1366 ivl_assert(*this, mux_width != 0);
1367
1368 if (apv && bpv && apv->width()==bpv->width() && apv->base()==bpv->base()) {
1369 // The a and b sides are both assigning to the
1370 // same bits of the output, so we can use that to
1371 // create a much narrower mux that only
1372 // manipulates the width of the part.
1373 mux_width = apv->width();
1374 mux_off = apv->base();
1375 a_out.pin(idx).unlink();
1376 b_out.pin(idx).unlink();
1377 connect(a_out.pin(idx), apv->pin(0));
1378 connect(b_out.pin(idx), bpv->pin(0));
1379 delete apv;
1380 delete bpv;
1381 } else {
1382 // The part selects are of no use. Forget them.
1383 apv = 0;
1384 bpv = 0;
1385 }
1386
1387 NetMux*mux = new NetMux(scope, scope->local_symbol(),
1388 mux_width, 2, 1);
1389 mux->set_line(*this);
1390 des->add_node(mux);
1391
1392 netvector_t*tmp_type = 0;
1393 if (mux_width==1)
1394 tmp_type = new netvector_t(mux_data_type);
1395 else
1396 tmp_type = new netvector_t(mux_data_type, mux_width-1,0);
1397
1398 // Bind some temporary signals to carry pin type.
1399 NetNet*otmp = new NetNet(scope, scope->local_symbol(),
1400 NetNet::WIRE, NetNet::not_an_array, tmp_type);
1401 otmp->local_flag(true);
1402 otmp->set_line(*this);
1403 connect(mux->pin_Result(),otmp->pin(0));
1404
1405 connect(mux->pin_Sel(), ssig->pin(0));
1406 connect(mux->pin_Data(1), a_out.pin(idx));
1407 connect(mux->pin_Data(0), b_out.pin(idx));
1408
1409 // If we are only muxing a part of the output vector, make a
1410 // NetSubstitute to blend the mux output with the accumulated
1411 // output from previous statements.
1412 if (mux_width < mux_lwidth) {
1413 tmp_type = new netvector_t(mux_data_type, mux_lwidth-1,0);
1414
1415 NetNet*itmp = statement_input.pin(idx).nexus()->pick_any_net();
1416 if (itmp == 0) {
1417 itmp = new NetNet(scope, scope->local_symbol(),
1418 NetNet::WIRE, NetNet::not_an_array, tmp_type);
1419 itmp->local_flag(true);
1420 itmp->set_line(*this);
1421 connect(itmp->pin(0), statement_input.pin(idx));
1422 }
1423
1424 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
1425 NetNet::WIRE, NetNet::not_an_array, tmp_type);
1426 tmp->local_flag(true);
1427 tmp->set_line(*this);
1428 NetSubstitute*ps = new NetSubstitute(itmp, otmp, mux_lwidth, mux_off);
1429 des->add_node(ps);
1430 connect(ps->pin(0), tmp->pin(0));
1431 otmp = tmp;
1432 }
1433
1434 connect(nex_out.pin(idx), otmp->pin(0));
1435 }
1436
1437 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1438 multiplex_enables(des, scope, ssig, a_ena.pin(idx), b_ena.pin(idx), enables.pin(idx));
1439 }
1440
1441 return true;
1442 }
1443
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)1444 bool NetEvWait::synth_async(Design*des, NetScope*scope,
1445 NexusSet&nex_map, NetBus&nex_out,
1446 NetBus&enables, vector<mask_t>&bitmasks)
1447 {
1448 bool flag = statement_->synth_async(des, scope, nex_map, nex_out, enables, bitmasks);
1449 return flag;
1450 }
1451
synth_async(Design * des,NetScope * scope,NexusSet & nex_map,NetBus & nex_out,NetBus & enables,vector<mask_t> & bitmasks)1452 bool NetForLoop::synth_async(Design*des, NetScope*scope,
1453 NexusSet&nex_map, NetBus&nex_out,
1454 NetBus&enables, vector<mask_t>&bitmasks)
1455 {
1456 if (debug_synth2) {
1457 cerr << get_fileline() << ": NetForLoop::synth_async: "
1458 << "Index variable is " << index_->name() << endl;
1459 cerr << get_fileline() << ": NetForLoop::synth_async: "
1460 << "Initialization expression: " << *init_expr_ << endl;
1461 }
1462
1463 // Get the step assignment statement and break it into the
1464 // l-value (should be the index) and the r-value, which is the
1465 // step expressions.
1466 NetAssign*step_assign = dynamic_cast<NetAssign*> (step_statement_);
1467 char assign_operator = step_assign->assign_operator();
1468 ivl_assert(*this, step_assign);
1469 NetExpr*step_expr = step_assign->rval();
1470
1471 // Tell the scope that this index value is like a genvar.
1472 LocalVar index_var;
1473 index_var.nwords = 0;
1474
1475 map<perm_string,LocalVar> index_args;
1476
1477 // Calculate the initial value for the index.
1478 index_var.value = init_expr_->evaluate_function(*this, index_args);
1479 ivl_assert(*this, index_var.value);
1480 index_args[index_->name()] = index_var;
1481
1482 for (;;) {
1483 // Evaluate the condition expression. If it is false,
1484 // then we are going to break out of this synthesis loop.
1485 NetExpr*tmp = condition_->evaluate_function(*this, index_args);
1486 ivl_assert(*this, tmp);
1487
1488 long cond_value;
1489 bool rc = eval_as_long(cond_value, tmp);
1490 ivl_assert(*this, rc);
1491 delete tmp;
1492 if (!cond_value) break;
1493
1494 scope->genvar_tmp = index_->name();
1495 rc = eval_as_long(scope->genvar_tmp_val, index_var.value);
1496 ivl_assert(*this, rc);
1497
1498 if (debug_synth2) {
1499 cerr << get_fileline() << ": NetForLoop::synth_async: "
1500 << "Synthesis iteration with " << index_->name()
1501 << "=" << *index_var.value << endl;
1502 }
1503
1504 // Synthesize the iterated expression. Stash the loop
1505 // index value so that the substatements can see this
1506 // value and use it during its own synthesis.
1507 ivl_assert(*this, scope->loop_index_tmp.empty());
1508 scope->loop_index_tmp = index_args;
1509
1510 NetBus tmp_ena (scope, nex_out.pin_count());
1511 vector<mask_t> tmp_masks (nex_out.pin_count());
1512
1513 rc = synth_async_block_substatement_(des, scope, nex_map, nex_out,
1514 tmp_ena, tmp_masks, statement_);
1515
1516 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
1517 merge_sequential_enables(des, scope, enables.pin(idx), tmp_ena.pin(idx));
1518 merge_sequential_masks(bitmasks[idx], tmp_masks[idx]);
1519 }
1520
1521 scope->loop_index_tmp.clear();
1522
1523 // Evaluate the step_expr to generate the next index value.
1524 tmp = step_expr->evaluate_function(*this, index_args);
1525 ivl_assert(*this, tmp);
1526
1527 // If there is an assign_operator, then replace the
1528 // index_var.value with (value <op> tmp) and evaluate
1529 // that to get the next value. "value" is the existing
1530 // value, and "tmp" is the step value. We are replacing
1531 // (value += tmp) with (value = value + tmp) and
1532 // evaluating it.
1533 switch (assign_operator) {
1534 case 0:
1535 break;
1536 case '+':
1537 case '-':
1538 index_var.value = new NetEBAdd(assign_operator, tmp, index_var.value, 32, true);
1539 tmp = index_var.value->evaluate_function(*this, index_args);
1540 break;
1541
1542 default:
1543 cerr << get_fileline() << ": internal error: "
1544 << "NetForLoop::synth_async: What to do with assign_operator=" << assign_operator << endl;
1545 ivl_assert(*this, 0);
1546 }
1547 delete index_var.value;
1548 index_var.value = tmp;
1549 index_args[index_->name()] = index_var;
1550 }
1551
1552 delete index_var.value;
1553
1554 return true;
1555 }
1556
1557 /*
1558 * This method is called when the process is shown to be
1559 * asynchronous. Figure out the nexus set of outputs from this
1560 * process, and pass that to the synth_async method for the statement
1561 * of the process. The statement will connect its output to the
1562 * nex_out set, using the nex_map as a guide. Starting from the top,
1563 * the nex_map is the same as the nex_map.
1564 */
synth_async(Design * des)1565 bool NetProcTop::synth_async(Design*des)
1566 {
1567 NexusSet nex_set;
1568 statement_->nex_output(nex_set);
1569
1570 if (debug_synth2) {
1571 cerr << get_fileline() << ": NetProcTop::synth_async: "
1572 << "Process has " << nex_set.size() << " outputs." << endl;
1573 }
1574
1575 NetBus nex_out (scope(), nex_set.size());
1576 NetBus enables (scope(), nex_set.size());
1577 vector<NetProc::mask_t> bitmasks (nex_set.size());
1578
1579 // Save links to the initial nex_out. These will be used later
1580 // to detect floating part-substitute and mux inputs that need
1581 // to be tied off.
1582 NetBus nex_in (scope(), nex_out.pin_count());
1583 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
1584 connect(nex_in.pin(idx), nex_out.pin(idx));
1585
1586 bool flag = statement_->synth_async(des, scope(), nex_set, nex_out, enables, bitmasks);
1587 if (!flag) return false;
1588
1589 flag = tie_off_floating_inputs_(des, nex_set, nex_in, bitmasks, false);
1590 if (!flag) return false;
1591
1592 for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
1593
1594 if (enables.pin(idx).is_linked(scope()->tie_hi())) {
1595 connect(nex_set[idx].lnk, nex_out.pin(idx));
1596 } else {
1597 cerr << get_fileline() << ": warning: "
1598 << "A latch has been inferred for '"
1599 << nex_set[idx].lnk.nexus()->pick_any_net()->name()
1600 << "'." << endl;
1601
1602 if (enables.pin(idx).nexus()->pick_any_net()->local_flag()) {
1603 cerr << get_fileline() << ": warning: The latch "
1604 "enable is connected to a synthesized "
1605 "expression. The latch may be sensitive "
1606 "to glitches." << endl;
1607 }
1608
1609 if (debug_synth2) {
1610 cerr << get_fileline() << ": debug: "
1611 << "Top level making a "
1612 << nex_set[idx].wid << "-wide "
1613 << "NetLatch device." << endl;
1614 }
1615
1616 NetLatch*latch = new NetLatch(scope(), scope()->local_symbol(),
1617 nex_set[idx].wid);
1618 des->add_node(latch);
1619 latch->set_line(*this);
1620
1621 NetNet*tmp = nex_out.pin(idx).nexus()->pick_any_net();
1622 tmp->set_line(*this);
1623 assert(tmp);
1624
1625 tmp = crop_to_width(des, tmp, latch->width());
1626
1627 connect(nex_set[idx].lnk, latch->pin_Q());
1628 connect(tmp->pin(0), latch->pin_Data());
1629
1630 assert (enables.pin(idx).is_linked());
1631 connect(enables.pin(idx), latch->pin_Enable());
1632 }
1633 }
1634
1635 synthesized_design_ = des;
1636 return true;
1637 }
1638
1639
synth_sync(Design * des,NetScope * scope,bool &,NetNet *,NetBus & ff_ce,NetBus &,NetBus &,vector<verinum> &,NexusSet & nex_map,NetBus & nex_out,vector<mask_t> & bitmasks,const vector<NetEvProbe * > & events)1640 bool NetProc::synth_sync(Design*des, NetScope*scope,
1641 bool& /* ff_negedge */,
1642 NetNet* /* ff_clk */, NetBus&ff_ce,
1643 NetBus& /* ff_aclr*/, NetBus& /* ff_aset*/,
1644 vector<verinum>& /*ff_aset_value*/,
1645 NexusSet&nex_map, NetBus&nex_out,
1646 vector<mask_t>&bitmasks,
1647 const vector<NetEvProbe*>&events)
1648 {
1649 if (events.size() > 0) {
1650 cerr << get_fileline() << ": error: Events are unaccounted"
1651 << " for in process synthesis." << endl;
1652 des->errors += 1;
1653 }
1654
1655 if (debug_synth2) {
1656 cerr << get_fileline() << ": NetProc::synth_sync: "
1657 << "This statement is an async input to a sync process." << endl;
1658 }
1659
1660 /* Synthesize the input to the DFF. */
1661 return synth_async(des, scope, nex_map, nex_out, ff_ce, bitmasks);
1662 }
1663
1664 /*
1665 * This method is called when a block is encountered near the surface
1666 * of a synchronous always statement. For example, this code will be
1667 * invoked for input like this:
1668 *
1669 * always @(posedge clk...) begin
1670 * <statement1>
1671 * <statement2>
1672 * ...
1673 * end
1674 *
1675 * This needs to be split into a DFF bank for each statement, because
1676 * the statements may each infer different reset and enables signals.
1677 */
synth_sync(Design * des,NetScope * scope,bool & ff_negedge,NetNet * ff_clk,NetBus & ff_ce,NetBus & ff_aclr,NetBus & ff_aset,vector<verinum> & ff_aset_value,NexusSet & nex_map,NetBus & nex_out,vector<mask_t> & bitmasks,const vector<NetEvProbe * > & events_in)1678 bool NetBlock::synth_sync(Design*des, NetScope*scope,
1679 bool&ff_negedge,
1680 NetNet*ff_clk, NetBus&ff_ce,
1681 NetBus&ff_aclr,NetBus&ff_aset,
1682 vector<verinum>&ff_aset_value,
1683 NexusSet&nex_map, NetBus&nex_out,
1684 vector<mask_t>&bitmasks,
1685 const vector<NetEvProbe*>&events_in)
1686 {
1687 if (debug_synth2) {
1688 cerr << get_fileline() << ": NetBlock::synth_sync: "
1689 << "Examine this block for synchronous logic." << endl;
1690 }
1691
1692 if (last_ == 0) {
1693 return true;
1694 }
1695
1696 bool flag = true;
1697
1698 NetProc*cur = last_;
1699 do {
1700 cur = cur->next_;
1701
1702 // Create a temporary nex_map for the substatement.
1703 NexusSet tmp_map;
1704 cur->nex_output(tmp_map);
1705
1706 // Create temporary variables to collect the output from the synthesis.
1707 NetBus tmp_out (scope, tmp_map.size());
1708 NetBus tmp_ce (scope, tmp_map.size());
1709 vector<mask_t> tmp_masks (tmp_map.size());
1710
1711 // Map (and move) the accumulated nex_out for this block
1712 // to the version that we can pass to the next statement.
1713 // We will move the result back later.
1714 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
1715 unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
1716 ivl_assert(*this, ptr < nex_out.pin_count());
1717 connect(tmp_out.pin(idx), nex_out.pin(ptr));
1718 nex_out.pin(ptr).unlink();
1719 }
1720
1721 /* Now go on with the synchronous synthesis for this
1722 subset of the statement. The tmp_map is the output
1723 nexa that we expect, and the tmp_out is where we want
1724 those outputs connected. */
1725 bool ok_flag = cur->synth_sync(des, scope,
1726 ff_negedge, ff_clk, tmp_ce,
1727 ff_aclr, ff_aset, ff_aset_value,
1728 tmp_map, tmp_out, tmp_masks,
1729 events_in);
1730 flag = flag && ok_flag;
1731
1732 if (ok_flag == false)
1733 continue;
1734
1735 // Now map the output from the substatement back to the
1736 // outputs for this block.
1737 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
1738 unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
1739 ivl_assert(*this, ptr < nex_out.pin_count());
1740 connect(nex_out.pin(ptr), tmp_out.pin(idx));
1741
1742 merge_sequential_enables(des, scope, ff_ce.pin(ptr), tmp_ce.pin(idx));
1743
1744 merge_sequential_masks(bitmasks[ptr], tmp_masks[idx]);
1745 }
1746
1747 } while (cur != last_);
1748
1749 if (debug_synth2) {
1750 cerr << get_fileline() << ": NetBlock::synth_sync: "
1751 << "Done Examining this block for synchronous logic." << endl;
1752 }
1753
1754 return flag;
1755 }
1756
1757 /*
1758 * This method handles the case where I find a conditional near the
1759 * surface of a synchronous thread. This conditional can be a CE or an
1760 * asynchronous set/reset, depending on whether the pin of the
1761 * expression is connected to an event, or not.
1762 */
synth_sync(Design * des,NetScope * scope,bool & ff_negedge,NetNet * ff_clk,NetBus & ff_ce,NetBus & ff_aclr,NetBus & ff_aset,vector<verinum> & ff_aset_value,NexusSet & nex_map,NetBus & nex_out,vector<mask_t> & bitmasks,const vector<NetEvProbe * > & events_in)1763 bool NetCondit::synth_sync(Design*des, NetScope*scope,
1764 bool&ff_negedge,
1765 NetNet*ff_clk, NetBus&ff_ce,
1766 NetBus&ff_aclr,NetBus&ff_aset,
1767 vector<verinum>&ff_aset_value,
1768 NexusSet&nex_map, NetBus&nex_out,
1769 vector<mask_t>&bitmasks,
1770 const vector<NetEvProbe*>&events_in)
1771 {
1772 /* First try to turn the condition expression into an
1773 asynchronous set/reset. If the condition expression has
1774 inputs that are included in the sensitivity list, then it
1775 is likely intended as an asynchronous input. */
1776
1777 NexusSet*expr_input = expr_->nex_input();
1778 assert(expr_input);
1779 for (unsigned idx = 0 ; idx < events_in.size() ; idx += 1) {
1780
1781 NetEvProbe*ev = events_in[idx];
1782 NexusSet pin_set;
1783 pin_set.add(ev->pin(0).nexus(), 0, 0);
1784
1785 if (! expr_input->contains(pin_set))
1786 continue;
1787
1788 // Synthesize the set/reset input expression.
1789 NetNet*rst = expr_->synthesize(des, scope, expr_);
1790 ivl_assert(*this, rst->pin_count() == 1);
1791
1792 // Check that the edge used on the set/reset input is correct.
1793 switch (ev->edge()) {
1794 case NetEvProbe::POSEDGE:
1795 if (ev->pin(0).nexus() != rst->pin(0).nexus()) {
1796 cerr << get_fileline() << ": error: "
1797 << "Condition for posedge asynchronous set/reset "
1798 << "must exactly match the event expression." << endl;
1799 des->errors += 1;
1800 return false;
1801 }
1802 break;
1803 case NetEvProbe::NEGEDGE: {
1804 bool is_inverter = false;
1805 NetNode*node = rst->pin(0).nexus()->pick_any_node();
1806 if (NetLogic*gate = dynamic_cast<NetLogic*>(node)) {
1807 if (gate->type() == NetLogic::NOT)
1808 is_inverter = true;
1809 }
1810 if (NetUReduce*gate = dynamic_cast<NetUReduce*>(node)) {
1811 if (gate->type() == NetUReduce::NOR)
1812 is_inverter = true;
1813 }
1814 if (!is_inverter || ev->pin(0).nexus() != node->pin(1).nexus()) {
1815 cerr << get_fileline() << ": error: "
1816 << "Condition for negedge asynchronous set/reset must be "
1817 << "a simple inversion of the event expression." << endl;
1818 des->errors += 1;
1819 return false;
1820 }
1821 break;
1822 }
1823 default:
1824 cerr << get_fileline() << ": error: "
1825 << "Asynchronous set/reset event must be "
1826 << "edge triggered." << endl;
1827 des->errors += 1;
1828 return false;
1829 }
1830
1831 // Synthesize the true clause to figure out what kind of
1832 // set/reset we have. This should synthesize down to a
1833 // constant. If not, we have an asynchronous LOAD, a
1834 // very different beast.
1835 ivl_assert(*this, if_);
1836 NetBus tmp_out(scope, nex_out.pin_count());
1837 NetBus tmp_ena(scope, nex_out.pin_count());
1838 vector<mask_t> tmp_masks (nex_out.pin_count());
1839 bool flag = if_->synth_async(des, scope, nex_map, tmp_out, tmp_ena, tmp_masks);
1840 if (!flag) return false;
1841
1842 ivl_assert(*this, tmp_out.pin_count() == ff_aclr.pin_count());
1843 ivl_assert(*this, tmp_out.pin_count() == ff_aset.pin_count());
1844
1845 for (unsigned pin = 0 ; pin < tmp_out.pin_count() ; pin += 1) {
1846 Nexus*rst_nex = tmp_out.pin(pin).nexus();
1847
1848 if (!all_bits_driven(tmp_masks[pin])) {
1849 cerr << get_fileline() << ": sorry: Not all bits of '"
1850 << nex_map[idx].lnk.nexus()->pick_any_net()->name()
1851 << "' are asynchronously set or reset. This is "
1852 << "not currently supported in synthesis." << endl;
1853 des->errors += 1;
1854 return false;
1855 }
1856
1857 if (! rst_nex->drivers_constant() ||
1858 ! tmp_ena.pin(pin).is_linked(scope->tie_hi()) ) {
1859 cerr << get_fileline() << ": sorry: Asynchronous load "
1860 << "is not currently supported in synthesis." << endl;
1861 des->errors += 1;
1862 return false;
1863 }
1864
1865 if (ff_aclr.pin(pin).is_linked() ||
1866 ff_aset.pin(pin).is_linked()) {
1867 cerr << get_fileline() << ": sorry: More than "
1868 "one asynchronous set/reset clause is "
1869 "not currently supported in synthesis." << endl;
1870 des->errors += 1;
1871 return false;
1872 }
1873
1874 verinum rst_drv = rst_nex->driven_vector();
1875
1876 verinum zero (verinum::V0, rst_drv.len());
1877 verinum ones (verinum::V1, rst_drv.len());
1878
1879 if (rst_drv==zero) {
1880 // Don't yet support multiple asynchronous reset inputs.
1881 ivl_assert(*this, ! ff_aclr.pin(pin).is_linked());
1882
1883 ivl_assert(*this, rst->pin_count()==1);
1884 connect(ff_aclr.pin(pin), rst->pin(0));
1885
1886 } else {
1887 // Don't yet support multiple asynchronous set inputs.
1888 ivl_assert(*this, ! ff_aset.pin(pin).is_linked());
1889
1890 ivl_assert(*this, rst->pin_count()==1);
1891 connect(ff_aset.pin(pin), rst->pin(0));
1892 if (rst_drv!=ones)
1893 ff_aset_value[pin] = rst_drv;
1894 }
1895 }
1896
1897 if (else_ == 0)
1898 return true;
1899
1900 vector<NetEvProbe*> events;
1901 for (unsigned jdx = 0 ; jdx < events_in.size() ; jdx += 1) {
1902 if (jdx != idx)
1903 events.push_back(events_in[jdx]);
1904 }
1905 return else_->synth_sync(des, scope,
1906 ff_negedge, ff_clk, ff_ce,
1907 ff_aclr, ff_aset, ff_aset_value,
1908 nex_map, nex_out, bitmasks, events);
1909 }
1910
1911 delete expr_input;
1912
1913 #if 0
1914 /* Detect the case that this is a *synchronous* set/reset. It
1915 is not asynchronous because we know the condition is not
1916 included in the sensitivity list, but if the if_ case is
1917 constant (has no inputs) then we can model this as a
1918 synchronous set/reset.
1919
1920 This is only synchronous set/reset if there is a true and a
1921 false clause, and no inputs. The "no inputs" requirement is
1922 met if the assignments are of all constant values. */
1923 assert(if_ != 0);
1924 NexusSet*a_set = if_->nex_input();
1925
1926 if ((a_set->count() == 0) && if_ && else_) {
1927
1928 NetNet*rst = expr_->synthesize(des);
1929 assert(rst->pin_count() == 1);
1930
1931 /* Synthesize the true clause to figure out what
1932 kind of set/reset we have. */
1933 NetNet*asig = new NetNet(scope, scope->local_symbol(),
1934 NetNet::WIRE, nex_map->pin_count());
1935 asig->local_flag(true);
1936 bool flag = if_->synth_async(des, scope, nex_map, asig);
1937
1938 if (!flag) {
1939 /* This path leads nowhere */
1940 delete asig;
1941 } else {
1942 assert(asig->pin_count() == ff->width());
1943
1944 /* Collect the set/reset value into a verinum. If
1945 this turns out to be entirely 0 values, then
1946 use the Sclr input. Otherwise, use the Aset
1947 input and save the set value. */
1948 verinum tmp (verinum::V0, ff->width());
1949 for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
1950
1951 assert(asig->pin(bit).nexus()->drivers_constant());
1952 tmp.set(bit, asig->pin(bit).nexus()->driven_value());
1953 }
1954
1955 assert(tmp.is_defined());
1956 if (tmp.is_zero()) {
1957 connect(ff->pin_Sclr(), rst->pin(0));
1958
1959 } else {
1960 connect(ff->pin_Sset(), rst->pin(0));
1961 ff->sset_value(tmp);
1962 }
1963
1964 delete a_set;
1965
1966 assert(else_ != 0);
1967 flag = else_->synth_sync(des, scope, ff, nex_map,
1968 nex_out, svector<NetEvProbe*>(0))
1969 && flag;
1970 DEBUG_SYNTH2_EXIT("NetCondit",flag)
1971 return flag;
1972 }
1973 }
1974
1975 delete a_set;
1976 #endif
1977
1978 #if 0
1979 /* This gives a false positive for strange coding styles,
1980 such as ivltests/conditsynth3.v. */
1981
1982 /* Failed to find an asynchronous set/reset, so any events
1983 input are probably in error. */
1984 if (events_in.size() > 0) {
1985 cerr << get_fileline() << ": error: Events are unaccounted"
1986 << " for in process synthesis." << endl;
1987 des->errors += 1;
1988 }
1989 #endif
1990
1991 return synth_async(des, scope, nex_map, nex_out, ff_ce, bitmasks);
1992 }
1993
synth_sync(Design * des,NetScope * scope,bool & ff_negedge,NetNet * ff_clk,NetBus & ff_ce,NetBus & ff_aclr,NetBus & ff_aset,vector<verinum> & ff_aset_value,NexusSet & nex_map,NetBus & nex_out,vector<mask_t> & bitmasks,const vector<NetEvProbe * > & events_in)1994 bool NetEvWait::synth_sync(Design*des, NetScope*scope,
1995 bool&ff_negedge,
1996 NetNet*ff_clk, NetBus&ff_ce,
1997 NetBus&ff_aclr,NetBus&ff_aset,
1998 vector<verinum>&ff_aset_value,
1999 NexusSet&nex_map, NetBus&nex_out,
2000 vector<mask_t>&bitmasks,
2001 const vector<NetEvProbe*>&events_in)
2002 {
2003 if (debug_synth2) {
2004 cerr << get_fileline() << ": NetEvWait::synth_sync: "
2005 << "Synchronous process an event statement." << endl;
2006 }
2007
2008 if (events_in.size() > 0) {
2009 cerr << get_fileline() << ": error: Events are unaccounted"
2010 << " for in process synthesis." << endl;
2011 des->errors += 1;
2012 }
2013
2014 assert(events_in.size() == 0);
2015
2016 /* This can't be other than one unless there are named events,
2017 which I cannot synthesize. */
2018 ivl_assert(*this, events_.size() == 1);
2019 NetEvent*ev = events_[0];
2020
2021 assert(ev->nprobe() >= 1);
2022 vector<NetEvProbe*>events (ev->nprobe() - 1);
2023
2024 /* Get the input set from the substatement. This will be used
2025 to figure out which of the probes is the clock. */
2026 NexusSet*statement_input = statement_ -> nex_input();
2027
2028 /* Search for a clock input. The clock input is the edge event
2029 that is not also an input to the substatement. */
2030 NetEvProbe*pclk = 0;
2031 unsigned event_idx = 0;
2032 for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) {
2033 NetEvProbe*tmp = ev->probe(idx);
2034 assert(tmp->pin_count() == 1);
2035
2036 NexusSet tmp_nex;
2037 tmp_nex .add( tmp->pin(0).nexus(), 0, 0 );
2038
2039 if (! statement_input ->contains(tmp_nex)) {
2040 if (pclk != 0) {
2041 cerr << get_fileline() << ": error: Too many "
2042 << "clocks for synchronous logic." << endl;
2043 cerr << get_fileline() << ": : Perhaps an"
2044 << " asynchronous set/reset is misused?" << endl;
2045 des->errors += 1;
2046 }
2047 pclk = tmp;
2048
2049 } else {
2050 events[event_idx++] = tmp;
2051 }
2052 }
2053
2054 if (pclk == 0) {
2055 cerr << get_fileline() << ": error: None of the edges"
2056 << " are valid clock inputs." << endl;
2057 cerr << get_fileline() << ": : Perhaps the clock"
2058 << " is read by a statement or expression?" << endl;
2059 des->errors += 1;
2060 return false;
2061 }
2062
2063 if (debug_synth2) {
2064 cerr << get_fileline() << ": NetEvWait::synth_sync: "
2065 << "Found and synthesized the FF clock." << endl;
2066 }
2067
2068 connect(ff_clk->pin(0), pclk->pin(0));
2069 if (pclk->edge() == NetEvProbe::NEGEDGE) {
2070 ff_negedge = true;
2071
2072 if (debug_synth2) {
2073 cerr << get_fileline() << ": debug: "
2074 << "Detected a NEGEDGE clock for the synthesized ff."
2075 << endl;
2076 }
2077 }
2078
2079 /* Synthesize the input to the DFF. */
2080 return statement_->synth_sync(des, scope,
2081 ff_negedge, ff_clk, ff_ce,
2082 ff_aclr, ff_aset, ff_aset_value,
2083 nex_map, nex_out, bitmasks, events);
2084 }
2085
2086 /*
2087 * This method is called for a process that is determined to be
2088 * synchronous. Create a NetFF device to hold the output from the
2089 * statement, and synthesize that statement in place.
2090 */
synth_sync(Design * des)2091 bool NetProcTop::synth_sync(Design*des)
2092 {
2093 if (debug_synth2) {
2094 cerr << get_fileline() << ": NetProcTop::synth_sync: "
2095 << "Process is apparently synchronous. Making NetFFs."
2096 << endl;
2097 }
2098
2099 NexusSet nex_set;
2100 statement_->nex_output(nex_set);
2101 vector<verinum> aset_value(nex_set.size());
2102
2103 /* Make a model FF that will connect to the first item in the
2104 set, and will also take the initial connection of clocks
2105 and resets. */
2106
2107 // Create a net to carry the clock for the synthesized FFs.
2108 NetNet*clock = new NetNet(scope(), scope()->local_symbol(),
2109 NetNet::TRI, &netvector_t::scalar_logic);
2110 clock->local_flag(true);
2111 clock->set_line(*this);
2112
2113 NetBus ce (scope(), nex_set.size());
2114 NetBus nex_d (scope(), nex_set.size());
2115 NetBus nex_q (scope(), nex_set.size());
2116 NetBus aclr (scope(), nex_set.size());
2117 NetBus aset (scope(), nex_set.size());
2118 vector<NetProc::mask_t> bitmasks (nex_set.size());
2119
2120 // Save links to the initial nex_d. These will be used later
2121 // to detect floating part-substitute and mux inputs that need
2122 // to be tied off.
2123 NetBus nex_in (scope(), nex_d.pin_count());
2124 for (unsigned idx = 0 ; idx < nex_in.pin_count() ; idx += 1)
2125 connect(nex_in.pin(idx), nex_d.pin(idx));
2126
2127 // The Q of the NetFF devices is connected to the output that
2128 // we are. The nex_q is a bundle of the outputs.
2129 for (unsigned idx = 0 ; idx < nex_q.pin_count() ; idx += 1)
2130 connect(nex_q.pin(idx), nex_set[idx].lnk);
2131
2132 // Connect the D of the NetFF devices later.
2133
2134 /* Synthesize the input to the DFF. */
2135 bool negedge = false;
2136 bool flag = statement_->synth_sync(des, scope(),
2137 negedge, clock, ce,
2138 aclr, aset, aset_value,
2139 nex_set, nex_d, bitmasks,
2140 vector<NetEvProbe*>());
2141 if (! flag) {
2142 delete clock;
2143 return false;
2144 }
2145
2146 flag = tie_off_floating_inputs_(des, nex_set, nex_in, bitmasks, true);
2147 if (!flag) return false;
2148
2149 for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
2150
2151 //ivl_assert(*this, nex_set[idx].nex);
2152 if (debug_synth2) {
2153 cerr << get_fileline() << ": debug: "
2154 << "Top level making a "
2155 << nex_set[idx].wid << "-wide "
2156 << "NetFF device." << endl;
2157 }
2158
2159 NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
2160 negedge, nex_set[idx].wid);
2161 des->add_node(ff2);
2162 ff2->set_line(*this);
2163 ff2->aset_value(aset_value[idx]);
2164
2165 NetNet*tmp = nex_d.pin(idx).nexus()->pick_any_net();
2166 tmp->set_line(*this);
2167 assert(tmp);
2168
2169 tmp = crop_to_width(des, tmp, ff2->width());
2170
2171 connect(nex_q.pin(idx), ff2->pin_Q());
2172 connect(tmp->pin(0), ff2->pin_Data());
2173
2174 connect(clock->pin(0), ff2->pin_Clock());
2175 if (ce.pin(idx).is_linked())
2176 connect(ce.pin(idx), ff2->pin_Enable());
2177 if (aclr.pin(idx).is_linked())
2178 connect(aclr.pin(idx), ff2->pin_Aclr());
2179 if (aset.pin(idx).is_linked())
2180 connect(aset.pin(idx), ff2->pin_Aset());
2181 #if 0
2182 if (ff->pin_Sset().is_linked())
2183 connect(ff->pin_Sset(), ff2->pin_Sset());
2184 if (ff->pin_Sclr().is_linked())
2185 connect(ff->pin_Sclr(), ff2->pin_Sclr());
2186 #endif
2187 }
2188
2189 // The "clock" net was just to carry the connection back
2190 // to the flip-flop. Delete it now. The connection will
2191 // persist.
2192 delete clock;
2193
2194 synthesized_design_ = des;
2195 return true;
2196 }
2197
2198 class synth2_f : public functor_t {
2199
2200 public:
2201 void process(Design*, NetProcTop*);
2202
2203 private:
2204 };
2205
2206
2207 /*
2208 * Look at a process. If it is asynchronous, then synthesize it as an
2209 * asynchronous process and delete the process itself for its gates.
2210 */
process(Design * des,NetProcTop * top)2211 void synth2_f::process(Design*des, NetProcTop*top)
2212 {
2213 if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
2214 return;
2215
2216 /* If the scope that contains this process as a cell attribute
2217 attached to it, then skip synthesis. */
2218 if (top->scope()->attribute(perm_string::literal("ivl_synthesis_cell")).len() > 0)
2219 return;
2220
2221 /* Create shared pullup and pulldown nodes (if they don't already
2222 exist) for use when creating clock/gate enables. */
2223 top->scope()->add_tie_hi(des);
2224 top->scope()->add_tie_lo(des);
2225
2226 if (top->is_synchronous()) {
2227 bool flag = top->synth_sync(des);
2228 if (! flag) {
2229 cerr << top->get_fileline() << ": error: "
2230 << "Unable to synthesize synchronous process."
2231 << endl;
2232 des->errors += 1;
2233 return;
2234 }
2235 des->delete_process(top);
2236 return;
2237 }
2238
2239 if (! top->is_asynchronous()) {
2240 bool synth_error_flag = false;
2241 if (top->attribute(perm_string::literal("ivl_combinational")).as_ulong() != 0) {
2242 cerr << top->get_fileline() << ": error: "
2243 << "Process is marked combinational,"
2244 << " but isn't really." << endl;
2245 des->errors += 1;
2246 synth_error_flag = true;
2247 }
2248
2249 if (top->attribute(perm_string::literal("ivl_synthesis_on")).as_ulong() != 0) {
2250 cerr << top->get_fileline() << ": error: "
2251 << "Process is marked for synthesis,"
2252 << " but I can't do it." << endl;
2253 des->errors += 1;
2254 synth_error_flag = true;
2255 }
2256
2257 if (! synth_error_flag)
2258 cerr << top->get_fileline() << ": warning: "
2259 << "Process not synthesized." << endl;
2260
2261 return;
2262 }
2263
2264 if (! top->synth_async(des)) {
2265 cerr << top->get_fileline() << ": error: "
2266 << "Unable to synthesize asynchronous process."
2267 << endl;
2268 des->errors += 1;
2269 return;
2270 }
2271
2272 des->delete_process(top);
2273 }
2274
synth2(Design * des)2275 void synth2(Design*des)
2276 {
2277 synth2_f synth_obj;
2278 des->functor(&synth_obj);
2279 }
2280