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