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)
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
20 #ident "$Id: synth2.cc,v 1.46 2007/03/22 16:08:17 steve Exp $"
28 # include "compiler.h"
32 bool NetProc::synth_async(Design
*des
, NetScope
*scope
,
33 const NetBus
&nex_map
, NetBus
&nex_out
)
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
;
48 /* Synthesize the input to the DFF. */
49 return synth_async(des
, scope
, nex_map
, nex_out
);
53 static unsigned find_nexus_in_set(const NetBus
&nset
, const Nexus
*nex
)
56 for (idx
= 0 ; idx
< nset
.pin_count() ; idx
+= 1)
57 if (nset
.pin(idx
).nexus() == nex
)
65 * Async synthesis of assignments is done by synthesizing the rvalue
66 * expression, then connecting the l-value directly to the output of
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
74 bool NetAssignBase::synth_async(Design
*des
, NetScope
*scope
,
75 const NetBus
&nex_map
, NetBus
&nex_out
)
77 NetNet
*rsig
= rval_
->synthesize(des
);
80 NetNet
*lsig
= lval_
->sig();
82 cerr
<< get_line() << ": error: "
83 << "NetAssignBase::synth_async on unsupported lval ";
88 assert(lval_
->more
== 0);
91 cerr
<< get_line() << ": debug: l-value signal is "
92 << lsig
->vector_width() << " bits, r-value signal is "
93 << rsig
->vector_width() << " bits." << endl
;
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
;
106 /* For now, assume there is exactly one output. */
107 assert(nex_out
.pin_count() == 1);
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();
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
128 bool NetBlock::synth_async(Design
*des
, NetScope
*scope
,
129 const NetBus
&nex_map
, NetBus
&nex_out
)
140 /* Create a temporary map of the output only from this
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)
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) {
165 while (ptr
< nex_map
.pin_count()
166 && ! nex_map
.pin(ptr
).is_linked(tmp_map
.pin(idx
)))
169 assert(ptr
< nex_out
.pin_count());
170 connect(nex_out
.pin(ptr
), tmp_out
.pin(idx
));
173 } while (cur
!= last_
);
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
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
;
206 NetEConst
*ge
= dynamic_cast<NetEConst
*>(items_
[item
].guard
);
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
);
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);
239 for (unsigned idx
= 0 ; idx
< mux_size
; idx
+= 1) {
241 NetProc
*stmt
= statement_map
[idx
];
243 cerr
<< get_line() << ": error: case " << idx
244 << " is not accounted for in asynchronous mux." << endl
;
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
);
263 bool NetCondit::synth_async(Design
*des
, NetScope
*scope
,
264 const NetBus
&nex_map
, NetBus
&nex_out
)
267 NetNet
*ssig
= expr_
->synthesize(des
);
271 DEBUG_SYNTH2_EXIT("NetCondit",false)
275 cerr
<< get_line() << ": error: Asynchronous if statement"
276 << " is missing the else clause." << endl
;
277 DEBUG_SYNTH2_EXIT("NetCondit",false)
284 NetNet
*asig
= new NetNet(scope
, scope
->local_symbol(),
285 NetNet::WIRE
, nex_map
->pin_count());
286 asig
->local_flag(true);
289 flag
= if_
->synth_async(des
, scope
, nex_map
, asig
);
292 DEBUG_SYNTH2_EXIT("NetCondit",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
);
304 DEBUG_SYNTH2_EXIT("NetCondit",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());
318 DEBUG_SYNTH2_EXIT("NetCondit",true)
322 cerr
<< get_line() << ": sorry: "
323 << "Forgot to implement NetCondit::synth_async" << endl
;
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
);
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
)
346 statement_
->nex_output(nex_set
);
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
);
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
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
)
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;
400 /* Create a temporary nex_map for the substatement. */
402 cur
->nex_output(tmp_set
);
403 NetNet
*tmp_map
= new NetNet(scope
, tmp1
, NetNet::WIRE
,
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());
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()
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();
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
,
497 flag
= flag
&& ok_flag
;
499 if (ok_flag
== false)
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
));
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. */
529 cerr
<< get_line() << ": sorry: "
530 << "Forgot to implement NetBlock::synth_sync"
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
)
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();
554 for (unsigned idx
= 0 ; idx
< events_in
.count() ; idx
+= 1) {
556 NetEvProbe
*ev
= events_in
[idx
];
558 pin_set
.add(ev
->pin(0).nexus());
560 if (! expr_input
->contains(pin_set
))
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
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);
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());
600 connect(ff
->pin_Aclr(), rst
->pin(0));
603 connect(ff
->pin_Aset(), rst
->pin(0));
610 assert(events_in
.count() == 1);
612 flag
= else_
->synth_sync(des
, scope
, ff
, nex_map
,
613 nex_out
, svector
<NetEvProbe
*>(0))
615 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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. */
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
);
646 /* This path leads nowhere */
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());
664 connect(ff
->pin_Sclr(), rst
->pin(0));
667 connect(ff
->pin_Sset(), rst
->pin(0));
674 flag
= else_
->synth_sync(des
, scope
, ff
, nex_map
,
675 nex_out
, svector
<NetEvProbe
*>(0))
677 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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
;
693 /* If this is an if/then/else, then it is likely a
694 combinational if, and I should synthesize it that way. */
696 bool flag
= synth_async(des
, scope
, nex_map
, nex_out
);
697 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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
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,
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));
743 connect(ff
->pin_Enable(), ce
->pin(0));
746 bool flag
= if_
->synth_sync(des
, scope
, ff
, nex_map
, nex_out
, events_in
);
751 cerr
<< get_line() << ": sorry: "
752 << "Forgot to implement NetCondit::synth_sync" << endl
;
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
;
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. */
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);
790 tmp_nex
.add( tmp
->pin(0).nexus() );
792 if (! statement_input
->contains(tmp_nex
)) {
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
;
803 events
[event_idx
++] = tmp
;
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
;
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"));
821 cerr
<< get_line() << ": debug: "
822 << "Detected a NEGEDGE clock for the synthesized ff."
827 /* Synthesize the input to the DFF. */
828 bool flag
= statement_
->synth_sync(des
, scope
, ff
,
829 nex_map
, nex_out
, events
);
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
)
842 cerr
<< get_line() << ": debug: "
843 << "Process is apparently synchronous. Making NetFFs."
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
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());
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
,
882 svector
<NetEvProbe
*>());
889 NetNet
*tmp
= nex_d
.pin(0).nexus()->pick_any_net();
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());
901 tmp
= nex_d
.pin(idx
).nexus()->pick_any_net();
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());
925 class synth2_f
: public functor_t
{
928 void process(class Design
*, class NetProcTop
*);
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)
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)
948 if (top
->is_synchronous()) do {
949 bool flag
= top
->synth_sync(des
);
951 cerr
<< top
->get_line() << ": error: "
952 << "Unable to synthesize synchronous process." << endl
;
956 des
->delete_process(top
);
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
;
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
;
975 synth_error_flag
= true;
978 if (! synth_error_flag
)
979 cerr
<< top
->get_line() << ": warning: "
980 << "Process not synthesized." << endl
;
985 if (! top
->synth_async(des
)) {
986 cerr
<< top
->get_line() << ": internal error: "
987 << "is_asynchronous does not match "
988 << "sync_async results." << endl
;
992 des
->delete_process(top
);
995 void synth2(Design
*des
)
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
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.