Reformulate number-to-real on vvp code generator
[iverilog.git] / synth2.cc
blobbc7f4a49d904675bec3eb6c67968ba1248a40940
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 return false;
88 assert(lval_->more == 0);
90 if (debug_synth2) {
91 cerr << get_line() << ": debug: l-value signal is "
92 << lsig->vector_width() << " bits, r-value signal is "
93 << rsig->vector_width() << " bits." << endl;
96 #if 0
97 /* The l-value and r-value map must have the same width. */
98 if (lval_->lwidth() != nex_map->vector_width()) {
99 cerr << get_line() << ": error: Assignment synthesis: "
100 << "vector width mismatch, "
101 << lval_->lwidth() << " bits != "
102 << nex_map->vector_width() << " bits." << endl;
103 return false;
105 #else
106 /* For now, assume there is exactly one output. */
107 assert(nex_out.pin_count() == 1);
108 #endif
110 connect(nex_out.pin(0), rsig->pin(0));
112 /* This lval_ represents a reg that is a WIRE in the
113 synthesized results. This function signals the destructor
114 to change the REG that this l-value refers to into a
115 WIRE. It is done then, at the last minute, so that pending
116 synthesis can continue to work with it as a WIRE. */
117 lval_->turn_sig_to_wire_on_release();
119 return true;
123 * Sequential blocks are translated to asynchronous logic by
124 * translating each statement of the block, in order, into gates. The
125 * nex_out for the block is the union of the nex_out for all the
126 * substatements.
128 bool NetBlock::synth_async(Design*des, NetScope*scope,
129 const NetBus&nex_map, NetBus&nex_out)
131 if (last_ == 0) {
132 return true;
135 bool flag = true;
136 NetProc*cur = last_;
137 do {
138 cur = cur->next_;
140 /* Create a temporary map of the output only from this
141 statement. */
142 NexusSet tmp_set;
143 cur->nex_output(tmp_set);
144 NetBus tmp_map (scope, tmp_set.count());
145 for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1)
146 connect(tmp_set[idx], tmp_map.pin(idx));
148 /* Create also a temporary NetBus to collect the
149 output from the synthesis. */
150 NetBus tmp_out (scope, tmp_set.count());
152 bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out);
154 flag = flag && ok_flag;
155 if (ok_flag == false)
156 continue;
158 /* Now find the tmp_map pins in the nex_map global map,
159 and use that to direct the connection to the nex_out
160 output bus. Look for the nex_map pin that is linked
161 to the tmp_map.pin(idx) pin, and link that to the
162 tmp_out.pin(idx) output link. */
163 for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
164 unsigned ptr = 0;
165 while (ptr < nex_map.pin_count()
166 && ! nex_map.pin(ptr).is_linked(tmp_map.pin(idx)))
167 ptr += 1;
169 assert(ptr < nex_out.pin_count());
170 connect(nex_out.pin(ptr), tmp_out.pin(idx));
173 } while (cur != last_);
175 return flag;
178 bool NetCase::synth_async(Design*des, NetScope*scope,
179 const NetBus&nex_map, NetBus&nex_out)
181 /* Synthesize the select expression. */
182 NetNet*esig = expr_->synthesize(des);
184 unsigned sel_width = esig->vector_width();
185 assert(sel_width > 0);
187 unsigned mux_width = 0;
188 for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
189 mux_width += nex_out.pin(idx).nexus()->vector_width();
191 /* Collect all the statements into a map of index to
192 statement. The guard expression it evaluated to be the
193 index of the mux value, and the statement is bound to that
194 index. */
196 unsigned long max_guard_value = 0;
197 map<unsigned long,NetProc*>statement_map;
198 NetProc*statement_default = 0;
200 for (unsigned item = 0 ; item < nitems_ ; item += 1) {
201 if (items_[item].guard == 0) {
202 statement_default = items_[item].statement;
203 continue;
206 NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
207 assert(ge);
208 verinum gval = ge->value();
210 unsigned sel_idx = gval.as_ulong();
212 assert(items_[item].statement);
213 statement_map[sel_idx] = items_[item].statement;
215 if (sel_idx > max_guard_value)
216 max_guard_value = sel_idx;
219 unsigned mux_size = max_guard_value + 1;
221 NetMux*mux = new NetMux(scope, scope->local_symbol(),
222 mux_width, mux_size, sel_width);
223 des->add_node(mux);
225 /* The select signal is already synthesized. Simply hook it up. */
226 connect(mux->pin_Sel(), esig->pin(0));
228 /* For now, assume that the output is only 1 signal. */
229 assert(nex_out.pin_count() == 1);
230 connect(mux->pin_Result(), nex_out.pin(0));
232 /* For now, only support logic types. */
233 ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
235 /* Forgot to support default statements? */
236 assert(statement_default == 0);
238 NetNet*isig;
239 for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
241 NetProc*stmt = statement_map[idx];
242 if (stmt == 0) {
243 cerr << get_line() << ": error: case " << idx
244 << " is not accounted for in asynchronous mux." << endl;
245 continue;
248 isig = new NetNet(scope, scope->local_symbol(),
249 NetNet::TRI, mux_width);
250 isig->local_flag(true);
251 isig->data_type(mux_data_type);
253 connect(mux->pin_Data(idx), isig->pin(0));
255 NetBus tmp (scope, 1);
256 connect(tmp.pin(0), isig->pin(0));
257 stmt->synth_async(des, scope, tmp, tmp);
260 return true;
263 bool NetCondit::synth_async(Design*des, NetScope*scope,
264 const NetBus&nex_map, NetBus&nex_out)
266 #if 0
267 NetNet*ssig = expr_->synthesize(des);
268 assert(ssig);
270 if (if_ == 0) {
271 DEBUG_SYNTH2_EXIT("NetCondit",false)
272 return false;
274 if (else_ == 0) {
275 cerr << get_line() << ": error: Asynchronous if statement"
276 << " is missing the else clause." << endl;
277 DEBUG_SYNTH2_EXIT("NetCondit",false)
278 return false;
281 assert(if_ != 0);
282 assert(else_ != 0);
284 NetNet*asig = new NetNet(scope, scope->local_symbol(),
285 NetNet::WIRE, nex_map->pin_count());
286 asig->local_flag(true);
288 bool flag;
289 flag = if_->synth_async(des, scope, nex_map, asig);
290 if (!flag) {
291 delete asig;
292 DEBUG_SYNTH2_EXIT("NetCondit",false)
293 return false;
296 NetNet*bsig = new NetNet(scope, scope->local_symbol(),
297 NetNet::WIRE, nex_map->pin_count());
298 bsig->local_flag(true);
300 flag = else_->synth_async(des, scope, nex_map, bsig);
301 if (!flag) {
302 delete asig;
303 delete bsig;
304 DEBUG_SYNTH2_EXIT("NetCondit",false)
305 return false;
308 NetMux*mux = new NetMux(scope, scope->local_symbol(),
309 nex_out->vector_width(), 2, 1);
311 connect(mux->pin_Sel(), ssig->pin(0));
312 connect(mux->pin_Data(1), asig->pin(0));
313 connect(mux->pin_Data(0), bsig->pin(0));
314 connect(nex_out->pin(0), mux->pin_Result());
316 des->add_node(mux);
318 DEBUG_SYNTH2_EXIT("NetCondit",true)
319 return true;
321 #else
322 cerr << get_line() << ": sorry: "
323 << "Forgot to implement NetCondit::synth_async" << endl;
324 return false;
325 #endif
328 bool NetEvWait::synth_async(Design*des, NetScope*scope,
329 const NetBus&nex_map, NetBus&nex_out)
331 bool flag = statement_->synth_async(des, scope, nex_map, nex_out);
332 return flag;
336 * This method is called when the process is shown to be
337 * asynchronous. Figure out the nexus set of outputs from this
338 * process, and pass that to the synth_async method for the statement
339 * of the process. The statement will connect its output to the
340 * nex_out set, using the nex_map as a guide. Starting from the top,
341 * the nex_map is the same as the nex_map.
343 bool NetProcTop::synth_async(Design*des)
345 NexusSet nex_set;
346 statement_->nex_output(nex_set);
348 if (debug_synth2) {
349 cerr << get_line() << ": debug: Process has "
350 << nex_set.count() << " outputs." << endl;
353 NetBus nex_q (scope(), nex_set.count());
354 for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
355 connect(nex_set[idx], nex_q.pin(idx));
358 bool flag = statement_->synth_async(des, scope(), nex_q, nex_q);
359 return flag;
363 * This method is called when a block is encountered near the surface
364 * of a synchronous always statement. For example, this code will be
365 * invoked for input like this:
367 * always @(posedge clk...) begin
368 * <statement1>
369 * <statement2>
370 * ...
371 * end
373 * This needs to be split into a DFF bank for each statement, because
374 * the statements may each infer different reset and enable signals.
376 bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff,
377 const NetBus&nex_map, NetBus&nex_out,
378 const svector<NetEvProbe*>&events_in)
380 if (last_ == 0) {
381 return true;
384 #if 0
385 bool flag = true;
387 const perm_string tmp1 = perm_string::literal("tmp1");
388 const perm_string tmp2 = perm_string::literal("tmp2");
390 /* Keep an accounting of which statement accounts for which
391 bit slice of the FF bank. This is used for error checking. */
392 NetProc**pin_accounting = new NetProc* [ff->pin_count()];
393 for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
394 pin_accounting[idx] = 0;
396 NetProc*cur = last_;
397 do {
398 cur = cur->next_;
400 /* Create a temporary nex_map for the substatement. */
401 NexusSet tmp_set;
402 cur->nex_output(tmp_set);
403 NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE,
404 tmp_set.count());
405 for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
406 connect(tmp_set[idx], tmp_map->pin(idx));
408 /* NOTE: After this point, tmp_set should not be used as
409 the various functions I call do a lot of connecting,
410 and the nexa in the tmp_set may get realloced. Use
411 the tmp_map instead. */
413 /* Create also a temporary net_out to collect the
414 output. The tmp1 and tmp2 map and out sets together
415 are used to collect the outputs from the substatement
416 for the inputs of the FF bank. */
417 NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE,
418 tmp_map->pin_count());
420 verinum tmp_aset = ff->aset_value();
421 verinum tmp_sset = ff->sset_value();
423 /* Create a new DFF to handle this part of the begin-end
424 block. Connect this NetFF to the associated pins of
425 the existing wide NetFF device. While I'm at it, also
426 copy the aset_value bits for the new ff device. */
427 NetFF*ff2 = new NetFF(scope, scope->local_symbol(),
428 tmp_out->pin_count());
429 des->add_node(ff2);
431 verinum aset_value2 (verinum::V1, ff2->width());
432 verinum sset_value2 (verinum::V1, ff2->width());
433 for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
434 unsigned ptr = find_nexus_in_set(nex_map,
435 tmp_map->pin(idx).nexus());
437 /* Connect Data and Q bits to the new FF. */
438 connect(ff->pin_Data(ptr), ff2->pin_Data(idx));
439 connect(ff->pin_Q(ptr), ff2->pin_Q(idx));
441 /* Copy the asynch set bit to the new device. */
442 if (ptr < tmp_aset.len())
443 aset_value2.set(idx, tmp_aset[ptr]);
445 /* Copy the synch set bit to the new device. */
446 if (ptr < tmp_sset.len())
447 sset_value2.set(idx, tmp_sset[ptr]);
449 if (pin_accounting[ptr] != 0) {
450 cerr << cur->get_line() << ": error: "
451 << "Synchronous output conflicts with "
452 << pin_accounting[ptr]->get_line()
453 << "." << endl;
454 flag = false;
456 } else {
457 pin_accounting[ptr] = cur;
461 if (ff->pin_Aclr().is_linked())
462 connect(ff->pin_Aclr(), ff2->pin_Aclr());
463 if (ff->pin_Aset().is_linked())
464 connect(ff->pin_Aset(), ff2->pin_Aset());
465 if (ff->pin_Sclr().is_linked())
466 connect(ff->pin_Sclr(), ff2->pin_Sclr());
467 if (ff->pin_Sset().is_linked())
468 connect(ff->pin_Sset(), ff2->pin_Sset());
469 if (ff->pin_Clock().is_linked())
470 connect(ff->pin_Clock(), ff2->pin_Clock());
471 if (ff->pin_Enable().is_linked())
472 connect(ff->pin_Enable(),ff2->pin_Enable());
474 /* Remember to store the aset value into the new FF. If
475 this leads to an Aset value of 0 (and Aclr is not
476 otherwise used) then move the Aset input to Aclr. */
477 if (tmp_aset.len() == ff->width()) {
479 if (aset_value2.is_zero()
480 && ff2->pin_Aset().is_linked()
481 && !ff2->pin_Aclr().is_linked()) {
483 connect(ff2->pin_Aclr(), ff2->pin_Aset());
484 ff2->pin_Aset().unlink();
486 } else {
487 ff2->aset_value(aset_value2);
491 /* Now go on with the synchronous synthesis for this
492 subset of the statement. The tmp_map is the output
493 nexa that we expect, and the tmp_out is where we want
494 those outputs connected. */
495 bool ok_flag = cur->synth_sync(des, scope, ff2, tmp_map,
496 tmp_out, events_in);
497 flag = flag && ok_flag;
499 if (ok_flag == false)
500 continue;
502 /* Use the nex_map to link up the output from the
503 substatement to the output of the block as a
504 whole. It is occasionally possible to have outputs
505 beyond the input set, for example when the l-value of
506 an assignment is smaller then the r-value. */
507 for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
508 unsigned ptr = find_nexus_in_set(nex_map,
509 tmp_map->pin(idx).nexus());
511 if (ptr < nex_out->pin_count())
512 connect(nex_out->pin(ptr), tmp_out->pin(idx));
515 delete tmp_map;
516 delete tmp_out;
518 } while (cur != last_);
520 delete[]pin_accounting;
522 /* Done. The large NetFF is no longer needed, as it has been
523 taken up by the smaller NetFF devices. */
524 delete ff;
526 return flag;
528 #else
529 cerr << get_line() << ": sorry: "
530 << "Forgot to implement NetBlock::synth_sync"
531 << endl;
532 return false;
533 #endif
537 * This method handles the case where I find a conditional near the
538 * surface of a synchronous thread. This conditional can be a CE or an
539 * asynchronous set/reset, depending on whether the pin of the
540 * expression is connected to an event, or not.
542 bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
543 const NetBus&nex_map, NetBus&nex_out,
544 const svector<NetEvProbe*>&events_in)
546 #if 0
547 /* First try to turn the condition expression into an
548 asynchronous set/reset. If the condition expression has
549 inputs that are included in the sensitivity list, then it
550 is likely intended as an asynchronous input. */
552 NexusSet*expr_input = expr_->nex_input();
553 assert(expr_input);
554 for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) {
556 NetEvProbe*ev = events_in[idx];
557 NexusSet pin_set;
558 pin_set.add(ev->pin(0).nexus());
560 if (! expr_input->contains(pin_set))
561 continue;
563 /* Ah, this edge is in the sensitivity list for the
564 expression, so we have an asynchronous
565 input. Synthesize the set/reset input expression. */
567 NetNet*rst = expr_->synthesize(des);
568 assert(rst->pin_count() == 1);
570 /* XXXX I really should find a way to check that the
571 edge used on the reset input is correct. This would
572 involve interpreting the exression that is fed by the
573 reset expression. */
574 //assert(ev->edge() == NetEvProbe::POSEDGE);
576 /* Synthesize the true clause to figure out what
577 kind of set/reset we have. */
578 NetNet*asig = new NetNet(scope, scope->local_symbol(),
579 NetNet::WIRE, nex_map->pin_count());
580 asig->local_flag(true);
582 assert(if_ != 0);
583 bool flag = if_->synth_async(des, scope, nex_map, asig);
585 assert(asig->pin_count() == ff->width());
587 /* Collect the set/reset value into a verinum. If
588 this turns out to be entirely 0 values, then
589 use the Aclr input. Otherwise, use the Aset
590 input and save the set value. */
591 verinum tmp (verinum::V0, ff->width());
592 for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
594 assert(asig->pin(bit).nexus()->drivers_constant());
595 tmp.set(bit, asig->pin(bit).nexus()->driven_value());
598 assert(tmp.is_defined());
599 if (tmp.is_zero()) {
600 connect(ff->pin_Aclr(), rst->pin(0));
602 } else {
603 connect(ff->pin_Aset(), rst->pin(0));
604 ff->aset_value(tmp);
607 delete asig;
608 delete expr_input;
610 assert(events_in.count() == 1);
611 assert(else_ != 0);
612 flag = else_->synth_sync(des, scope, ff, nex_map,
613 nex_out, svector<NetEvProbe*>(0))
614 && flag;
615 DEBUG_SYNTH2_EXIT("NetCondit",flag)
616 return flag;
619 delete expr_input;
621 /* Detect the case that this is a *synchronous* set/reset. It
622 is not asyncronous because we know the condition is not
623 included in the sensitivity list, but if the if_ case is
624 constant (has no inputs) then we can model this as a
625 synchronous set/reset.
627 This is only synchronous set/reset if there is a true and a
628 false clause, and no inputs. The "no inputs" requirement is
629 met if the assignments are of all constant values. */
630 assert(if_ != 0);
631 NexusSet*a_set = if_->nex_input();
633 if ((a_set->count() == 0) && if_ && else_) {
635 NetNet*rst = expr_->synthesize(des);
636 assert(rst->pin_count() == 1);
638 /* Synthesize the true clause to figure out what
639 kind of set/reset we have. */
640 NetNet*asig = new NetNet(scope, scope->local_symbol(),
641 NetNet::WIRE, nex_map->pin_count());
642 asig->local_flag(true);
643 bool flag = if_->synth_async(des, scope, nex_map, asig);
645 if (!flag) {
646 /* This path leads nowhere */
647 delete asig;
648 } else {
649 assert(asig->pin_count() == ff->width());
651 /* Collect the set/reset value into a verinum. If
652 this turns out to be entirely 0 values, then
653 use the Sclr input. Otherwise, use the Aset
654 input and save the set value. */
655 verinum tmp (verinum::V0, ff->width());
656 for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
658 assert(asig->pin(bit).nexus()->drivers_constant());
659 tmp.set(bit, asig->pin(bit).nexus()->driven_value());
662 assert(tmp.is_defined());
663 if (tmp.is_zero()) {
664 connect(ff->pin_Sclr(), rst->pin(0));
666 } else {
667 connect(ff->pin_Sset(), rst->pin(0));
668 ff->sset_value(tmp);
671 delete a_set;
673 assert(else_ != 0);
674 flag = else_->synth_sync(des, scope, ff, nex_map,
675 nex_out, svector<NetEvProbe*>(0))
676 && flag;
677 DEBUG_SYNTH2_EXIT("NetCondit",flag)
678 return flag;
682 delete a_set;
684 /* Failed to find an asynchronous set/reset, so any events
685 input are probably in error. */
686 if (events_in.count() > 0) {
687 cerr << get_line() << ": error: Events are unaccounted"
688 << " for in process synthesis." << endl;
689 des->errors += 1;
693 /* If this is an if/then/else, then it is likely a
694 combinational if, and I should synthesize it that way. */
695 if (if_ && else_) {
696 bool flag = synth_async(des, scope, nex_map, nex_out);
697 DEBUG_SYNTH2_EXIT("NetCondit",flag)
698 return flag;
701 assert(if_);
702 assert(!else_);
704 /* Synthesize the enable expression. */
705 NetNet*ce = expr_->synthesize(des);
706 assert(ce->pin_count() == 1);
708 /* What's left, is a synchronous CE statement like this:
710 if (expr_) <true statement>;
712 The expr_ expression has already been synthesized to the ce
713 net, so we connect it here to the FF. What's left is to
714 synthesize the substatement as a combinational
715 statement.
717 Watch out for the special case that there is already a CE
718 connected to this FF. This can be caused by code like this:
720 if (a) if (b) <statement>;
722 In this case, we are working on the inner IF, so we AND the
723 a and b expressions to make a new CE. */
725 if (ff->pin_Enable().is_linked()) {
726 NetLogic*ce_and = new NetLogic(scope,
727 scope->local_symbol(), 3,
728 NetLogic::AND, 1);
729 des->add_node(ce_and);
730 connect(ff->pin_Enable(), ce_and->pin(1));
731 connect(ce->pin(0), ce_and->pin(2));
733 ff->pin_Enable().unlink();
734 connect(ff->pin_Enable(), ce_and->pin(0));
736 NetNet*tmp = new NetNet(scope, scope->local_symbol(),
737 NetNet::IMPLICIT, 1);
738 tmp->local_flag(true);
739 connect(ff->pin_Enable(), tmp->pin(0));
741 } else {
743 connect(ff->pin_Enable(), ce->pin(0));
746 bool flag = if_->synth_sync(des, scope, ff, nex_map, nex_out, events_in);
748 return flag;
750 #else
751 cerr << get_line() << ": sorry: "
752 << "Forgot to implement NetCondit::synth_sync" << endl;
753 return false;
754 #endif
757 bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
758 const NetBus&nex_map, NetBus&nex_out,
759 const svector<NetEvProbe*>&events_in)
761 if (events_in.count() > 0) {
762 cerr << get_line() << ": error: Events are unaccounted"
763 << " for in process synthesis." << endl;
764 des->errors += 1;
767 assert(events_in.count() == 0);
769 /* This can't be other than one unless there are named events,
770 which I cannot synthesize. */
771 assert(nevents_ == 1);
772 NetEvent*ev = events_[0];
774 assert(ev->nprobe() >= 1);
775 svector<NetEvProbe*>events (ev->nprobe() - 1);
777 /* Get the input set from the substatement. This will be used
778 to figure out which of the probes is the clock. */
779 NexusSet*statement_input = statement_ -> nex_input();
781 /* Search for a clock input. The clock input is the edge event
782 that is not also an input to the substatement. */
783 NetEvProbe*pclk = 0;
784 unsigned event_idx = 0;
785 for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) {
786 NetEvProbe*tmp = ev->probe(idx);
787 assert(tmp->pin_count() == 1);
789 NexusSet tmp_nex;
790 tmp_nex .add( tmp->pin(0).nexus() );
792 if (! statement_input ->contains(tmp_nex)) {
793 if (pclk != 0) {
794 cerr << get_line() << ": error: Too many "
795 << "clocks for synchronous logic." << endl;
796 cerr << get_line() << ": : Perhaps an"
797 << " asynchronous set/reset is misused?" << endl;
798 des->errors += 1;
800 pclk = tmp;
802 } else {
803 events[event_idx++] = tmp;
807 if (pclk == 0) {
808 cerr << get_line() << ": error: None of the edges"
809 << " are valid clock inputs." << endl;
810 cerr << get_line() << ": : Perhaps the clock"
811 << " is read by a statement or expression?" << endl;
812 return false;
815 connect(ff->pin_Clock(), pclk->pin(0));
816 if (pclk->edge() == NetEvProbe::NEGEDGE) {
817 perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
818 ff->attribute(polarity, verinum("INVERT"));
820 if (debug_synth2) {
821 cerr << get_line() << ": debug: "
822 << "Detected a NEGEDGE clock for the synthesized ff."
823 << endl;
827 /* Synthesize the input to the DFF. */
828 bool flag = statement_->synth_sync(des, scope, ff,
829 nex_map, nex_out, events);
831 return flag;
835 * This method is called for a process that is determined to be
836 * synchronous. Create a NetFF device to hold the output from the
837 * statement, and synthesize that statement in place.
839 bool NetProcTop::synth_sync(Design*des)
841 if (debug_synth2) {
842 cerr << get_line() << ": debug: "
843 << "Process is apparently synchronous. Making NetFFs."
844 << endl;
847 NexusSet nex_set;
848 statement_->nex_output(nex_set);
850 /* Make a model FF that will connect to the first item in the
851 set, and will also take the initial connection of clocks
852 and resets. */
854 if (debug_synth2) {
855 cerr << get_line() << ": debug: "
856 << "Top level making a "
857 << nex_set[0]->vector_width() << "-wide "
858 << "NetFF device." << endl;
861 NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
862 nex_set[0]->vector_width());
863 des->add_node(ff);
864 ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF"));
866 NetBus nex_d (scope(), nex_set.count());
867 NetBus nex_q (scope(), nex_set.count());
869 /* The Q of the NetFF devices is connected to the output that
870 we are. The nex_q is a bundle of the outputs. We will also
871 pass the nex_q as a map to the statement's synth_sync
872 method to map it to the correct nex_d pin. */
873 for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
874 connect(nex_set[idx], nex_q.pin(idx));
877 // Connect the input later.
879 /* Synthesize the input to the DFF. */
880 bool flag = statement_->synth_sync(des, scope(), ff,
881 nex_q, nex_d,
882 svector<NetEvProbe*>());
883 if (! flag) {
884 delete ff;
885 return false;
889 NetNet*tmp = nex_d.pin(0).nexus()->pick_any_net();
890 assert(tmp);
892 tmp = crop_to_width(des, tmp, ff->width());
893 connect(tmp->pin(0), ff->pin_Data());
894 connect(nex_q.pin(0), ff->pin_Q());
896 for (unsigned idx = 1 ; idx < nex_set.count() ; idx += 1) {
897 NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
898 nex_set[idx]->vector_width());
899 des->add_node(ff2);
901 tmp = nex_d.pin(idx).nexus()->pick_any_net();
902 assert(tmp);
904 tmp = crop_to_width(des, tmp, ff2->width());
906 connect(nex_q.pin(idx), ff2->pin_Q());
907 connect(tmp->pin(0), ff2->pin_Data());
909 connect(ff->pin_Clock(), ff2->pin_Clock());
910 if (ff->pin_Enable().is_linked())
911 connect(ff->pin_Enable(), ff2->pin_Enable());
912 if (ff->pin_Aset().is_linked())
913 connect(ff->pin_Aset(), ff2->pin_Aset());
914 if (ff->pin_Aclr().is_linked())
915 connect(ff->pin_Aclr(), ff2->pin_Aclr());
916 if (ff->pin_Sset().is_linked())
917 connect(ff->pin_Sset(), ff2->pin_Sset());
918 if (ff->pin_Sclr().is_linked())
919 connect(ff->pin_Sclr(), ff2->pin_Sclr());
922 return true;
925 class synth2_f : public functor_t {
927 public:
928 void process(class Design*, class NetProcTop*);
930 private:
935 * Look at a process. If it is asynchronous, then synthesize it as an
936 * asynchronous process and delete the process itself for its gates.
938 void synth2_f::process(class Design*des, class NetProcTop*top)
940 if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
941 return;
943 /* If the scope that contains this process as a cell attribute
944 attached to it, then skip synthesis. */
945 if (top->scope()->attribute(perm_string::literal("ivl_synthesis_cell")).len() > 0)
946 return;
948 if (top->is_synchronous()) do {
949 bool flag = top->synth_sync(des);
950 if (! flag) {
951 cerr << top->get_line() << ": error: "
952 << "Unable to synthesize synchronous process." << endl;
953 des->errors += 1;
954 return;
956 des->delete_process(top);
957 return;
958 } while (0);
960 if (! top->is_asynchronous()) {
961 bool synth_error_flag = false;
962 if (top->attribute(perm_string::literal("ivl_combinational")).as_ulong() != 0) {
963 cerr << top->get_line() << ": error: "
964 << "Process is marked combinational,"
965 << " but isn't really." << endl;
966 des->errors += 1;
967 synth_error_flag = true;
970 if (top->attribute(perm_string::literal("ivl_synthesis_on")).as_ulong() != 0) {
971 cerr << top->get_line() << ": error: "
972 << "Process is marked for synthesis,"
973 << " but I can't do it." << endl;
974 des->errors += 1;
975 synth_error_flag = true;
978 if (! synth_error_flag)
979 cerr << top->get_line() << ": warning: "
980 << "Process not synthesized." << endl;
982 return;
985 if (! top->synth_async(des)) {
986 cerr << top->get_line() << ": internal error: "
987 << "is_asynchronous does not match "
988 << "sync_async results." << endl;
989 return;
992 des->delete_process(top);
995 void synth2(Design*des)
997 synth2_f synth_obj;
998 des->functor(&synth_obj);
1002 * $Log: synth2.cc,v $
1003 * Revision 1.46 2007/03/22 16:08:17 steve
1004 * Spelling fixes from Larry
1006 * Revision 1.45 2005/08/27 04:32:08 steve
1007 * Handle synthesis of fully packed case statements.
1009 * Revision 1.44 2005/05/15 04:45:50 steve
1010 * Debug text.
1012 * Revision 1.43 2005/04/25 01:35:58 steve
1013 * Reimplement basic asynchronous processes.
1015 * Revision 1.42 2005/04/24 23:44:02 steve
1016 * Update DFF support to new data flow.