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 ";
89 assert(lval_
->more
== 0);
92 cerr
<< get_line() << ": debug: l-value signal is "
93 << lsig
->vector_width() << " bits, r-value signal is "
94 << rsig
->vector_width() << " bits." << endl
;
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
;
107 /* For now, assume there is exactly one output. */
108 assert(nex_out
.pin_count() == 1);
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();
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
129 bool NetBlock::synth_async(Design
*des
, NetScope
*scope
,
130 const NetBus
&nex_map
, NetBus
&nex_out
)
141 /* Create a temporary map of the output only from this
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)
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) {
166 while (ptr
< nex_map
.pin_count()
167 && ! nex_map
.pin(ptr
).is_linked(tmp_map
.pin(idx
)))
170 assert(ptr
< nex_out
.pin_count());
171 connect(nex_out
.pin(ptr
), tmp_out
.pin(idx
));
174 } while (cur
!= last_
);
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
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
;
207 NetEConst
*ge
= dynamic_cast<NetEConst
*>(items_
[item
].guard
);
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
);
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);
240 for (unsigned idx
= 0 ; idx
< mux_size
; idx
+= 1) {
242 NetProc
*stmt
= statement_map
[idx
];
244 cerr
<< get_line() << ": error: case " << idx
245 << " is not accounted for in asynchronous mux." << endl
;
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
);
265 bool NetCondit::synth_async(Design
*des
, NetScope
*scope
,
266 const NetBus
&nex_map
, NetBus
&nex_out
)
269 NetNet
*ssig
= expr_
->synthesize(des
);
273 DEBUG_SYNTH2_EXIT("NetCondit",false)
277 cerr
<< get_line() << ": error: Asynchronous if statement"
278 << " is missing the else clause." << endl
;
279 DEBUG_SYNTH2_EXIT("NetCondit",false)
286 NetNet
*asig
= new NetNet(scope
, scope
->local_symbol(),
287 NetNet::WIRE
, nex_map
->pin_count());
288 asig
->local_flag(true);
291 flag
= if_
->synth_async(des
, scope
, nex_map
, asig
);
294 DEBUG_SYNTH2_EXIT("NetCondit",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
);
306 DEBUG_SYNTH2_EXIT("NetCondit",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());
320 DEBUG_SYNTH2_EXIT("NetCondit",true)
324 cerr
<< get_line() << ": sorry: "
325 << "Forgot to implement NetCondit::synth_async" << endl
;
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
);
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
)
349 statement_
->nex_output(nex_set
);
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
);
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
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
)
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;
403 /* Create a temporary nex_map for the substatement. */
405 cur
->nex_output(tmp_set
);
406 NetNet
*tmp_map
= new NetNet(scope
, tmp1
, NetNet::WIRE
,
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());
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()
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();
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
,
500 flag
= flag
&& ok_flag
;
502 if (ok_flag
== false)
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
));
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. */
532 cerr
<< get_line() << ": sorry: "
533 << "Forgot to implement NetBlock::synth_sync"
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
)
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();
558 for (unsigned idx
= 0 ; idx
< events_in
.count() ; idx
+= 1) {
560 NetEvProbe
*ev
= events_in
[idx
];
562 pin_set
.add(ev
->pin(0).nexus());
564 if (! expr_input
->contains(pin_set
))
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
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);
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());
604 connect(ff
->pin_Aclr(), rst
->pin(0));
607 connect(ff
->pin_Aset(), rst
->pin(0));
614 assert(events_in
.count() == 1);
616 flag
= else_
->synth_sync(des
, scope
, ff
, nex_map
,
617 nex_out
, svector
<NetEvProbe
*>(0))
619 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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. */
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
);
650 /* This path leads nowhere */
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());
668 connect(ff
->pin_Sclr(), rst
->pin(0));
671 connect(ff
->pin_Sset(), rst
->pin(0));
678 flag
= else_
->synth_sync(des
, scope
, ff
, nex_map
,
679 nex_out
, svector
<NetEvProbe
*>(0))
681 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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
;
697 /* If this is an if/then/else, then it is likely a
698 combinational if, and I should synthesize it that way. */
700 bool flag
= synth_async(des
, scope
, nex_map
, nex_out
);
701 DEBUG_SYNTH2_EXIT("NetCondit",flag
)
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
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,
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));
747 connect(ff
->pin_Enable(), ce
->pin(0));
750 bool flag
= if_
->synth_sync(des
, scope
, ff
, nex_map
, nex_out
, events_in
);
755 cerr
<< get_line() << ": sorry: "
756 << "Forgot to implement NetCondit::synth_sync" << endl
;
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
;
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. */
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);
795 tmp_nex
.add( tmp
->pin(0).nexus() );
797 if (! statement_input
->contains(tmp_nex
)) {
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
;
808 events
[event_idx
++] = tmp
;
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
;
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"));
826 cerr
<< get_line() << ": debug: "
827 << "Detected a NEGEDGE clock for the synthesized ff."
832 /* Synthesize the input to the DFF. */
833 bool flag
= statement_
->synth_sync(des
, scope
, ff
,
834 nex_map
, nex_out
, events
);
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
)
847 cerr
<< get_line() << ": debug: "
848 << "Process is apparently synchronous. Making NetFFs."
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
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());
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
,
887 svector
<NetEvProbe
*>());
894 NetNet
*tmp
= nex_d
.pin(0).nexus()->pick_any_net();
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());
906 tmp
= nex_d
.pin(idx
).nexus()->pick_any_net();
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());
930 class synth2_f
: public functor_t
{
933 void process(class Design
*, class NetProcTop
*);
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)
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)
953 if (top
->is_synchronous()) do {
954 bool flag
= top
->synth_sync(des
);
956 cerr
<< top
->get_line() << ": error: "
957 << "Unable to synthesize synchronous process." << endl
;
961 des
->delete_process(top
);
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
;
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
;
980 synth_error_flag
= true;
983 if (! synth_error_flag
)
984 cerr
<< top
->get_line() << ": warning: "
985 << "Process not synthesized." << endl
;
990 if (! top
->synth_async(des
)) {
991 cerr
<< top
->get_line() << ": internal error: "
992 << "is_asynchronous does not match "
993 << "sync_async results." << endl
;
998 des
->delete_process(top
);
1001 void synth2(Design
*des
)
1004 des
->functor(&synth_obj
);