Fix for assertion error when expanding macro.
[iverilog.git] / synth2.cc
blobb6068cd845535875cab7a3785f9e2bf41c200d86
1 /*
2 * Copyright (c) 2002-2005 Stephen Williams (steve@icarus.com)
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #ifdef HAVE_CVS_IDENT
20 #ident "$Id: synth2.cc,v 1.46 2007/03/22 16:08:17 steve Exp $"
21 #endif
23 # include "config.h"
25 # include "functor.h"
26 # include "netlist.h"
27 # include "netmisc.h"
28 # include "compiler.h"
29 # include <assert.h>
32 bool NetProc::synth_async(Design*des, NetScope*scope,
33 const NetBus&nex_map, NetBus&nex_out)
35 return false;
38 bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*ff,
39 const NetBus&nex_map, NetBus&nex_out,
40 const svector<NetEvProbe*>&events)
42 if (events.count() > 0) {
43 cerr << get_line() << ": error: Events are unaccounted"
44 << " for in process synthesis." << endl;
45 des->errors += 1;
48 /* Synthesize the input to the DFF. */
49 return synth_async(des, scope, nex_map, nex_out);
52 #if 0
53 static unsigned find_nexus_in_set(const NetBus&nset, const Nexus*nex)
55 unsigned idx = 0;
56 for (idx = 0 ; idx < nset.pin_count() ; idx += 1)
57 if (nset.pin(idx).nexus() == nex)
58 return idx;
60 return idx;
62 #endif
65 * Async synthesis of assignments is done by synthesizing the rvalue
66 * expression, then connecting the l-value directly to the output of
67 * the r-value.
69 * The nex_map is the O-set for the statement, and lists the positions
70 * of the outputs as the caller wants results linked up. The nex_out,
71 * however, is the set of nexa that are to actually get linked to the
72 * r-value.
74 bool NetAssignBase::synth_async(Design*des, NetScope*scope,
75 const NetBus&nex_map, NetBus&nex_out)
77 NetNet*rsig = rval_->synthesize(des);
78 assert(rsig);
80 NetNet*lsig = lval_->sig();
81 if (!lsig) {
82 cerr << get_line() << ": error: "
83 << "NetAssignBase::synth_async on unsupported lval ";
84 dump_lval(cerr);
85 cerr << endl;
86 des->errors += 1;
87 return false;
89 assert(lval_->more == 0);
91 if (debug_synth2) {
92 cerr << get_line() << ": debug: l-value signal is "
93 << lsig->vector_width() << " bits, r-value signal is "
94 << rsig->vector_width() << " bits." << endl;
97 #if 0
98 /* The l-value and r-value map must have the same width. */
99 if (lval_->lwidth() != nex_map->vector_width()) {
100 cerr << get_line() << ": error: Assignment synthesis: "
101 << "vector width mismatch, "
102 << lval_->lwidth() << " bits != "
103 << nex_map->vector_width() << " bits." << endl;
104 return false;
106 #else
107 /* For now, assume there is exactly one output. */
108 assert(nex_out.pin_count() == 1);
109 #endif
111 connect(nex_out.pin(0), rsig->pin(0));
113 /* This lval_ represents a reg that is a WIRE in the
114 synthesized results. This function signals the destructor
115 to change the REG that this l-value refers to into a
116 WIRE. It is done then, at the last minute, so that pending
117 synthesis can continue to work with it as a WIRE. */
118 lval_->turn_sig_to_wire_on_release();
120 return true;
124 * Sequential blocks are translated to asynchronous logic by
125 * translating each statement of the block, in order, into gates. The
126 * nex_out for the block is the union of the nex_out for all the
127 * substatements.
129 bool NetBlock::synth_async(Design*des, NetScope*scope,
130 const NetBus&nex_map, NetBus&nex_out)
132 if (last_ == 0) {
133 return true;
136 bool flag = true;
137 NetProc*cur = last_;
138 do {
139 cur = cur->next_;
141 /* Create a temporary map of the output only from this
142 statement. */
143 NexusSet tmp_set;
144 cur->nex_output(tmp_set);
145 NetBus tmp_map (scope, tmp_set.count());
146 for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1)
147 connect(tmp_set[idx], tmp_map.pin(idx));
149 /* Create also a temporary NetBus to collect the
150 output from the synthesis. */
151 NetBus tmp_out (scope, tmp_set.count());
153 bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out);
155 flag = flag && ok_flag;
156 if (ok_flag == false)
157 continue;
159 /* Now find the tmp_map pins in the nex_map global map,
160 and use that to direct the connection to the nex_out
161 output bus. Look for the nex_map pin that is linked
162 to the tmp_map.pin(idx) pin, and link that to the
163 tmp_out.pin(idx) output link. */
164 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
165 unsigned ptr = 0;
166 while (ptr < nex_map.pin_count()
167 && ! nex_map.pin(ptr).is_linked(tmp_map.pin(idx)))
168 ptr += 1;
170 assert(ptr < nex_out.pin_count());
171 connect(nex_out.pin(ptr), tmp_out.pin(idx));
174 } while (cur != last_);
176 return flag;
179 bool NetCase::synth_async(Design*des, NetScope*scope,
180 const NetBus&nex_map, NetBus&nex_out)
182 /* Synthesize the select expression. */
183 NetNet*esig = expr_->synthesize(des);
185 unsigned sel_width = esig->vector_width();
186 assert(sel_width > 0);
188 unsigned mux_width = 0;
189 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
190 mux_width += nex_out.pin(idx).nexus()->vector_width();
192 /* Collect all the statements into a map of index to
193 statement. The guard expression it evaluated to be the
194 index of the mux value, and the statement is bound to that
195 index. */
197 unsigned long max_guard_value = 0;
198 map<unsigned long,NetProc*>statement_map;
199 NetProc*statement_default = 0;
201 for (unsigned item = 0 ; item < nitems_ ; item += 1) {
202 if (items_[item].guard == 0) {
203 statement_default = items_[item].statement;
204 continue;
207 NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
208 assert(ge);
209 verinum gval = ge->value();
211 unsigned sel_idx = gval.as_ulong();
213 assert(items_[item].statement);
214 statement_map[sel_idx] = items_[item].statement;
216 if (sel_idx > max_guard_value)
217 max_guard_value = sel_idx;
220 unsigned mux_size = max_guard_value + 1;
222 NetMux*mux = new NetMux(scope, scope->local_symbol(),
223 mux_width, mux_size, sel_width);
224 des->add_node(mux);
226 /* The select signal is already synthesized. Simply hook it up. */
227 connect(mux->pin_Sel(), esig->pin(0));
229 /* For now, assume that the output is only 1 signal. */
230 assert(nex_out.pin_count() == 1);
231 connect(mux->pin_Result(), nex_out.pin(0));
233 /* For now, only support logic types. */
234 ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
236 /* Forgot to support default statements? */
237 assert(statement_default == 0);
239 NetNet*isig;
240 for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
242 NetProc*stmt = statement_map[idx];
243 if (stmt == 0) {
244 cerr << get_line() << ": error: case " << idx
245 << " is not accounted for in asynchronous mux." << endl;
246 des->errors += 1;
247 continue;
250 isig = new NetNet(scope, scope->local_symbol(),
251 NetNet::TRI, mux_width);
252 isig->local_flag(true);
253 isig->data_type(mux_data_type);
255 connect(mux->pin_Data(idx), isig->pin(0));
257 NetBus tmp (scope, 1);
258 connect(tmp.pin(0), isig->pin(0));
259 stmt->synth_async(des, scope, tmp, tmp);
262 return true;
265 bool NetCondit::synth_async(Design*des, NetScope*scope,
266 const NetBus&nex_map, NetBus&nex_out)
268 #if 0
269 NetNet*ssig = expr_->synthesize(des);
270 assert(ssig);
272 if (if_ == 0) {
273 DEBUG_SYNTH2_EXIT("NetCondit",false)
274 return false;
276 if (else_ == 0) {
277 cerr << get_line() << ": error: Asynchronous if statement"
278 << " is missing the else clause." << endl;
279 DEBUG_SYNTH2_EXIT("NetCondit",false)
280 return false;
283 assert(if_ != 0);
284 assert(else_ != 0);
286 NetNet*asig = new NetNet(scope, scope->local_symbol(),
287 NetNet::WIRE, nex_map->pin_count());
288 asig->local_flag(true);
290 bool flag;
291 flag = if_->synth_async(des, scope, nex_map, asig);
292 if (!flag) {
293 delete asig;
294 DEBUG_SYNTH2_EXIT("NetCondit",false)
295 return false;
298 NetNet*bsig = new NetNet(scope, scope->local_symbol(),
299 NetNet::WIRE, nex_map->pin_count());
300 bsig->local_flag(true);
302 flag = else_->synth_async(des, scope, nex_map, bsig);
303 if (!flag) {
304 delete asig;
305 delete bsig;
306 DEBUG_SYNTH2_EXIT("NetCondit",false)
307 return false;
310 NetMux*mux = new NetMux(scope, scope->local_symbol(),
311 nex_out->vector_width(), 2, 1);
313 connect(mux->pin_Sel(), ssig->pin(0));
314 connect(mux->pin_Data(1), asig->pin(0));
315 connect(mux->pin_Data(0), bsig->pin(0));
316 connect(nex_out->pin(0), mux->pin_Result());
318 des->add_node(mux);
320 DEBUG_SYNTH2_EXIT("NetCondit",true)
321 return true;
323 #else
324 cerr << get_line() << ": sorry: "
325 << "Forgot to implement NetCondit::synth_async" << endl;
326 des->errors += 1;
327 return false;
328 #endif
331 bool NetEvWait::synth_async(Design*des, NetScope*scope,
332 const NetBus&nex_map, NetBus&nex_out)
334 bool flag = statement_->synth_async(des, scope, nex_map, nex_out);
335 return flag;
339 * This method is called when the process is shown to be
340 * asynchronous. Figure out the nexus set of outputs from this
341 * process, and pass that to the synth_async method for the statement
342 * of the process. The statement will connect its output to the
343 * nex_out set, using the nex_map as a guide. Starting from the top,
344 * the nex_map is the same as the nex_map.
346 bool NetProcTop::synth_async(Design*des)
348 NexusSet nex_set;
349 statement_->nex_output(nex_set);
351 if (debug_synth2) {
352 cerr << get_line() << ": debug: Process has "
353 << nex_set.count() << " outputs." << endl;
356 NetBus nex_q (scope(), nex_set.count());
357 for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
358 connect(nex_set[idx], nex_q.pin(idx));
361 bool flag = statement_->synth_async(des, scope(), nex_q, nex_q);
362 return flag;
366 * This method is called when a block is encountered near the surface
367 * of a synchronous always statement. For example, this code will be
368 * invoked for input like this:
370 * always @(posedge clk...) begin
371 * <statement1>
372 * <statement2>
373 * ...
374 * end
376 * This needs to be split into a DFF bank for each statement, because
377 * the statements may each infer different reset and enable signals.
379 bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff,
380 const NetBus&nex_map, NetBus&nex_out,
381 const svector<NetEvProbe*>&events_in)
383 if (last_ == 0) {
384 return true;
387 #if 0
388 bool flag = true;
390 const perm_string tmp1 = perm_string::literal("tmp1");
391 const perm_string tmp2 = perm_string::literal("tmp2");
393 /* Keep an accounting of which statement accounts for which
394 bit slice of the FF bank. This is used for error checking. */
395 NetProc**pin_accounting = new NetProc* [ff->pin_count()];
396 for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
397 pin_accounting[idx] = 0;
399 NetProc*cur = last_;
400 do {
401 cur = cur->next_;
403 /* Create a temporary nex_map for the substatement. */
404 NexusSet tmp_set;
405 cur->nex_output(tmp_set);
406 NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE,
407 tmp_set.count());
408 for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
409 connect(tmp_set[idx], tmp_map->pin(idx));
411 /* NOTE: After this point, tmp_set should not be used as
412 the various functions I call do a lot of connecting,
413 and the nexa in the tmp_set may get realloced. Use
414 the tmp_map instead. */
416 /* Create also a temporary net_out to collect the
417 output. The tmp1 and tmp2 map and out sets together
418 are used to collect the outputs from the substatement
419 for the inputs of the FF bank. */
420 NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE,
421 tmp_map->pin_count());
423 verinum tmp_aset = ff->aset_value();
424 verinum tmp_sset = ff->sset_value();
426 /* Create a new DFF to handle this part of the begin-end
427 block. Connect this NetFF to the associated pins of
428 the existing wide NetFF device. While I'm at it, also
429 copy the aset_value bits for the new ff device. */
430 NetFF*ff2 = new NetFF(scope, scope->local_symbol(),
431 tmp_out->pin_count());
432 des->add_node(ff2);
434 verinum aset_value2 (verinum::V1, ff2->width());
435 verinum sset_value2 (verinum::V1, ff2->width());
436 for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
437 unsigned ptr = find_nexus_in_set(nex_map,
438 tmp_map->pin(idx).nexus());
440 /* Connect Data and Q bits to the new FF. */
441 connect(ff->pin_Data(ptr), ff2->pin_Data(idx));
442 connect(ff->pin_Q(ptr), ff2->pin_Q(idx));
444 /* Copy the asynch set bit to the new device. */
445 if (ptr < tmp_aset.len())
446 aset_value2.set(idx, tmp_aset[ptr]);
448 /* Copy the synch set bit to the new device. */
449 if (ptr < tmp_sset.len())
450 sset_value2.set(idx, tmp_sset[ptr]);
452 if (pin_accounting[ptr] != 0) {
453 cerr << cur->get_line() << ": error: "
454 << "Synchronous output conflicts with "
455 << pin_accounting[ptr]->get_line()
456 << "." << endl;
457 flag = false;
459 } else {
460 pin_accounting[ptr] = cur;
464 if (ff->pin_Aclr().is_linked())
465 connect(ff->pin_Aclr(), ff2->pin_Aclr());
466 if (ff->pin_Aset().is_linked())
467 connect(ff->pin_Aset(), ff2->pin_Aset());
468 if (ff->pin_Sclr().is_linked())
469 connect(ff->pin_Sclr(), ff2->pin_Sclr());
470 if (ff->pin_Sset().is_linked())
471 connect(ff->pin_Sset(), ff2->pin_Sset());
472 if (ff->pin_Clock().is_linked())
473 connect(ff->pin_Clock(), ff2->pin_Clock());
474 if (ff->pin_Enable().is_linked())
475 connect(ff->pin_Enable(),ff2->pin_Enable());
477 /* Remember to store the aset value into the new FF. If
478 this leads to an Aset value of 0 (and Aclr is not
479 otherwise used) then move the Aset input to Aclr. */
480 if (tmp_aset.len() == ff->width()) {
482 if (aset_value2.is_zero()
483 && ff2->pin_Aset().is_linked()
484 && !ff2->pin_Aclr().is_linked()) {
486 connect(ff2->pin_Aclr(), ff2->pin_Aset());
487 ff2->pin_Aset().unlink();
489 } else {
490 ff2->aset_value(aset_value2);
494 /* Now go on with the synchronous synthesis for this
495 subset of the statement. The tmp_map is the output
496 nexa that we expect, and the tmp_out is where we want
497 those outputs connected. */
498 bool ok_flag = cur->synth_sync(des, scope, ff2, tmp_map,
499 tmp_out, events_in);
500 flag = flag && ok_flag;
502 if (ok_flag == false)
503 continue;
505 /* Use the nex_map to link up the output from the
506 substatement to the output of the block as a
507 whole. It is occasionally possible to have outputs
508 beyond the input set, for example when the l-value of
509 an assignment is smaller then the r-value. */
510 for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
511 unsigned ptr = find_nexus_in_set(nex_map,
512 tmp_map->pin(idx).nexus());
514 if (ptr < nex_out->pin_count())
515 connect(nex_out->pin(ptr), tmp_out->pin(idx));
518 delete tmp_map;
519 delete tmp_out;
521 } while (cur != last_);
523 delete[]pin_accounting;
525 /* Done. The large NetFF is no longer needed, as it has been
526 taken up by the smaller NetFF devices. */
527 delete ff;
529 return flag;
531 #else
532 cerr << get_line() << ": sorry: "
533 << "Forgot to implement NetBlock::synth_sync"
534 << endl;
535 des->errors += 1;
536 return false;
537 #endif
541 * This method handles the case where I find a conditional near the
542 * surface of a synchronous thread. This conditional can be a CE or an
543 * asynchronous set/reset, depending on whether the pin of the
544 * expression is connected to an event, or not.
546 bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
547 const NetBus&nex_map, NetBus&nex_out,
548 const svector<NetEvProbe*>&events_in)
550 #if 0
551 /* First try to turn the condition expression into an
552 asynchronous set/reset. If the condition expression has
553 inputs that are included in the sensitivity list, then it
554 is likely intended as an asynchronous input. */
556 NexusSet*expr_input = expr_->nex_input();
557 assert(expr_input);
558 for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) {
560 NetEvProbe*ev = events_in[idx];
561 NexusSet pin_set;
562 pin_set.add(ev->pin(0).nexus());
564 if (! expr_input->contains(pin_set))
565 continue;
567 /* Ah, this edge is in the sensitivity list for the
568 expression, so we have an asynchronous
569 input. Synthesize the set/reset input expression. */
571 NetNet*rst = expr_->synthesize(des);
572 assert(rst->pin_count() == 1);
574 /* XXXX I really should find a way to check that the
575 edge used on the reset input is correct. This would
576 involve interpreting the exression that is fed by the
577 reset expression. */
578 //assert(ev->edge() == NetEvProbe::POSEDGE);
580 /* Synthesize the true clause to figure out what
581 kind of set/reset we have. */
582 NetNet*asig = new NetNet(scope, scope->local_symbol(),
583 NetNet::WIRE, nex_map->pin_count());
584 asig->local_flag(true);
586 assert(if_ != 0);
587 bool flag = if_->synth_async(des, scope, nex_map, asig);
589 assert(asig->pin_count() == ff->width());
591 /* Collect the set/reset value into a verinum. If
592 this turns out to be entirely 0 values, then
593 use the Aclr input. Otherwise, use the Aset
594 input and save the set value. */
595 verinum tmp (verinum::V0, ff->width());
596 for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
598 assert(asig->pin(bit).nexus()->drivers_constant());
599 tmp.set(bit, asig->pin(bit).nexus()->driven_value());
602 assert(tmp.is_defined());
603 if (tmp.is_zero()) {
604 connect(ff->pin_Aclr(), rst->pin(0));
606 } else {
607 connect(ff->pin_Aset(), rst->pin(0));
608 ff->aset_value(tmp);
611 delete asig;
612 delete expr_input;
614 assert(events_in.count() == 1);
615 assert(else_ != 0);
616 flag = else_->synth_sync(des, scope, ff, nex_map,
617 nex_out, svector<NetEvProbe*>(0))
618 && flag;
619 DEBUG_SYNTH2_EXIT("NetCondit",flag)
620 return flag;
623 delete expr_input;
625 /* Detect the case that this is a *synchronous* set/reset. It
626 is not asyncronous because we know the condition is not
627 included in the sensitivity list, but if the if_ case is
628 constant (has no inputs) then we can model this as a
629 synchronous set/reset.
631 This is only synchronous set/reset if there is a true and a
632 false clause, and no inputs. The "no inputs" requirement is
633 met if the assignments are of all constant values. */
634 assert(if_ != 0);
635 NexusSet*a_set = if_->nex_input();
637 if ((a_set->count() == 0) && if_ && else_) {
639 NetNet*rst = expr_->synthesize(des);
640 assert(rst->pin_count() == 1);
642 /* Synthesize the true clause to figure out what
643 kind of set/reset we have. */
644 NetNet*asig = new NetNet(scope, scope->local_symbol(),
645 NetNet::WIRE, nex_map->pin_count());
646 asig->local_flag(true);
647 bool flag = if_->synth_async(des, scope, nex_map, asig);
649 if (!flag) {
650 /* This path leads nowhere */
651 delete asig;
652 } else {
653 assert(asig->pin_count() == ff->width());
655 /* Collect the set/reset value into a verinum. If
656 this turns out to be entirely 0 values, then
657 use the Sclr input. Otherwise, use the Aset
658 input and save the set value. */
659 verinum tmp (verinum::V0, ff->width());
660 for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
662 assert(asig->pin(bit).nexus()->drivers_constant());
663 tmp.set(bit, asig->pin(bit).nexus()->driven_value());
666 assert(tmp.is_defined());
667 if (tmp.is_zero()) {
668 connect(ff->pin_Sclr(), rst->pin(0));
670 } else {
671 connect(ff->pin_Sset(), rst->pin(0));
672 ff->sset_value(tmp);
675 delete a_set;
677 assert(else_ != 0);
678 flag = else_->synth_sync(des, scope, ff, nex_map,
679 nex_out, svector<NetEvProbe*>(0))
680 && flag;
681 DEBUG_SYNTH2_EXIT("NetCondit",flag)
682 return flag;
686 delete a_set;
688 /* Failed to find an asynchronous set/reset, so any events
689 input are probably in error. */
690 if (events_in.count() > 0) {
691 cerr << get_line() << ": error: Events are unaccounted"
692 << " for in process synthesis." << endl;
693 des->errors += 1;
697 /* If this is an if/then/else, then it is likely a
698 combinational if, and I should synthesize it that way. */
699 if (if_ && else_) {
700 bool flag = synth_async(des, scope, nex_map, nex_out);
701 DEBUG_SYNTH2_EXIT("NetCondit",flag)
702 return flag;
705 assert(if_);
706 assert(!else_);
708 /* Synthesize the enable expression. */
709 NetNet*ce = expr_->synthesize(des);
710 assert(ce->pin_count() == 1);
712 /* What's left, is a synchronous CE statement like this:
714 if (expr_) <true statement>;
716 The expr_ expression has already been synthesized to the ce
717 net, so we connect it here to the FF. What's left is to
718 synthesize the substatement as a combinational
719 statement.
721 Watch out for the special case that there is already a CE
722 connected to this FF. This can be caused by code like this:
724 if (a) if (b) <statement>;
726 In this case, we are working on the inner IF, so we AND the
727 a and b expressions to make a new CE. */
729 if (ff->pin_Enable().is_linked()) {
730 NetLogic*ce_and = new NetLogic(scope,
731 scope->local_symbol(), 3,
732 NetLogic::AND, 1);
733 des->add_node(ce_and);
734 connect(ff->pin_Enable(), ce_and->pin(1));
735 connect(ce->pin(0), ce_and->pin(2));
737 ff->pin_Enable().unlink();
738 connect(ff->pin_Enable(), ce_and->pin(0));
740 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
741 NetNet::IMPLICIT, 1);
742 tmp->local_flag(true);
743 connect(ff->pin_Enable(), tmp->pin(0));
745 } else {
747 connect(ff->pin_Enable(), ce->pin(0));
750 bool flag = if_->synth_sync(des, scope, ff, nex_map, nex_out, events_in);
752 return flag;
754 #else
755 cerr << get_line() << ": sorry: "
756 << "Forgot to implement NetCondit::synth_sync" << endl;
757 des->errors += 1;
758 return false;
759 #endif
762 bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
763 const NetBus&nex_map, NetBus&nex_out,
764 const svector<NetEvProbe*>&events_in)
766 if (events_in.count() > 0) {
767 cerr << get_line() << ": error: Events are unaccounted"
768 << " for in process synthesis." << endl;
769 des->errors += 1;
772 assert(events_in.count() == 0);
774 /* This can't be other than one unless there are named events,
775 which I cannot synthesize. */
776 assert(nevents_ == 1);
777 NetEvent*ev = events_[0];
779 assert(ev->nprobe() >= 1);
780 svector<NetEvProbe*>events (ev->nprobe() - 1);
782 /* Get the input set from the substatement. This will be used
783 to figure out which of the probes is the clock. */
784 NexusSet*statement_input = statement_ -> nex_input();
786 /* Search for a clock input. The clock input is the edge event
787 that is not also an input to the substatement. */
788 NetEvProbe*pclk = 0;
789 unsigned event_idx = 0;
790 for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) {
791 NetEvProbe*tmp = ev->probe(idx);
792 assert(tmp->pin_count() == 1);
794 NexusSet tmp_nex;
795 tmp_nex .add( tmp->pin(0).nexus() );
797 if (! statement_input ->contains(tmp_nex)) {
798 if (pclk != 0) {
799 cerr << get_line() << ": error: Too many "
800 << "clocks for synchronous logic." << endl;
801 cerr << get_line() << ": : Perhaps an"
802 << " asynchronous set/reset is misused?" << endl;
803 des->errors += 1;
805 pclk = tmp;
807 } else {
808 events[event_idx++] = tmp;
812 if (pclk == 0) {
813 cerr << get_line() << ": error: None of the edges"
814 << " are valid clock inputs." << endl;
815 cerr << get_line() << ": : Perhaps the clock"
816 << " is read by a statement or expression?" << endl;
817 return false;
820 connect(ff->pin_Clock(), pclk->pin(0));
821 if (pclk->edge() == NetEvProbe::NEGEDGE) {
822 perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
823 ff->attribute(polarity, verinum("INVERT"));
825 if (debug_synth2) {
826 cerr << get_line() << ": debug: "
827 << "Detected a NEGEDGE clock for the synthesized ff."
828 << endl;
832 /* Synthesize the input to the DFF. */
833 bool flag = statement_->synth_sync(des, scope, ff,
834 nex_map, nex_out, events);
836 return flag;
840 * This method is called for a process that is determined to be
841 * synchronous. Create a NetFF device to hold the output from the
842 * statement, and synthesize that statement in place.
844 bool NetProcTop::synth_sync(Design*des)
846 if (debug_synth2) {
847 cerr << get_line() << ": debug: "
848 << "Process is apparently synchronous. Making NetFFs."
849 << endl;
852 NexusSet nex_set;
853 statement_->nex_output(nex_set);
855 /* Make a model FF that will connect to the first item in the
856 set, and will also take the initial connection of clocks
857 and resets. */
859 if (debug_synth2) {
860 cerr << get_line() << ": debug: "
861 << "Top level making a "
862 << nex_set[0]->vector_width() << "-wide "
863 << "NetFF device." << endl;
866 NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
867 nex_set[0]->vector_width());
868 des->add_node(ff);
869 ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF"));
871 NetBus nex_d (scope(), nex_set.count());
872 NetBus nex_q (scope(), nex_set.count());
874 /* The Q of the NetFF devices is connected to the output that
875 we are. The nex_q is a bundle of the outputs. We will also
876 pass the nex_q as a map to the statement's synth_sync
877 method to map it to the correct nex_d pin. */
878 for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
879 connect(nex_set[idx], nex_q.pin(idx));
882 // Connect the input later.
884 /* Synthesize the input to the DFF. */
885 bool flag = statement_->synth_sync(des, scope(), ff,
886 nex_q, nex_d,
887 svector<NetEvProbe*>());
888 if (! flag) {
889 delete ff;
890 return false;
894 NetNet*tmp = nex_d.pin(0).nexus()->pick_any_net();
895 assert(tmp);
897 tmp = crop_to_width(des, tmp, ff->width());
898 connect(tmp->pin(0), ff->pin_Data());
899 connect(nex_q.pin(0), ff->pin_Q());
901 for (unsigned idx = 1 ; idx < nex_set.count() ; idx += 1) {
902 NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
903 nex_set[idx]->vector_width());
904 des->add_node(ff2);
906 tmp = nex_d.pin(idx).nexus()->pick_any_net();
907 assert(tmp);
909 tmp = crop_to_width(des, tmp, ff2->width());
911 connect(nex_q.pin(idx), ff2->pin_Q());
912 connect(tmp->pin(0), ff2->pin_Data());
914 connect(ff->pin_Clock(), ff2->pin_Clock());
915 if (ff->pin_Enable().is_linked())
916 connect(ff->pin_Enable(), ff2->pin_Enable());
917 if (ff->pin_Aset().is_linked())
918 connect(ff->pin_Aset(), ff2->pin_Aset());
919 if (ff->pin_Aclr().is_linked())
920 connect(ff->pin_Aclr(), ff2->pin_Aclr());
921 if (ff->pin_Sset().is_linked())
922 connect(ff->pin_Sset(), ff2->pin_Sset());
923 if (ff->pin_Sclr().is_linked())
924 connect(ff->pin_Sclr(), ff2->pin_Sclr());
927 return true;
930 class synth2_f : public functor_t {
932 public:
933 void process(class Design*, class NetProcTop*);
935 private:
940 * Look at a process. If it is asynchronous, then synthesize it as an
941 * asynchronous process and delete the process itself for its gates.
943 void synth2_f::process(class Design*des, class NetProcTop*top)
945 if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
946 return;
948 /* If the scope that contains this process as a cell attribute
949 attached to it, then skip synthesis. */
950 if (top->scope()->attribute(perm_string::literal("ivl_synthesis_cell")).len() > 0)
951 return;
953 if (top->is_synchronous()) do {
954 bool flag = top->synth_sync(des);
955 if (! flag) {
956 cerr << top->get_line() << ": error: "
957 << "Unable to synthesize synchronous process." << endl;
958 des->errors += 1;
959 return;
961 des->delete_process(top);
962 return;
963 } while (0);
965 if (! top->is_asynchronous()) {
966 bool synth_error_flag = false;
967 if (top->attribute(perm_string::literal("ivl_combinational")).as_ulong() != 0) {
968 cerr << top->get_line() << ": error: "
969 << "Process is marked combinational,"
970 << " but isn't really." << endl;
971 des->errors += 1;
972 synth_error_flag = true;
975 if (top->attribute(perm_string::literal("ivl_synthesis_on")).as_ulong() != 0) {
976 cerr << top->get_line() << ": error: "
977 << "Process is marked for synthesis,"
978 << " but I can't do it." << endl;
979 des->errors += 1;
980 synth_error_flag = true;
983 if (! synth_error_flag)
984 cerr << top->get_line() << ": warning: "
985 << "Process not synthesized." << endl;
987 return;
990 if (! top->synth_async(des)) {
991 cerr << top->get_line() << ": internal error: "
992 << "is_asynchronous does not match "
993 << "sync_async results." << endl;
994 des->errors += 1;
995 return;
998 des->delete_process(top);
1001 void synth2(Design*des)
1003 synth2_f synth_obj;
1004 des->functor(&synth_obj);