2002-06-30 04:21:31 +02:00
|
|
|
/*
|
2006-01-01 02:30:39 +01:00
|
|
|
* Copyright (c) 2002-2006 Stephen Williams (steve@icarus.com)
|
2002-06-30 04:21:31 +02:00
|
|
|
*
|
|
|
|
|
* This source code is free software; you can redistribute it
|
|
|
|
|
* and/or modify it in source code form under the terms of the GNU
|
|
|
|
|
* General Public License as published by the Free Software
|
|
|
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
|
|
|
* any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
2002-08-12 03:34:58 +02:00
|
|
|
#ifdef HAVE_CVS_IDENT
|
2006-01-18 07:16:11 +01:00
|
|
|
#ident "$Id: synth2.cc,v 1.39.2.17 2006/01/18 06:16:11 steve Exp $"
|
2002-06-30 04:21:31 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "config.h"
|
|
|
|
|
|
|
|
|
|
# include "functor.h"
|
|
|
|
|
# include "netlist.h"
|
2002-07-01 02:54:21 +02:00
|
|
|
# include "compiler.h"
|
2002-06-30 04:21:31 +02:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
static int debug_synth2=0;
|
2004-03-15 19:40:12 +01:00
|
|
|
|
|
|
|
|
#ifdef __FUNCTION__
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
#define DEBUG_SYNTH2_ENTRY(class) if (debug_synth2) { cerr << "Enter " << class << "::" \
|
|
|
|
|
<< __FUNCTION__ << endl; dump(cerr, 4); }
|
|
|
|
|
#define DEBUG_SYNTH2_EXIT(class,val) if (debug_synth2) { cerr << "Exit " << class << "::" \
|
|
|
|
|
<< __FUNCTION__ << ", result " << val << endl; }
|
|
|
|
|
|
2004-03-15 19:40:12 +01:00
|
|
|
#else
|
|
|
|
|
#define DEBUG_SYNTH2_ENTRY(class)
|
|
|
|
|
#define DEBUG_SYNTH2_EXIT(class,val)
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetProc::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetProc::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2005-08-22 03:00:41 +02:00
|
|
|
NetNet*accum_in)
|
|
|
|
|
{
|
2005-12-14 01:54:29 +01:00
|
|
|
return synth_async(des, scope, sync_flag, nex_map, nex_out);
|
2005-08-22 03:00:41 +02:00
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
bool NetProc::synth_sync(Design*des, NetScope*scope,
|
|
|
|
|
struct sync_accounting_cell*nex_ff,
|
2005-12-14 01:54:29 +01:00
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2005-12-19 02:13:47 +01:00
|
|
|
#if 0
|
2002-09-26 03:13:14 +02:00
|
|
|
if (events.count() > 0) {
|
|
|
|
|
cerr << get_line() << ": error: Events are unaccounted"
|
2005-12-19 02:13:47 +01:00
|
|
|
<< " for in process synthesis. (proc)" << endl;
|
2002-09-26 03:13:14 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
2005-12-19 02:13:47 +01:00
|
|
|
#endif
|
2002-09-16 02:30:33 +02:00
|
|
|
/* Synthesize the input to the DFF. */
|
2005-12-14 01:54:29 +01:00
|
|
|
return synth_async(des, scope, true, nex_map, nex_out);
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
static unsigned find_nexus_in_set(const NetNet*nset, const Nexus*nex)
|
|
|
|
|
{
|
|
|
|
|
unsigned idx = 0;
|
|
|
|
|
for (idx = 0 ; idx < nset->pin_count() ; idx += 1)
|
|
|
|
|
if (nset->pin(idx).nexus() == nex)
|
|
|
|
|
return idx;
|
|
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
2002-06-30 04:21:31 +02:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Async synthesis of assignments is done by synthesizing the rvalue
|
|
|
|
|
* expression, then connecting the l-value directly to the output of
|
|
|
|
|
* the r-value.
|
2002-07-01 02:54:21 +02:00
|
|
|
*
|
|
|
|
|
* The nex_map is the O-set for the statement, and lists the positions
|
|
|
|
|
* of the outputs as the caller wants results linked up. The nex_out,
|
|
|
|
|
* however, is the set of nexa that are to actually get linked to the
|
|
|
|
|
* r-value.
|
2002-06-30 04:21:31 +02:00
|
|
|
*/
|
2005-11-13 23:28:48 +01:00
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2005-11-13 23:28:48 +01:00
|
|
|
{
|
|
|
|
|
const perm_string tmp = perm_string::literal("tmp");
|
|
|
|
|
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
|
2005-11-13 23:28:48 +01:00
|
|
|
delete stub;
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetAssignBase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2005-11-13 23:28:48 +01:00
|
|
|
NetNet*accum_in)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
|
|
|
|
NetNet*rsig = rval_->synthesize(des);
|
2002-07-01 02:54:21 +02:00
|
|
|
assert(rsig);
|
2005-12-14 01:54:29 +01:00
|
|
|
|
2005-12-10 05:26:32 +01:00
|
|
|
unsigned roff = 0;
|
2002-06-30 04:21:31 +02:00
|
|
|
|
2005-12-10 05:26:32 +01:00
|
|
|
for (NetAssign_*cur = lval_ ; cur ; cur = cur->more) {
|
|
|
|
|
|
|
|
|
|
NetNet*lsig = cur->sig();
|
|
|
|
|
if (!lsig) {
|
|
|
|
|
cerr << get_line() << ": error: NetAssignBase::synth_async "
|
|
|
|
|
"on unsupported lval ";
|
|
|
|
|
dump_lval(cerr);
|
|
|
|
|
cerr << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
if (cur->bmux() && !sync_flag) {
|
|
|
|
|
cerr << get_line() << ": error: Assign to bit select "
|
|
|
|
|
<< "Not possible in asynchronous logic." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Detect and handle the special case that this is a
|
|
|
|
|
memory-like access to a vector. */
|
|
|
|
|
if (cur->bmux()) {
|
|
|
|
|
NetNet*adr = cur->bmux()->synthesize(des);
|
|
|
|
|
NetRamDq*dq = new NetRamDq(scope, scope->local_symbol(),
|
|
|
|
|
lsig, adr->pin_count());
|
|
|
|
|
des->add_node(dq);
|
|
|
|
|
dq->set_line(*this);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < adr->pin_count() ; idx += 1)
|
|
|
|
|
connect(dq->pin_Address(idx), adr->pin(idx));
|
|
|
|
|
#if 0
|
|
|
|
|
/* Connect the Q bit to all the bits of the
|
|
|
|
|
output. This is a signal to a later stage that
|
|
|
|
|
the DFF should be replaced with a RAM to
|
|
|
|
|
support this port. */
|
|
|
|
|
for (unsigned idx = 0; idx < lsig->pin_count(); idx += 1){
|
|
|
|
|
unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(idx).nexus());
|
|
|
|
|
connect(dq->pin_Q(0), nex_out->pin(ptr));
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
connect(dq->pin_Data(0), rsig->pin(roff));
|
|
|
|
|
roff += cur->lwidth();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-10 05:26:32 +01:00
|
|
|
/* Bind the outputs that we do make to the nex_out. Use the
|
|
|
|
|
nex_map to map the l-value bit position to the nex_out bit
|
|
|
|
|
position. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < cur->lwidth() ; idx += 1) {
|
|
|
|
|
unsigned off = cur->get_loff()+idx;
|
|
|
|
|
unsigned ptr = find_nexus_in_set(nex_map, lsig->pin(off).nexus());
|
|
|
|
|
assert(ptr <= nex_map->pin_count());
|
|
|
|
|
connect(nex_out->pin(ptr), rsig->pin(roff+idx));
|
|
|
|
|
}
|
2002-06-30 04:21:31 +02:00
|
|
|
|
2005-12-10 05:26:32 +01:00
|
|
|
roff += cur->lwidth();
|
|
|
|
|
|
|
|
|
|
/* This lval_ represents a reg that is a WIRE in the
|
|
|
|
|
synthesized results. This function signals the destructor
|
|
|
|
|
to change the REG that this l-value refers to into a
|
|
|
|
|
WIRE. It is done then, at the last minute, so that pending
|
|
|
|
|
synthesis can continue to work with it as a WIRE. */
|
|
|
|
|
cur->turn_sig_to_wire_on_release();
|
|
|
|
|
}
|
2004-08-28 17:08:31 +02:00
|
|
|
|
2002-06-30 04:21:31 +02:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-29 02:00:28 +02:00
|
|
|
/*
|
|
|
|
|
* Sequential blocks are translated to asynchronous logic by
|
|
|
|
|
* translating each statement of the block, in order, into gates. The
|
|
|
|
|
* nex_out for the block is the union of the nex_out for all the
|
|
|
|
|
* substatements.
|
|
|
|
|
*/
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetBlock::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2002-07-29 02:00:28 +02:00
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_ENTRY("NetBlock")
|
|
|
|
|
if (last_ == 0) {
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetBlock",true)
|
2002-07-29 02:00:28 +02:00
|
|
|
return true;
|
2003-12-17 17:52:39 +01:00
|
|
|
}
|
2002-07-29 02:00:28 +02:00
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
const perm_string tmp1 = perm_string::literal("tmp1");
|
|
|
|
|
const perm_string tmp2 = perm_string::literal("tmp2");
|
2005-08-22 00:49:54 +02:00
|
|
|
const perm_string tmp3 = perm_string::literal("tmp3");
|
|
|
|
|
|
|
|
|
|
NetNet*accum_out = new NetNet(scope, tmp3, NetNet::WIRE,
|
|
|
|
|
nex_out->pin_count());
|
|
|
|
|
accum_out->local_flag(true);
|
2004-02-18 18:11:54 +01:00
|
|
|
|
2002-07-29 02:00:28 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
NetProc*cur = last_;
|
|
|
|
|
do {
|
2005-08-22 03:00:41 +02:00
|
|
|
NetNet*new_accum;
|
|
|
|
|
|
2002-07-29 02:00:28 +02:00
|
|
|
cur = cur->next_;
|
|
|
|
|
|
2002-09-17 06:40:28 +02:00
|
|
|
/* Create a temporary nex_map for the substatement. */
|
2002-07-29 02:00:28 +02:00
|
|
|
NexusSet tmp_set;
|
|
|
|
|
cur->nex_output(tmp_set);
|
2004-02-18 18:11:54 +01:00
|
|
|
NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE,
|
2002-07-29 02:00:28 +02:00
|
|
|
tmp_set.count());
|
2002-09-17 06:40:28 +02:00
|
|
|
for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
|
|
|
|
|
connect(tmp_set[idx], tmp_map->pin(idx));
|
2002-07-29 02:00:28 +02:00
|
|
|
|
2002-09-17 06:40:28 +02:00
|
|
|
/* Create also a temporary net_out to collect the
|
|
|
|
|
output. */
|
2004-02-18 18:11:54 +01:00
|
|
|
NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE,
|
2002-09-17 06:40:28 +02:00
|
|
|
tmp_set.count());
|
2005-12-10 04:30:50 +01:00
|
|
|
tmp_out->set_line(*this);
|
2002-09-17 06:40:28 +02:00
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
/* Make a temporary set of currently accumulated outputs
|
|
|
|
|
that we can pass to the synth_async of the
|
|
|
|
|
sub-statement. Some sub-statements will use this to
|
|
|
|
|
handle default cases specially. We will delete this
|
|
|
|
|
temporary map as soon as the synth_async is done. */
|
|
|
|
|
new_accum = new NetNet(scope, tmp3, NetNet::WIRE, tmp_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1) {
|
|
|
|
|
unsigned ptr = find_nexus_in_set(nex_map, tmp_set[idx]);
|
|
|
|
|
if (accum_out->pin(ptr).is_linked())
|
|
|
|
|
connect(new_accum->pin(idx), accum_out->pin(ptr));
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool ok_flag = cur->synth_async(des, scope, sync_flag,
|
2005-08-22 03:00:41 +02:00
|
|
|
tmp_map, tmp_out, new_accum);
|
2002-07-29 02:00:28 +02:00
|
|
|
flag = flag && ok_flag;
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
delete new_accum;
|
|
|
|
|
|
2005-12-10 04:30:50 +01:00
|
|
|
/* NOTE: tmp_set is not valid after this point, since
|
|
|
|
|
the cur->synth_async method may change nexa that it
|
|
|
|
|
refers to. */
|
|
|
|
|
|
2002-07-29 02:00:28 +02:00
|
|
|
if (ok_flag == false)
|
|
|
|
|
continue;
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
/* Now start building a new set of accumulated outputs
|
|
|
|
|
that we will pass to the next statement of the block,
|
|
|
|
|
or that will be the output of the block. */
|
|
|
|
|
new_accum = new NetNet(scope, tmp3, NetNet::WIRE,
|
|
|
|
|
nex_out->pin_count());
|
2005-12-10 04:30:50 +01:00
|
|
|
new_accum->set_line(*this);
|
2005-08-22 00:49:54 +02:00
|
|
|
|
2002-09-17 06:40:28 +02:00
|
|
|
/* Use the nex_map to link up the output from the
|
2002-07-29 02:00:28 +02:00
|
|
|
substatement to the output of the block as a whole. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
|
2005-12-10 04:30:50 +01:00
|
|
|
unsigned ptr = find_nexus_in_set(nex_map, tmp_map->pin(idx).nexus());
|
|
|
|
|
if (ptr >= nex_map->pin_count()) {
|
|
|
|
|
cerr << cur->get_line() << ": internal error: "
|
|
|
|
|
<< "Nexus isn't in nex_map?! idx=" << idx
|
|
|
|
|
<< " map width = " << nex_map->pin_count()
|
|
|
|
|
<< " tmp_map count = " << tmp_map->pin_count()
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
assert(ptr < new_accum->pin_count());
|
2005-08-22 00:49:54 +02:00
|
|
|
connect(new_accum->pin(ptr), tmp_out->pin(idx));
|
2002-07-29 02:00:28 +02:00
|
|
|
}
|
|
|
|
|
|
2002-09-17 06:40:28 +02:00
|
|
|
delete tmp_map;
|
2002-07-29 02:00:28 +02:00
|
|
|
delete tmp_out;
|
|
|
|
|
|
2005-08-22 00:49:54 +02:00
|
|
|
/* Anything that is not redriven by the current
|
|
|
|
|
statement inherits the value that was driven from any
|
|
|
|
|
previous statements. */
|
|
|
|
|
for (unsigned idx = 0; idx < new_accum->pin_count(); idx += 1) {
|
|
|
|
|
if (new_accum->pin(idx).is_linked())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
connect(new_accum->pin(idx), accum_out->pin(idx));
|
|
|
|
|
}
|
|
|
|
|
delete accum_out;
|
|
|
|
|
accum_out = new_accum;
|
|
|
|
|
|
2002-07-29 02:00:28 +02:00
|
|
|
} while (cur != last_);
|
|
|
|
|
|
2005-08-22 00:49:54 +02:00
|
|
|
/* Now bind the accumulated output valies to the nex_out
|
|
|
|
|
passed in. Note that each previous step has already did the
|
|
|
|
|
pin mapping, so just connect. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < accum_out->pin_count() ; idx += 1) {
|
|
|
|
|
connect(nex_out->pin(idx), accum_out->pin(idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete accum_out;
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetBlock",flag)
|
2002-07-29 02:00:28 +02:00
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2005-08-22 03:00:41 +02:00
|
|
|
{
|
|
|
|
|
const perm_string tmp = perm_string::literal("tmp");
|
|
|
|
|
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
|
2005-08-22 03:00:41 +02:00
|
|
|
delete stub;
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetCase::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out, NetNet*accum)
|
2002-07-08 00:32:15 +02:00
|
|
|
{
|
|
|
|
|
unsigned cur;
|
|
|
|
|
|
|
|
|
|
NetNet*esig = expr_->synthesize(des);
|
|
|
|
|
|
|
|
|
|
/* Scan the select vector looking for constant bits. The
|
|
|
|
|
constant bits will be elided from the select input connect,
|
|
|
|
|
but we still need to keep track of them. */
|
|
|
|
|
unsigned sel_pins = 0;
|
|
|
|
|
unsigned long sel_mask = 0;
|
|
|
|
|
unsigned long sel_ref = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < esig->pin_count() ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
if (esig->pin(idx).nexus()->drivers_constant()) {
|
|
|
|
|
verinum::V bit = esig->pin(idx).nexus()->driven_value();
|
|
|
|
|
if (bit == verinum::V1)
|
|
|
|
|
sel_ref |= 1 << idx;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
sel_pins += 1;
|
|
|
|
|
sel_mask |= 1 << idx;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
/* At this point, sel_ref represents the constant part of the
|
|
|
|
|
select input. That is, (select&sel_mask) == sel_ref for all
|
|
|
|
|
guard values that are reachable. We can use this to skip
|
|
|
|
|
unreachable guards. */
|
|
|
|
|
|
|
|
|
|
|
2002-07-08 00:32:15 +02:00
|
|
|
/* Build a map of guard values to mux select values. This
|
|
|
|
|
helps account for constant select bits that are being
|
2006-01-18 02:23:23 +01:00
|
|
|
elided. The guard2sel mapping will only be valid for
|
|
|
|
|
reachable guards. */
|
2002-07-08 00:32:15 +02:00
|
|
|
map<unsigned long,unsigned long>guard2sel;
|
|
|
|
|
cur = 0;
|
2003-06-21 03:21:42 +02:00
|
|
|
for (unsigned idx = 0 ; idx < (1U<<esig->pin_count()) ; idx += 1) {
|
2002-07-08 00:32:15 +02:00
|
|
|
if ((idx & ~sel_mask) == sel_ref) {
|
|
|
|
|
guard2sel[idx] = cur;
|
|
|
|
|
cur += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-21 03:21:42 +02:00
|
|
|
assert(cur == (1U << sel_pins));
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2003-02-26 02:29:24 +01:00
|
|
|
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
2002-07-08 00:32:15 +02:00
|
|
|
nex_out->pin_count(),
|
2003-06-21 03:21:42 +02:00
|
|
|
1U << sel_pins, sel_pins);
|
2005-09-11 04:56:37 +02:00
|
|
|
mux->set_line(*this);
|
2002-07-08 00:32:15 +02:00
|
|
|
|
|
|
|
|
/* Connect the non-constant select bits to the select input of
|
|
|
|
|
the mux device. */
|
|
|
|
|
cur = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < esig->pin_count() ; idx += 1) {
|
|
|
|
|
/* skip bits that are known to be constant. */
|
2003-06-21 03:21:42 +02:00
|
|
|
if ((sel_mask & (1U << idx)) == 0)
|
2002-07-08 00:32:15 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
connect(mux->pin_Sel(cur), esig->pin(idx));
|
|
|
|
|
cur += 1;
|
|
|
|
|
}
|
|
|
|
|
assert(cur == sel_pins);
|
|
|
|
|
|
2003-08-28 06:11:17 +02:00
|
|
|
/* Hook up the output of the mux to the mapped output pins. */
|
2002-07-08 00:32:15 +02:00
|
|
|
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1)
|
|
|
|
|
connect(nex_out->pin(idx), mux->pin_Result(idx));
|
|
|
|
|
|
2003-03-25 05:04:29 +01:00
|
|
|
NetProc**statement_map = new NetProc*[1 << sel_pins];
|
2003-06-21 03:21:42 +02:00
|
|
|
for (unsigned item = 0 ; item < (1U<<sel_pins) ; item += 1)
|
2003-03-25 05:04:29 +01:00
|
|
|
statement_map[item] = 0;
|
|
|
|
|
|
|
|
|
|
/* Assign the input statements to MUX inputs. This involves
|
|
|
|
|
calculating the guard value, passing that through the
|
|
|
|
|
guard2sel map, then saving the statement in the
|
|
|
|
|
statement_map. If I find a default case, then save that for
|
|
|
|
|
use later. */
|
|
|
|
|
NetProc*default_statement = 0;
|
2002-07-08 00:32:15 +02:00
|
|
|
for (unsigned item = 0 ; item < nitems_ ; item += 1) {
|
2003-03-25 05:04:29 +01:00
|
|
|
/* Skip the default case this pass. */
|
|
|
|
|
if (items_[item].guard == 0) {
|
|
|
|
|
default_statement = items_[item].statement;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
|
|
|
|
|
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
|
|
|
|
|
assert(ge);
|
|
|
|
|
verinum gval = ge->value();
|
2006-01-18 02:23:23 +01:00
|
|
|
|
|
|
|
|
/* Skip guards that are unreachable. */
|
|
|
|
|
if ((sel_ref&~sel_mask) != (gval.as_ulong()&~sel_mask)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-08 00:32:15 +02:00
|
|
|
unsigned sel_idx = guard2sel[gval.as_ulong()];
|
|
|
|
|
|
2003-03-25 05:04:29 +01:00
|
|
|
assert(items_[item].statement);
|
|
|
|
|
statement_map[sel_idx] = items_[item].statement;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
/* Set up a default default_sig that uses the accumulated
|
|
|
|
|
input pins. This binding is suppressed by an actual default
|
|
|
|
|
statement if one exists. */
|
|
|
|
|
NetNet*default_sig = 0;
|
|
|
|
|
if (default_statement == 0) {
|
|
|
|
|
default_sig = accum;
|
|
|
|
|
for (unsigned idx = 0 ; idx < accum->pin_count() ; idx += 1) {
|
|
|
|
|
if (! accum->pin(idx).is_linked()) {
|
|
|
|
|
default_sig = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-11-13 23:28:48 +01:00
|
|
|
bool return_flag = true;
|
|
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
/* Now that statements match with mux inputs, synthesize the
|
2003-03-25 05:04:29 +01:00
|
|
|
sub-statements. If I get to an input that has no statement,
|
|
|
|
|
then use the default statement there. */
|
2003-06-21 03:21:42 +02:00
|
|
|
for (unsigned item = 0 ; item < (1U<<sel_pins) ; item += 1) {
|
2003-03-25 05:04:29 +01:00
|
|
|
|
|
|
|
|
/* Detect the case that this is a default input, and I
|
|
|
|
|
have a precalculated default_sig. */
|
|
|
|
|
if ((statement_map[item] == 0) && (default_sig != 0)) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1)
|
|
|
|
|
connect(mux->pin_Data(idx, item), default_sig->pin(idx));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*sig = new NetNet(scope, scope->local_symbol(),
|
2002-07-08 00:32:15 +02:00
|
|
|
NetNet::WIRE, nex_map->pin_count());
|
|
|
|
|
sig->local_flag(true);
|
2003-03-25 05:04:29 +01:00
|
|
|
|
|
|
|
|
if (statement_map[item] == 0) {
|
|
|
|
|
statement_map[item] = default_statement;
|
|
|
|
|
default_statement = 0;
|
|
|
|
|
default_sig = sig;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-01 02:30:39 +01:00
|
|
|
if (statement_map[item] == 0 && !sync_flag) {
|
2003-12-20 01:59:31 +01:00
|
|
|
/* Missing case and no default; this could still be
|
|
|
|
|
* synthesizable with synchronous logic, but not here. */
|
2005-08-22 03:00:41 +02:00
|
|
|
cerr << get_line()
|
2006-01-01 02:30:39 +01:00
|
|
|
<< ": error: Incomplete case"
|
|
|
|
|
<< " in asynchronous process"
|
|
|
|
|
<< " needs a default case." << endl;
|
2005-11-13 23:28:48 +01:00
|
|
|
return_flag = false;
|
|
|
|
|
continue;
|
2003-12-20 01:59:31 +01:00
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2006-01-01 02:30:39 +01:00
|
|
|
if (statement_map[item] == 0) {
|
|
|
|
|
|
|
|
|
|
/* If this is an unspecified case, then get the
|
|
|
|
|
input from the synchronous output. Note that we
|
|
|
|
|
know by design that there is no relevent
|
|
|
|
|
default or accum input to use here, as those
|
|
|
|
|
cases are handled above. */
|
|
|
|
|
|
|
|
|
|
for (unsigned idx=0; idx < mux->width(); idx += 1)
|
|
|
|
|
connect(mux->pin_Data(idx,item), nex_map->pin(idx));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
/* Synthesize this specified case. The synth_async will
|
|
|
|
|
connect all the output bits it knows how to the
|
|
|
|
|
sig net. */
|
|
|
|
|
statement_map[item]->synth_async(des, scope, sync_flag,
|
|
|
|
|
nex_map, sig, accum);
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1) {
|
|
|
|
|
if (sig->pin(idx).is_linked())
|
2006-01-01 03:25:07 +01:00
|
|
|
connect(mux->pin_Data(idx,item), sig->pin(idx));
|
2006-01-01 02:30:39 +01:00
|
|
|
else if (accum->pin(idx).is_linked())
|
2006-01-01 03:25:07 +01:00
|
|
|
connect(mux->pin_Data(idx,item), accum->pin(idx));
|
|
|
|
|
else if (sync_flag)
|
|
|
|
|
connect(mux->pin_Data(idx,item), nex_map->pin(idx));
|
2006-01-01 02:30:39 +01:00
|
|
|
else {
|
|
|
|
|
cerr << get_line()
|
2006-01-01 03:25:07 +01:00
|
|
|
<< ": error: case " << item << " statement"
|
2006-01-01 02:30:39 +01:00
|
|
|
<< " does not assign expected outputs." << endl;
|
|
|
|
|
return_flag = false;
|
|
|
|
|
}
|
2005-11-13 23:28:48 +01:00
|
|
|
}
|
|
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-03-25 05:04:29 +01:00
|
|
|
delete[]statement_map;
|
2002-07-08 00:32:15 +02:00
|
|
|
des->add_node(mux);
|
|
|
|
|
|
2005-11-13 23:28:48 +01:00
|
|
|
return return_flag;
|
2002-07-08 00:32:15 +02:00
|
|
|
}
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
/*
|
|
|
|
|
* If the synth_async method is called without an accumulated input
|
|
|
|
|
* (in other words not from within a block) then stub the input signal
|
|
|
|
|
* with an unconnected net.
|
|
|
|
|
*/
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2005-08-22 03:00:41 +02:00
|
|
|
{
|
|
|
|
|
const perm_string tmp = perm_string::literal("tmp");
|
|
|
|
|
NetNet*stub = new NetNet(scope, tmp, NetNet::WIRE, nex_out->pin_count());
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = synth_async(des, scope, sync_flag, nex_map, nex_out, stub);
|
2005-08-22 03:00:41 +02:00
|
|
|
delete stub;
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
/*
|
|
|
|
|
* Handle synthesis for an asynchronous condition statement. If we get
|
|
|
|
|
* here, we know that the CE of a DFF has already been filled, so the
|
|
|
|
|
* condition expression goes to the select of an asynchronous mux.
|
|
|
|
|
*/
|
|
|
|
|
bool NetCondit::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2005-08-22 03:00:41 +02:00
|
|
|
NetNet*accum)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_ENTRY("NetCondit")
|
2002-07-01 02:54:21 +02:00
|
|
|
NetNet*ssig = expr_->synthesize(des);
|
|
|
|
|
assert(ssig);
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
/* Use the accumulated input net as a default input for
|
|
|
|
|
covering a missing clause, except that if I find portions
|
|
|
|
|
are unconnected, then give up on that idea. */
|
|
|
|
|
NetNet*default_sig = accum;
|
|
|
|
|
for (unsigned idx = 0 ; idx < default_sig->pin_count() ; idx += 1) {
|
|
|
|
|
if (! default_sig->pin(idx).is_linked()) {
|
|
|
|
|
default_sig = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-12-17 17:52:39 +01:00
|
|
|
}
|
2005-08-22 03:00:41 +02:00
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
// At least one of the clauses must have contents. */
|
|
|
|
|
assert(if_ != 0 || else_ != 0);
|
|
|
|
|
|
|
|
|
|
/* If there is no default_sig, and if this is a fully
|
|
|
|
|
asynchronous process (nex_map is not a synchronous output)
|
|
|
|
|
then both clases *must* be present.
|
|
|
|
|
|
|
|
|
|
If either clause is missing, and the output is synchronous,
|
|
|
|
|
then the code below can take as the input the output from
|
|
|
|
|
the DFF without worry for asynchronous cycles. */
|
|
|
|
|
if (default_sig == 0 && ! sync_flag) {
|
2005-08-22 03:00:41 +02:00
|
|
|
if (if_ == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Asynchronous if statement"
|
|
|
|
|
<< " is missing the if clause." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2005-12-14 01:54:29 +01:00
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
if (else_ == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Asynchronous if statement"
|
|
|
|
|
<< " is missing the else clause." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-10-20 21:19:37 +02:00
|
|
|
}
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*asig = new NetNet(scope, scope->local_symbol(),
|
2002-07-01 02:54:21 +02:00
|
|
|
NetNet::WIRE, nex_map->pin_count());
|
|
|
|
|
asig->local_flag(true);
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
if (if_ == 0) {
|
2005-12-14 01:54:29 +01:00
|
|
|
/* If the if clause is missing, then take the clause to
|
|
|
|
|
be an assignment from the defaults input. If there is
|
|
|
|
|
no defaults input, then take the input to be from the
|
|
|
|
|
output. */
|
|
|
|
|
if (default_sig) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
|
|
|
|
connect(asig->pin(idx), default_sig->pin(idx));
|
|
|
|
|
} else {
|
|
|
|
|
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
|
|
|
|
connect(asig->pin(idx), nex_map->pin(idx));
|
|
|
|
|
}
|
2005-08-22 03:00:41 +02:00
|
|
|
|
|
|
|
|
} else {
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = if_->synth_async(des, scope, sync_flag,
|
|
|
|
|
nex_map, asig, accum);
|
2005-08-22 03:00:41 +02:00
|
|
|
if (!flag) {
|
|
|
|
|
delete asig;
|
|
|
|
|
cerr << get_line() << ": error: Asynchronous if statement"
|
|
|
|
|
<< " true clause failed to synthesize." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-12-20 01:59:31 +01:00
|
|
|
}
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*bsig = new NetNet(scope, scope->local_symbol(),
|
2002-07-01 02:54:21 +02:00
|
|
|
NetNet::WIRE, nex_map->pin_count());
|
|
|
|
|
bsig->local_flag(true);
|
|
|
|
|
|
2005-08-22 03:00:41 +02:00
|
|
|
if (else_ == 0) {
|
2005-12-14 01:54:29 +01:00
|
|
|
if (default_sig) {
|
|
|
|
|
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
|
|
|
|
connect(bsig->pin(idx), default_sig->pin(idx));
|
|
|
|
|
} else {
|
|
|
|
|
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1)
|
|
|
|
|
connect(bsig->pin(idx), nex_map->pin(idx));
|
|
|
|
|
}
|
2005-08-22 03:00:41 +02:00
|
|
|
} else {
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = else_->synth_async(des, scope, sync_flag,
|
|
|
|
|
nex_map, bsig, accum);
|
2005-08-22 03:00:41 +02:00
|
|
|
if (!flag) {
|
|
|
|
|
delete asig;
|
|
|
|
|
delete bsig;
|
|
|
|
|
cerr << get_line() << ": error: Asynchronous if statement"
|
|
|
|
|
<< " else clause failed to synthesize." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2003-12-20 01:59:31 +01:00
|
|
|
}
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2003-02-26 02:29:24 +01:00
|
|
|
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
2002-07-01 02:54:21 +02:00
|
|
|
nex_out->pin_count(), 2, 1);
|
2005-09-11 04:56:37 +02:00
|
|
|
mux->set_line(*this);
|
2002-07-01 02:54:21 +02:00
|
|
|
|
|
|
|
|
connect(mux->pin_Sel(0), ssig->pin(0));
|
|
|
|
|
|
2005-11-16 01:38:26 +01:00
|
|
|
bool return_flag = true;
|
|
|
|
|
|
|
|
|
|
/* Connected the clauses to the data inputs of the
|
|
|
|
|
condition. If there are bits unassigned by the case, then
|
2005-12-15 03:38:51 +01:00
|
|
|
bind them from the accum bits instead. If the bit is not
|
|
|
|
|
represented in the accum list, but this is a synchronous
|
|
|
|
|
output, then get the bit from the nex_map, which is the
|
|
|
|
|
output held in the DFF. */
|
2005-11-16 01:38:26 +01:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < asig->pin_count() ; idx += 1) {
|
|
|
|
|
if (asig->pin(idx).is_linked())
|
|
|
|
|
connect(mux->pin_Data(idx, 1), asig->pin(idx));
|
|
|
|
|
else if (accum->pin(idx).is_linked())
|
|
|
|
|
connect(mux->pin_Data(idx, 1), accum->pin(idx));
|
2005-12-15 03:38:51 +01:00
|
|
|
else if (sync_flag)
|
|
|
|
|
connect(mux->pin_Data(idx, 1), nex_map->pin(idx));
|
2005-11-16 01:38:26 +01:00
|
|
|
else {
|
|
|
|
|
cerr << get_line()
|
|
|
|
|
<< ": error: Condition true clause "
|
2005-12-15 03:38:51 +01:00
|
|
|
<< "does not assign expected outputs." << endl;
|
2005-11-16 01:38:26 +01:00
|
|
|
return_flag = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2005-11-16 01:38:26 +01:00
|
|
|
for (unsigned idx = 0 ; idx < bsig->pin_count() ; idx += 1) {
|
|
|
|
|
if (bsig->pin(idx).is_linked())
|
|
|
|
|
connect(mux->pin_Data(idx, 0), bsig->pin(idx));
|
|
|
|
|
else if (accum->pin(idx).is_linked())
|
|
|
|
|
connect(mux->pin_Data(idx, 0), accum->pin(idx));
|
2005-12-15 03:38:51 +01:00
|
|
|
else if (sync_flag)
|
|
|
|
|
connect(mux->pin_Data(idx, 0), nex_map->pin(idx));
|
2005-11-16 01:38:26 +01:00
|
|
|
else {
|
|
|
|
|
cerr << get_line()
|
|
|
|
|
<< ": error: Condition false clause "
|
2005-12-15 03:38:51 +01:00
|
|
|
<< "does not assign expected outputs." << endl;
|
2005-11-16 01:38:26 +01:00
|
|
|
return_flag = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-07-01 02:54:21 +02:00
|
|
|
|
|
|
|
|
for (unsigned idx = 0 ; idx < mux->width() ; idx += 1)
|
|
|
|
|
connect(nex_out->pin(idx), mux->pin_Result(idx));
|
|
|
|
|
|
|
|
|
|
des->add_node(mux);
|
|
|
|
|
|
|
|
|
|
return true;
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool NetEvWait::synth_async(Design*des, NetScope*scope, bool sync_flag,
|
|
|
|
|
NetNet*nex_map, NetNet*nex_out)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = statement_->synth_async(des, scope, sync_flag,
|
|
|
|
|
nex_map, nex_out);
|
2003-12-17 17:52:39 +01:00
|
|
|
return flag;
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetProcTop::synth_async(Design*des)
|
|
|
|
|
{
|
2002-07-01 02:54:21 +02:00
|
|
|
NexusSet nex_set;
|
|
|
|
|
statement_->nex_output(nex_set);
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
const perm_string tmp1 = perm_string::literal("tmp");
|
|
|
|
|
NetNet*nex_out = new NetNet(scope(), tmp1, NetNet::WIRE,
|
2002-07-01 02:54:21 +02:00
|
|
|
nex_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < nex_out->pin_count() ; idx += 1)
|
|
|
|
|
connect(nex_set[idx], nex_out->pin(idx));
|
|
|
|
|
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = statement_->synth_async(des, scope(), false,
|
|
|
|
|
nex_out, nex_out);
|
2002-07-01 02:54:21 +02:00
|
|
|
|
|
|
|
|
delete nex_out;
|
|
|
|
|
return flag;
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
2005-12-19 02:13:47 +01:00
|
|
|
static bool merge_ff_slices(NetFF*ff1, unsigned idx1,
|
|
|
|
|
NetFF*ff2, unsigned idx2)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* If the Aset inputs are connected, and not to each other
|
|
|
|
|
(possible since pre-existing Asets are carried forwards)
|
|
|
|
|
then there is a conflict. */
|
|
|
|
|
if (ff1->pin_Aset().is_linked()
|
|
|
|
|
&& ff2->pin_Aset().is_linked()
|
|
|
|
|
&& ! ff1->pin_Aset().is_linked(ff2->pin_Aset())) {
|
|
|
|
|
cerr << ff2->get_line() << ": error: "
|
|
|
|
|
<< "DFF Aset conflicts with "
|
|
|
|
|
<< ff1->get_line() << "." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ff1->pin_Aclr().is_linked()
|
|
|
|
|
&& ff2->pin_Aclr().is_linked()
|
|
|
|
|
&& ! ff1->pin_Aclr().is_linked(ff2->pin_Aclr())) {
|
|
|
|
|
cerr << ff2->get_line() << ": error: "
|
|
|
|
|
<< "DFF Aclr conflicts with "
|
|
|
|
|
<< ff1->get_line() << "." << endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
#if XXXX
|
2005-12-19 02:13:47 +01:00
|
|
|
if (ff2->pin_Data(idx2).is_linked())
|
|
|
|
|
connect(ff1->pin_Data(idx1), ff2->pin_Data(idx2));
|
|
|
|
|
if (ff2->pin_Aset().is_linked())
|
|
|
|
|
connect(ff1->pin_Aset(), ff2->pin_Aset());
|
|
|
|
|
if (ff2->pin_Aclr().is_linked())
|
|
|
|
|
connect(ff1->pin_Aclr(), ff2->pin_Aclr());
|
2006-01-18 02:23:23 +01:00
|
|
|
if (ff2->pin_Sclr().is_linked())
|
|
|
|
|
connect(ff1->pin_Sclr(), ff2->pin_Sclr());
|
|
|
|
|
if (ff2->pin_Sset().is_linked())
|
|
|
|
|
connect(ff1->pin_Sset(), ff2->pin_Sset());
|
|
|
|
|
if (ff2->pin_Clock().is_linked())
|
|
|
|
|
connect(ff1->pin_Clock(), ff2->pin_Clock());
|
|
|
|
|
#endif
|
|
|
|
|
if (ff2->pin_Enable().is_linked())
|
|
|
|
|
connect(ff1->pin_Enable(),ff2->pin_Enable());
|
2005-12-19 02:13:47 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/*
|
|
|
|
|
* This method is called when a block is encountered near the surface
|
|
|
|
|
* of a synchronous always statement. For example, this code will be
|
|
|
|
|
* invoked for input like this:
|
|
|
|
|
*
|
|
|
|
|
* always @(posedge clk...) begin
|
|
|
|
|
* <statement1>
|
|
|
|
|
* <statement2>
|
|
|
|
|
* ...
|
|
|
|
|
* end
|
|
|
|
|
*
|
|
|
|
|
* This needs to be split into a DFF bank for each statement, because
|
|
|
|
|
* the statements may each infer different reset and enable signals.
|
|
|
|
|
*/
|
2006-01-18 02:23:23 +01:00
|
|
|
bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
|
|
|
|
struct sync_accounting_cell*nex_ff,
|
2005-12-14 01:54:29 +01:00
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
|
|
|
|
const svector<NetEvProbe*>&events_in)
|
2002-10-21 03:42:08 +02:00
|
|
|
{
|
2005-12-19 02:13:47 +01:00
|
|
|
/* Do nothing for empty blocks. */
|
|
|
|
|
if (last_ == 0)
|
2002-10-21 03:42:08 +02:00
|
|
|
return true;
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
/* Assert that this region still represents a single DFF. */
|
|
|
|
|
for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) {
|
|
|
|
|
assert(nex_ff[0].ff == nex_ff[idx].ff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetFF*ff = nex_ff[0].ff;
|
|
|
|
|
|
|
|
|
|
assert(ff->width() == nex_out->pin_count());
|
|
|
|
|
unsigned block_width = nex_out->pin_count();
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
bool flag = true;
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
const perm_string tmp1 = perm_string::literal("tmp1");
|
|
|
|
|
const perm_string tmp2 = perm_string::literal("tmp2");
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
NetProc*cur = last_;
|
|
|
|
|
do {
|
|
|
|
|
cur = cur->next_;
|
|
|
|
|
|
|
|
|
|
/* Create a temporary nex_map for the substatement. */
|
|
|
|
|
NexusSet tmp_set;
|
|
|
|
|
cur->nex_output(tmp_set);
|
2004-02-18 18:11:54 +01:00
|
|
|
NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE,
|
2002-10-21 03:42:08 +02:00
|
|
|
tmp_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
|
|
|
|
|
connect(tmp_set[idx], tmp_map->pin(idx));
|
|
|
|
|
|
2003-08-14 04:41:05 +02:00
|
|
|
/* NOTE: After this point, tmp_set should not be used as
|
|
|
|
|
the various functions I call do a lot of connecting,
|
|
|
|
|
and the nexa in the tmp_set may get realloced. Use
|
|
|
|
|
the tmp_map instead. */
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/* Create also a temporary net_out to collect the
|
2002-11-09 21:22:57 +01:00
|
|
|
output. The tmp1 and tmp2 map and out sets together
|
|
|
|
|
are used to collect the outputs from the substatement
|
|
|
|
|
for the inputs of the FF bank. */
|
2004-02-18 18:11:54 +01:00
|
|
|
NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE,
|
2003-08-14 04:41:05 +02:00
|
|
|
tmp_map->pin_count());
|
2002-10-21 03:42:08 +02:00
|
|
|
|
2002-10-23 03:45:24 +02:00
|
|
|
verinum tmp_aset = ff->aset_value();
|
2003-08-15 04:23:52 +02:00
|
|
|
verinum tmp_sset = ff->sset_value();
|
2002-10-23 03:45:24 +02:00
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/* Create a new DFF to handle this part of the begin-end
|
|
|
|
|
block. Connect this NetFF to the associated pins of
|
2002-10-23 03:45:24 +02:00
|
|
|
the existing wide NetFF device. While I'm at it, also
|
|
|
|
|
copy the aset_value bits for the new ff device. */
|
2004-02-18 18:11:54 +01:00
|
|
|
NetFF*ff2 = new NetFF(scope, scope->local_symbol(),
|
2002-10-21 03:42:08 +02:00
|
|
|
tmp_out->pin_count());
|
2005-12-19 02:13:47 +01:00
|
|
|
ff2->set_line(*cur);
|
2002-10-21 03:42:08 +02:00
|
|
|
des->add_node(ff2);
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
struct sync_accounting_cell*tmp_ff
|
|
|
|
|
= new struct sync_accounting_cell[ff2->width()];
|
|
|
|
|
|
2002-10-23 03:45:24 +02:00
|
|
|
verinum aset_value2 (verinum::V1, ff2->width());
|
2003-08-15 04:23:52 +02:00
|
|
|
verinum sset_value2 (verinum::V1, ff2->width());
|
2002-10-21 03:42:08 +02:00
|
|
|
for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
|
2003-08-14 04:41:05 +02:00
|
|
|
unsigned ptr = find_nexus_in_set(nex_map,
|
|
|
|
|
tmp_map->pin(idx).nexus());
|
2003-08-15 04:23:52 +02:00
|
|
|
|
|
|
|
|
/* Copy the asynch set bit to the new device. */
|
2002-10-23 03:45:24 +02:00
|
|
|
if (ptr < tmp_aset.len())
|
|
|
|
|
aset_value2.set(idx, tmp_aset[ptr]);
|
2002-11-09 21:22:57 +01:00
|
|
|
|
2003-08-15 04:23:52 +02:00
|
|
|
/* Copy the synch set bit to the new device. */
|
|
|
|
|
if (ptr < tmp_sset.len())
|
|
|
|
|
sset_value2.set(idx, tmp_sset[ptr]);
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
// Connect the tmp_out vector, what the
|
|
|
|
|
// sub-synthesis is linking, to the inputs of this
|
|
|
|
|
// new FF.
|
|
|
|
|
connect(tmp_out->pin(idx), ff2->pin_Data(idx));
|
|
|
|
|
tmp_ff[idx].ff = ff2;
|
|
|
|
|
tmp_ff[idx].pin = idx;
|
|
|
|
|
tmp_ff[idx].proc = cur;
|
2002-10-21 03:42:08 +02:00
|
|
|
}
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2005-12-19 02:13:47 +01:00
|
|
|
/* PUll the non-sliced inputs (clock, set, reset, etc)
|
|
|
|
|
forward to the new FF we are building. */
|
2002-10-21 03:42:08 +02:00
|
|
|
if (ff->pin_Aclr().is_linked())
|
|
|
|
|
connect(ff->pin_Aclr(), ff2->pin_Aclr());
|
|
|
|
|
if (ff->pin_Aset().is_linked())
|
|
|
|
|
connect(ff->pin_Aset(), ff2->pin_Aset());
|
2003-08-15 04:23:52 +02:00
|
|
|
if (ff->pin_Sclr().is_linked())
|
|
|
|
|
connect(ff->pin_Sclr(), ff2->pin_Sclr());
|
|
|
|
|
if (ff->pin_Sset().is_linked())
|
|
|
|
|
connect(ff->pin_Sset(), ff2->pin_Sset());
|
2002-10-21 03:42:08 +02:00
|
|
|
if (ff->pin_Clock().is_linked())
|
|
|
|
|
connect(ff->pin_Clock(), ff2->pin_Clock());
|
|
|
|
|
if (ff->pin_Enable().is_linked())
|
|
|
|
|
connect(ff->pin_Enable(),ff2->pin_Enable());
|
|
|
|
|
|
2002-10-23 03:45:24 +02:00
|
|
|
/* Remember to store the aset value into the new FF. If
|
|
|
|
|
this leads to an Aset value of 0 (and Aclr is not
|
|
|
|
|
otherwise used) then move the Aset input to Aclr. */
|
|
|
|
|
if (tmp_aset.len() == ff->width()) {
|
|
|
|
|
|
2003-04-03 06:30:00 +02:00
|
|
|
if (aset_value2.is_zero()
|
2002-10-23 03:45:24 +02:00
|
|
|
&& ff2->pin_Aset().is_linked()
|
|
|
|
|
&& !ff2->pin_Aclr().is_linked()) {
|
|
|
|
|
|
|
|
|
|
ff2->pin_Aset().unlink();
|
2006-01-18 02:23:23 +01:00
|
|
|
connect(ff2->pin_Aclr(), ff->pin_Aset());
|
2002-10-23 03:45:24 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
ff2->aset_value(aset_value2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/* Now go on with the synchronous synthesis for this
|
2005-12-31 05:28:14 +01:00
|
|
|
statement of the block. The tmp_map is the output
|
2003-08-14 04:41:05 +02:00
|
|
|
nexa that we expect, and the tmp_out is where we want
|
|
|
|
|
those outputs connected. */
|
2006-01-18 02:23:23 +01:00
|
|
|
bool ok_flag = cur->synth_sync(des, scope,
|
|
|
|
|
tmp_ff, tmp_map, tmp_out,
|
|
|
|
|
events_in);
|
|
|
|
|
ff2 = 0; // NOTE: The synth_sync may delete ff2.
|
2002-10-21 03:42:08 +02:00
|
|
|
flag = flag && ok_flag;
|
|
|
|
|
|
|
|
|
|
if (ok_flag == false)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Use the nex_map to link up the output from the
|
2002-11-06 04:22:28 +01:00
|
|
|
substatement to the output of the block as a
|
|
|
|
|
whole. It is occasionally possible to have outputs
|
|
|
|
|
beyond the input set, for example when the l-value of
|
|
|
|
|
an assignment is smaller then the r-value. */
|
2002-10-21 03:42:08 +02:00
|
|
|
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
|
2006-01-18 02:23:23 +01:00
|
|
|
ff2 = tmp_ff[idx].ff;
|
|
|
|
|
unsigned ff2_pin = tmp_ff[idx].pin;
|
2003-08-14 04:41:05 +02:00
|
|
|
unsigned ptr = find_nexus_in_set(nex_map,
|
2006-01-18 02:23:23 +01:00
|
|
|
tmp_map->pin(idx).nexus());
|
2003-08-14 04:41:05 +02:00
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
if (ptr >= nex_out->pin_count())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
// This is the current DFF for this bit slice...
|
|
|
|
|
NetFF*ff1 = nex_ff[ptr].ff;
|
|
|
|
|
unsigned ff1_pin = nex_ff[ptr].pin;
|
|
|
|
|
|
|
|
|
|
// Connect the new NetFF to the baseline
|
|
|
|
|
// NetFF Q and D pins.
|
|
|
|
|
connect(ff1->pin_Data(ff1_pin), ff2->pin_Data(ff2_pin));
|
|
|
|
|
connect(ff1->pin_Q(ff1_pin), ff2->pin_Q(ff2_pin));
|
|
|
|
|
// Merge the new ff2 with the current ff1. This
|
|
|
|
|
// brings all the non-sliced bits forward from
|
|
|
|
|
// ff1, as well as any other merging needed.
|
|
|
|
|
merge_ff_slices(ff2, ff2_pin, ff1, ff1_pin);
|
|
|
|
|
|
|
|
|
|
// Save the bit slice map as the new referece.
|
|
|
|
|
nex_ff[ptr] = tmp_ff[idx];
|
|
|
|
|
|
|
|
|
|
// If the (old) current DFF is not the same as the
|
|
|
|
|
// baseline DFF, then it is possible that the
|
|
|
|
|
// slice update rendered ff1 obsolete. If so, it
|
|
|
|
|
// will no longer appear in the nex_ff map, so
|
|
|
|
|
// remove it.
|
|
|
|
|
if (ff1 != ff) {
|
|
|
|
|
bool found_flag = false;
|
|
|
|
|
for (unsigned scan=0
|
|
|
|
|
; scan < ff->width() && !found_flag
|
|
|
|
|
; scan += 1) {
|
|
|
|
|
if (nex_ff[scan].ff == ff1)
|
|
|
|
|
found_flag = true;
|
|
|
|
|
}
|
|
|
|
|
if (! found_flag) {
|
|
|
|
|
delete ff1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-10-21 03:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete tmp_map;
|
|
|
|
|
delete tmp_out;
|
2006-01-18 02:23:23 +01:00
|
|
|
delete tmp_ff;
|
2002-10-21 03:42:08 +02:00
|
|
|
|
|
|
|
|
} while (cur != last_);
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
/* Done. The large NetFF is no longer needed, as it has been
|
|
|
|
|
taken up by the smaller NetFF devices. */
|
|
|
|
|
delete ff;
|
|
|
|
|
ff = 0;
|
|
|
|
|
|
2005-12-19 02:13:47 +01:00
|
|
|
/* Run through the pin accounting one more time to make sure
|
|
|
|
|
the data inputs are all connected. */
|
2006-01-18 02:23:23 +01:00
|
|
|
for (unsigned idx = 0 ; idx < block_width ; idx += 1) {
|
|
|
|
|
if (nex_ff[idx].proc == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
NetFF*ff2 = nex_ff[idx].ff;
|
|
|
|
|
unsigned pin = nex_ff[idx].pin;
|
2005-12-19 02:13:47 +01:00
|
|
|
/* Skip this output if it is not handled in this block. */
|
|
|
|
|
if (ff2 == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
2005-12-31 05:28:14 +01:00
|
|
|
if (pin >= ff2->width()) {
|
|
|
|
|
cerr << ff2->get_line() << ": internal error: "
|
|
|
|
|
<< "pin " << pin << " out of range of "
|
|
|
|
|
<< ff2->width() << " bit DFF." << endl;
|
|
|
|
|
flag = false;
|
|
|
|
|
|
2005-12-19 02:13:47 +01:00
|
|
|
/* If this block mentioned it, then the data must have
|
|
|
|
|
been set here. */
|
2005-12-31 05:28:14 +01:00
|
|
|
} else if (!ff2->pin_Data(pin).is_linked()) {
|
2005-12-19 02:13:47 +01:00
|
|
|
cerr << ff2->get_line() << ": error: "
|
2006-01-18 02:23:23 +01:00
|
|
|
<< "DFF introduced here is missing Data "
|
|
|
|
|
<< pin << " input." << endl;
|
2005-12-19 02:13:47 +01:00
|
|
|
flag = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* This method handles the case where I find a conditional near the
|
|
|
|
|
* surface of a synchronous thread. This conditional can be a CE or an
|
|
|
|
|
* asynchronous set/reset, depending on whether the pin of the
|
|
|
|
|
* expression is connected to an event, or not.
|
|
|
|
|
*/
|
2006-01-18 02:23:23 +01:00
|
|
|
bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
|
|
|
|
struct sync_accounting_cell*nex_ff,
|
2005-12-14 01:54:29 +01:00
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events_in)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2006-01-18 02:23:23 +01:00
|
|
|
for (unsigned idx = 1 ; idx < nex_out->pin_count() ; idx += 1) {
|
|
|
|
|
assert(nex_ff[0].ff == nex_ff[idx].ff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetFF*ff = nex_ff[0].ff;
|
|
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
/* First try to turn the condition expression into an
|
|
|
|
|
asynchronous set/reset. If the condition expression has
|
|
|
|
|
inputs that are included in the sensitivity list, then it
|
|
|
|
|
is likely intended as an asynchronous input. */
|
2002-11-10 00:29:29 +01:00
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
NexusSet*expr_input = expr_->nex_input();
|
|
|
|
|
assert(expr_input);
|
2002-09-26 03:13:14 +02:00
|
|
|
for (unsigned idx = 0 ; idx < events_in.count() ; idx += 1) {
|
|
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
NetEvProbe*ev = events_in[idx];
|
|
|
|
|
NexusSet pin_set;
|
|
|
|
|
pin_set.add(ev->pin(0).nexus());
|
2002-10-23 03:45:24 +02:00
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
if (! expr_input->contains(pin_set))
|
|
|
|
|
continue;
|
2002-10-23 03:45:24 +02:00
|
|
|
|
2005-12-07 03:14:37 +01:00
|
|
|
/* If we are taking this to be an asynchronous
|
|
|
|
|
set/clear, then *all* the condition expression inputs
|
|
|
|
|
must be asynchronous. Check that here. */
|
|
|
|
|
if (! pin_set.contains(*expr_input)) {
|
|
|
|
|
|
|
|
|
|
NexusSet tmp_set;
|
|
|
|
|
tmp_set.add(ev->pin(0).nexus());
|
|
|
|
|
for (unsigned tmp = idx+1; tmp<events_in.count(); tmp += 1) {
|
|
|
|
|
NetEvProbe*ev_tmp = events_in[tmp];
|
|
|
|
|
tmp_set.add(ev_tmp->pin(0).nexus());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! tmp_set.contains(*expr_input)) {
|
|
|
|
|
cerr << get_line() << ": error: Condition expression "
|
|
|
|
|
<< "mixes synchronous and asynchronous "
|
|
|
|
|
<< "inputs." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
/* Ah, this edge is in the sensitivity list for the
|
|
|
|
|
expression, so we have an asynchronous
|
|
|
|
|
input. Synthesize the set/reset input expression. */
|
|
|
|
|
|
|
|
|
|
NetNet*rst = expr_->synthesize(des);
|
|
|
|
|
assert(rst->pin_count() == 1);
|
|
|
|
|
|
|
|
|
|
/* XXXX I really should find a way to check that the
|
|
|
|
|
edge used on the reset input is correct. This would
|
|
|
|
|
involve interpreting the exression that is fed by the
|
|
|
|
|
reset expression. */
|
|
|
|
|
//assert(ev->edge() == NetEvProbe::POSEDGE);
|
|
|
|
|
|
|
|
|
|
/* Synthesize the true clause to figure out what
|
|
|
|
|
kind of set/reset we have. */
|
|
|
|
|
NetNet*asig = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
NetNet::WIRE, nex_map->pin_count());
|
|
|
|
|
asig->local_flag(true);
|
2003-10-27 03:18:04 +01:00
|
|
|
|
|
|
|
|
assert(if_ != 0);
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = if_->synth_async(des, scope, true, nex_map, asig);
|
2003-08-10 19:04:23 +02:00
|
|
|
|
|
|
|
|
assert(asig->pin_count() == ff->width());
|
|
|
|
|
|
|
|
|
|
/* Collect the set/reset value into a verinum. If
|
|
|
|
|
this turns out to be entirely 0 values, then
|
|
|
|
|
use the Aclr input. Otherwise, use the Aset
|
|
|
|
|
input and save the set value. */
|
|
|
|
|
verinum tmp (verinum::V0, ff->width());
|
|
|
|
|
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
|
|
|
|
|
|
|
|
|
|
assert(asig->pin(bit).nexus()->drivers_constant());
|
|
|
|
|
tmp.set(bit, asig->pin(bit).nexus()->driven_value());
|
|
|
|
|
}
|
2002-09-26 03:13:14 +02:00
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
assert(tmp.is_defined());
|
|
|
|
|
if (tmp.is_zero()) {
|
|
|
|
|
connect(ff->pin_Aclr(), rst->pin(0));
|
2002-09-26 03:13:14 +02:00
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
} else {
|
|
|
|
|
connect(ff->pin_Aset(), rst->pin(0));
|
|
|
|
|
ff->aset_value(tmp);
|
2002-09-26 03:13:14 +02:00
|
|
|
}
|
|
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
delete asig;
|
|
|
|
|
delete expr_input;
|
|
|
|
|
|
2005-12-07 03:14:37 +01:00
|
|
|
if (else_ == 0) {
|
2005-12-19 02:13:47 +01:00
|
|
|
|
|
|
|
|
/* The lack of an else_ clause here means that
|
|
|
|
|
there is no data input to the DFF yet
|
|
|
|
|
defined. This is bad, but the data input may be
|
|
|
|
|
given later in an enclosing block, so don't
|
|
|
|
|
report an error here quite yet. */
|
|
|
|
|
return true;
|
2005-12-07 03:14:37 +01:00
|
|
|
}
|
|
|
|
|
|
2003-10-27 03:18:04 +01:00
|
|
|
assert(else_ != 0);
|
2005-12-14 02:53:39 +01:00
|
|
|
|
|
|
|
|
/* Create a new NetEvProbe list that does not include
|
|
|
|
|
the current probe that we've absorbed into this
|
|
|
|
|
input. */
|
|
|
|
|
assert(events_in.count() >= 1);
|
|
|
|
|
svector<NetEvProbe*> events_tmp (events_in.count() - 1);
|
|
|
|
|
unsigned count_events = 0;
|
|
|
|
|
for (unsigned tmp = 0 ; tmp < events_in.count() ; tmp += 1) {
|
|
|
|
|
if (tmp == idx) continue;
|
|
|
|
|
events_tmp[count_events++] = events_in[tmp];
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
flag = flag && else_->synth_sync(des, scope,
|
|
|
|
|
nex_ff, nex_map,
|
2005-12-14 02:53:39 +01:00
|
|
|
nex_out, events_tmp);
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
return flag;
|
2002-09-26 03:13:14 +02:00
|
|
|
}
|
|
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
delete expr_input;
|
|
|
|
|
|
2003-08-15 04:23:52 +02:00
|
|
|
/* Detect the case that this is a *synchronous* set/reset. It
|
|
|
|
|
is not asyncronous because we know the condition is not
|
|
|
|
|
included in the sensitivity list, but if the if_ case is
|
|
|
|
|
constant (has no inputs) then we can model this as a
|
2003-10-27 03:18:04 +01:00
|
|
|
synchronous set/reset.
|
|
|
|
|
|
|
|
|
|
This is only synchronous set/reset if there is a true and a
|
|
|
|
|
false clause, and no inputs. The "no inputs" requirement is
|
2006-01-18 07:16:11 +01:00
|
|
|
met if the assignments are of all constant values.
|
|
|
|
|
|
|
|
|
|
Also, we will not allow both Sset and Sclr to be used on a
|
|
|
|
|
single LPM_FF (due to unclear priority issues) so don't try
|
|
|
|
|
if either are already connected. */
|
2003-10-27 03:18:04 +01:00
|
|
|
assert(if_ != 0);
|
2003-08-15 04:23:52 +02:00
|
|
|
NexusSet*a_set = if_->nex_input();
|
|
|
|
|
|
2006-01-18 07:16:11 +01:00
|
|
|
if ((a_set->count() == 0)
|
|
|
|
|
&& if_ && else_
|
|
|
|
|
&& !ff->pin_Sset().is_linked()
|
|
|
|
|
&& !ff->pin_Sclr().is_linked()) {
|
2003-08-15 04:23:52 +02:00
|
|
|
|
|
|
|
|
NetNet*rst = expr_->synthesize(des);
|
|
|
|
|
assert(rst->pin_count() == 1);
|
|
|
|
|
|
|
|
|
|
/* Synthesize the true clause to figure out what
|
|
|
|
|
kind of set/reset we have. */
|
|
|
|
|
NetNet*asig = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
NetNet::WIRE, nex_map->pin_count());
|
|
|
|
|
asig->local_flag(true);
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = if_->synth_async(des, scope, true, nex_map, asig);
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
if (!flag) {
|
|
|
|
|
/* This path leads nowhere */
|
|
|
|
|
delete asig;
|
|
|
|
|
} else {
|
|
|
|
|
assert(asig->pin_count() == ff->width());
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
/* Collect the set/reset value into a verinum. If
|
|
|
|
|
this turns out to be entirely 0 values, then
|
|
|
|
|
use the Sclr input. Otherwise, use the Aset
|
|
|
|
|
input and save the set value. */
|
|
|
|
|
verinum tmp (verinum::V0, ff->width());
|
|
|
|
|
for (unsigned bit = 0 ; bit < ff->width() ; bit += 1) {
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
assert(asig->pin(bit).nexus()->drivers_constant());
|
|
|
|
|
tmp.set(bit, asig->pin(bit).nexus()->driven_value());
|
|
|
|
|
}
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2005-12-10 05:26:32 +01:00
|
|
|
if (! tmp.is_defined())
|
|
|
|
|
cerr << get_line() << ": internal error: "
|
|
|
|
|
<< "Strange clr r-value=" << tmp << endl;
|
|
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
assert(tmp.is_defined());
|
|
|
|
|
if (tmp.is_zero()) {
|
|
|
|
|
connect(ff->pin_Sclr(), rst->pin(0));
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
} else {
|
|
|
|
|
connect(ff->pin_Sset(), rst->pin(0));
|
|
|
|
|
ff->sset_value(tmp);
|
|
|
|
|
}
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
delete a_set;
|
2003-08-15 04:23:52 +02:00
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
assert(else_ != 0);
|
2006-01-18 02:23:23 +01:00
|
|
|
flag = else_->synth_sync(des, scope,
|
|
|
|
|
nex_ff, nex_map, nex_out,
|
|
|
|
|
svector<NetEvProbe*>(0))
|
2003-12-20 01:59:31 +01:00
|
|
|
&& flag;
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
2003-08-15 04:23:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete a_set;
|
|
|
|
|
|
2002-09-26 03:13:14 +02:00
|
|
|
/* Failed to find an asynchronous set/reset, so any events
|
2005-12-19 02:13:47 +01:00
|
|
|
input are probably in error, or simply not in use. */
|
2002-09-26 03:13:14 +02:00
|
|
|
|
2003-08-10 19:04:23 +02:00
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
/* If this is an if/then/else, then it is likely a
|
|
|
|
|
combinational if, and I should synthesize it that way. */
|
|
|
|
|
if (if_ && else_) {
|
2005-12-14 01:54:29 +01:00
|
|
|
bool flag = synth_async(des, scope, true, nex_map, nex_out);
|
2003-12-17 17:52:39 +01:00
|
|
|
return flag;
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(if_);
|
|
|
|
|
assert(!else_);
|
|
|
|
|
|
2003-08-14 04:41:05 +02:00
|
|
|
/* Synthesize the enable expression. */
|
|
|
|
|
NetNet*ce = expr_->synthesize(des);
|
|
|
|
|
assert(ce->pin_count() == 1);
|
|
|
|
|
|
2002-11-10 00:29:29 +01:00
|
|
|
/* What's left, is a synchronous CE statement like this:
|
|
|
|
|
|
|
|
|
|
if (expr_) <true statement>;
|
|
|
|
|
|
2003-01-27 06:09:17 +01:00
|
|
|
The expr_ expression has already been synthesized to the ce
|
2002-11-10 00:29:29 +01:00
|
|
|
net, so we connect it here to the FF. What's left is to
|
|
|
|
|
synthesize the substatement as a combinational
|
|
|
|
|
statement.
|
|
|
|
|
|
|
|
|
|
Watch out for the special case that there is already a CE
|
|
|
|
|
connected to this FF. This can be caused by code like this:
|
|
|
|
|
|
|
|
|
|
if (a) if (b) <statement>;
|
|
|
|
|
|
|
|
|
|
In this case, we are working on the inner IF, so we AND the
|
|
|
|
|
a and b expressions to make a new CE. */
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2002-11-10 00:29:29 +01:00
|
|
|
if (ff->pin_Enable().is_linked()) {
|
|
|
|
|
NetLogic*ce_and = new NetLogic(scope,
|
2004-02-18 18:11:54 +01:00
|
|
|
scope->local_symbol(), 3,
|
2002-11-10 00:29:29 +01:00
|
|
|
NetLogic::AND);
|
|
|
|
|
des->add_node(ce_and);
|
|
|
|
|
connect(ff->pin_Enable(), ce_and->pin(1));
|
|
|
|
|
connect(ce->pin(0), ce_and->pin(2));
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2002-11-10 00:29:29 +01:00
|
|
|
ff->pin_Enable().unlink();
|
|
|
|
|
connect(ff->pin_Enable(), ce_and->pin(0));
|
|
|
|
|
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
|
2002-11-10 00:29:29 +01:00
|
|
|
NetNet::IMPLICIT, 1);
|
|
|
|
|
tmp->local_flag(true);
|
|
|
|
|
connect(ff->pin_Enable(), tmp->pin(0));
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
connect(ff->pin_Enable(), ce->pin(0));
|
|
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
bool flag = if_->synth_sync(des, scope,
|
|
|
|
|
nex_ff, nex_map, nex_out,
|
|
|
|
|
events_in);
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
return flag;
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
|
|
|
|
struct sync_accounting_cell*nex_ff,
|
2005-12-14 01:54:29 +01:00
|
|
|
NetNet*nex_map, NetNet*nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events_in)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_ENTRY("NetEvWait")
|
2002-09-26 03:13:14 +02:00
|
|
|
if (events_in.count() > 0) {
|
|
|
|
|
cerr << get_line() << ": error: Events are unaccounted"
|
2005-12-19 02:13:47 +01:00
|
|
|
<< " for in process synthesis. (evw)" << endl;
|
2002-09-26 03:13:14 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(events_in.count() == 0);
|
|
|
|
|
|
2002-09-24 02:58:35 +02:00
|
|
|
/* This can't be other then one unless there are named events,
|
|
|
|
|
which I cannot synthesize. */
|
2002-09-16 02:30:33 +02:00
|
|
|
assert(nevents_ == 1);
|
|
|
|
|
NetEvent*ev = events_[0];
|
|
|
|
|
|
2002-09-24 02:58:35 +02:00
|
|
|
assert(ev->nprobe() >= 1);
|
2002-09-26 03:13:14 +02:00
|
|
|
svector<NetEvProbe*>events (ev->nprobe() - 1);
|
2002-09-24 02:58:35 +02:00
|
|
|
|
|
|
|
|
/* Get the input set from the substatement. This will be used
|
|
|
|
|
to figure out which of the probes in the clock. */
|
|
|
|
|
NexusSet*statement_input = statement_ -> nex_input();
|
|
|
|
|
|
|
|
|
|
/* Search for a clock input. The clock input is the edge event
|
|
|
|
|
that is not also an input to the substatement. */
|
|
|
|
|
NetEvProbe*pclk = 0;
|
2002-09-26 03:13:14 +02:00
|
|
|
unsigned event_idx = 0;
|
2002-09-24 02:58:35 +02:00
|
|
|
for (unsigned idx = 0 ; idx < ev->nprobe() ; idx += 1) {
|
|
|
|
|
NetEvProbe*tmp = ev->probe(idx);
|
|
|
|
|
assert(tmp->pin_count() == 1);
|
|
|
|
|
|
|
|
|
|
NexusSet tmp_nex;
|
|
|
|
|
tmp_nex .add( tmp->pin(0).nexus() );
|
|
|
|
|
|
|
|
|
|
if (! statement_input ->contains(tmp_nex)) {
|
|
|
|
|
if (pclk != 0) {
|
|
|
|
|
cerr << get_line() << ": error: Too many "
|
|
|
|
|
<< "clocks for synchronous logic." << endl;
|
|
|
|
|
cerr << get_line() << ": : Perhaps an"
|
|
|
|
|
<< " asynchronous set/reset is misused?" << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
pclk = tmp;
|
2002-09-26 03:13:14 +02:00
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
events[event_idx++] = tmp;
|
2002-09-24 02:58:35 +02:00
|
|
|
}
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2002-09-24 02:58:35 +02:00
|
|
|
if (pclk == 0) {
|
|
|
|
|
cerr << get_line() << ": error: None of the edges"
|
|
|
|
|
<< " are valid clock inputs." << endl;
|
|
|
|
|
cerr << get_line() << ": : Perhaps the clock"
|
|
|
|
|
<< " is read by a statement or expression?" << endl;
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetEvWait",false)
|
2002-09-24 02:58:35 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
NetFF*ff = nex_ff[0].ff;
|
2002-09-16 02:30:33 +02:00
|
|
|
connect(ff->pin_Clock(), pclk->pin(0));
|
|
|
|
|
if (pclk->edge() == NetEvProbe::NEGEDGE)
|
2004-02-20 19:53:33 +01:00
|
|
|
ff->attribute(perm_string::literal("Clock:LPM_Polarity"), verinum("INVERT"));
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2002-09-24 02:58:35 +02:00
|
|
|
/* Synthesize the input to the DFF. */
|
2006-01-18 02:23:23 +01:00
|
|
|
bool flag = statement_->synth_sync(des, scope, nex_ff,
|
2002-09-26 03:13:14 +02:00
|
|
|
nex_map, nex_out, events);
|
2002-09-24 02:58:35 +02:00
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetEvWait",flag)
|
2002-09-16 02:30:33 +02:00
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetProcTop::synth_sync(Design*des)
|
|
|
|
|
{
|
|
|
|
|
NexusSet nex_set;
|
|
|
|
|
statement_->nex_output(nex_set);
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
|
2002-09-16 02:30:33 +02:00
|
|
|
nex_set.count());
|
|
|
|
|
des->add_node(ff);
|
2004-02-20 19:53:33 +01:00
|
|
|
ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF"));
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2006-01-18 02:23:23 +01:00
|
|
|
struct sync_accounting_cell*nex_ff
|
|
|
|
|
= new struct sync_accounting_cell[ff->pin_count()];
|
|
|
|
|
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1) {
|
|
|
|
|
nex_ff[idx].ff = ff;
|
|
|
|
|
nex_ff[idx].pin = idx;
|
|
|
|
|
nex_ff[idx].proc = statement_;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
/* The D inputs to the DFF device will receive the output from
|
2003-01-27 06:09:17 +01:00
|
|
|
the statements of the process. */
|
2003-03-06 01:28:41 +01:00
|
|
|
NetNet*nex_d = new NetNet(scope(), scope()->local_symbol(),
|
2002-09-16 02:30:33 +02:00
|
|
|
NetNet::WIRE, nex_set.count());
|
|
|
|
|
nex_d->local_flag(true);
|
|
|
|
|
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
|
|
|
|
|
connect(nex_d->pin(idx), ff->pin_Data(idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The Q outputs of the DFF will connect to the actual outputs
|
|
|
|
|
of the process. Thus, the DFF will be between the outputs
|
|
|
|
|
of the process and the outputs of the substatement. */
|
2004-02-18 18:11:54 +01:00
|
|
|
const perm_string tmpq = perm_string::literal("tmpq");
|
|
|
|
|
NetNet*nex_q = new NetNet(scope(), tmpq, NetNet::WIRE,
|
2002-09-16 02:30:33 +02:00
|
|
|
nex_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
|
|
|
|
|
connect(nex_set[idx], nex_q->pin(idx));
|
|
|
|
|
connect(nex_q->pin(idx), ff->pin_Q(idx));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Synthesize the input to the DFF. */
|
2006-01-18 02:23:23 +01:00
|
|
|
bool flag = statement_->synth_sync(des, scope(),
|
|
|
|
|
nex_ff,
|
2002-09-26 03:13:14 +02:00
|
|
|
nex_q, nex_d,
|
|
|
|
|
svector<NetEvProbe*>());
|
2002-09-16 02:30:33 +02:00
|
|
|
|
|
|
|
|
delete nex_q;
|
2006-01-18 02:23:23 +01:00
|
|
|
delete[]nex_ff;
|
2002-09-16 02:30:33 +02:00
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-30 04:21:31 +02:00
|
|
|
class synth2_f : public functor_t {
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
void process(class Design*, class NetProcTop*);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
2002-07-01 02:54:21 +02:00
|
|
|
* Look at a process. If it is asynchronous, then synthesize it as an
|
|
|
|
|
* asynchronous process and delete the process itself for its gates.
|
2002-06-30 04:21:31 +02:00
|
|
|
*/
|
|
|
|
|
void synth2_f::process(class Design*des, class NetProcTop*top)
|
|
|
|
|
{
|
2004-02-20 19:53:33 +01:00
|
|
|
if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0)
|
2002-08-11 00:07:08 +02:00
|
|
|
return;
|
|
|
|
|
|
2003-06-23 02:14:44 +02:00
|
|
|
/* If the scope that contains this process as a cell attribute
|
|
|
|
|
attached to it, then skip synthesis. */
|
2004-02-20 19:53:33 +01:00
|
|
|
if (top->scope()->attribute(perm_string::literal("ivl_synthesis_cell")).len() > 0)
|
2003-06-23 02:14:44 +02:00
|
|
|
return;
|
|
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
if (top->is_synchronous()) do {
|
|
|
|
|
bool flag = top->synth_sync(des);
|
2002-09-24 02:58:35 +02:00
|
|
|
if (! flag) {
|
2002-10-20 21:19:37 +02:00
|
|
|
cerr << top->get_line() << ": error: "
|
|
|
|
|
<< "Unable to synthesize synchronous process." << endl;
|
2002-09-24 02:58:35 +02:00
|
|
|
des->errors += 1;
|
|
|
|
|
return;
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
des->delete_process(top);
|
|
|
|
|
return;
|
|
|
|
|
} while (0);
|
|
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
if (! top->is_asynchronous()) {
|
2002-08-19 00:07:16 +02:00
|
|
|
bool synth_error_flag = false;
|
2004-02-20 19:53:33 +01:00
|
|
|
if (top->attribute(perm_string::literal("ivl_combinational")).as_ulong() != 0) {
|
2002-08-11 00:07:08 +02:00
|
|
|
cerr << top->get_line() << ": error: "
|
|
|
|
|
<< "Process is marked combinational,"
|
2002-07-01 02:54:21 +02:00
|
|
|
<< " but isn't really." << endl;
|
2002-08-11 00:07:08 +02:00
|
|
|
des->errors += 1;
|
2002-08-19 00:07:16 +02:00
|
|
|
synth_error_flag = true;
|
2002-08-11 00:07:08 +02:00
|
|
|
}
|
|
|
|
|
|
2004-02-20 19:53:33 +01:00
|
|
|
if (top->attribute(perm_string::literal("ivl_synthesis_on")).as_ulong() != 0) {
|
2002-08-11 00:07:08 +02:00
|
|
|
cerr << top->get_line() << ": error: "
|
|
|
|
|
<< "Process is marked for synthesis,"
|
|
|
|
|
<< " but I can't do it." << endl;
|
|
|
|
|
des->errors += 1;
|
2002-08-19 00:07:16 +02:00
|
|
|
synth_error_flag = true;
|
2002-08-11 00:07:08 +02:00
|
|
|
}
|
|
|
|
|
|
2002-08-19 00:07:16 +02:00
|
|
|
if (! synth_error_flag)
|
|
|
|
|
cerr << top->get_line() << ": warning: "
|
|
|
|
|
<< "Process not synthesized." << endl;
|
|
|
|
|
|
2002-06-30 04:21:31 +02:00
|
|
|
return;
|
2002-07-01 02:54:21 +02:00
|
|
|
}
|
2002-06-30 04:21:31 +02:00
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
if (! top->synth_async(des)) {
|
|
|
|
|
cerr << top->get_line() << ": internal error: "
|
|
|
|
|
<< "is_asynchronous does not match "
|
|
|
|
|
<< "sync_async results." << endl;
|
2002-06-30 04:21:31 +02:00
|
|
|
return;
|
2002-07-01 02:54:21 +02:00
|
|
|
}
|
2002-06-30 04:21:31 +02:00
|
|
|
|
|
|
|
|
des->delete_process(top);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void synth2(Design*des)
|
|
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
debug_synth2 = atoi(des->get_flag("ivl-synth2-debug"));
|
2002-06-30 04:21:31 +02:00
|
|
|
synth2_f synth_obj;
|
|
|
|
|
des->functor(&synth_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* $Log: synth2.cc,v $
|
2006-01-18 07:16:11 +01:00
|
|
|
* Revision 1.39.2.17 2006/01/18 06:16:11 steve
|
|
|
|
|
* Restrict DFF to only one of Sset and Sclr.
|
|
|
|
|
*
|
2006-01-18 02:23:23 +01:00
|
|
|
* Revision 1.39.2.16 2006/01/18 01:23:25 steve
|
|
|
|
|
* Rework l-value handling to allow for more l-value type flexibility.
|
|
|
|
|
*
|
2006-01-01 03:25:07 +01:00
|
|
|
* Revision 1.39.2.15 2006/01/01 02:25:07 steve
|
|
|
|
|
* Case statement handles partial outputs.
|
|
|
|
|
*
|
2006-01-01 02:30:39 +01:00
|
|
|
* Revision 1.39.2.14 2006/01/01 01:30:39 steve
|
|
|
|
|
* Allow for implicit case default in synchronous processes.
|
|
|
|
|
*
|
2005-12-31 05:28:14 +01:00
|
|
|
* Revision 1.39.2.13 2005/12/31 04:28:15 steve
|
|
|
|
|
* Fix crashes caused bu synthesis of sqrt32.v.
|
|
|
|
|
*
|
2005-12-19 02:13:47 +01:00
|
|
|
* Revision 1.39.2.12 2005/12/19 01:13:47 steve
|
|
|
|
|
* Handle DFF definitions spread out within a block.
|
|
|
|
|
*
|
2005-12-15 03:38:51 +01:00
|
|
|
* Revision 1.39.2.11 2005/12/15 02:38:51 steve
|
|
|
|
|
* Fix missing outputs from synchronous conditionals to get out from in.
|
|
|
|
|
*
|
2005-12-14 02:53:39 +01:00
|
|
|
* Revision 1.39.2.10 2005/12/14 01:53:39 steve
|
|
|
|
|
* Handle both asynchronous set and reset.
|
|
|
|
|
*
|
2005-12-14 01:54:29 +01:00
|
|
|
* Revision 1.39.2.9 2005/12/14 00:54:30 steve
|
|
|
|
|
* Account for sync vs async muxes.
|
|
|
|
|
*
|
2005-12-10 05:26:32 +01:00
|
|
|
* Revision 1.39.2.8 2005/12/10 04:26:32 steve
|
|
|
|
|
* Handle concatenations in l-values.
|
|
|
|
|
*
|
2005-12-10 04:30:50 +01:00
|
|
|
* Revision 1.39.2.7 2005/12/10 03:30:51 steve
|
|
|
|
|
* Fix crash on block with assignments that assign lval to self.
|
|
|
|
|
*
|
2005-12-07 03:14:37 +01:00
|
|
|
* Revision 1.39.2.6 2005/12/07 02:14:37 steve
|
|
|
|
|
* Error messages for missing else clauses.
|
|
|
|
|
*
|
2005-11-16 01:38:26 +01:00
|
|
|
* Revision 1.39.2.5 2005/11/16 00:38:26 steve
|
|
|
|
|
* Handle partial sets of conditional clauses.
|
|
|
|
|
*
|
2005-11-13 23:28:48 +01:00
|
|
|
* Revision 1.39.2.4 2005/11/13 22:28:48 steve
|
|
|
|
|
* Allow for block output to be set throughout the statements.
|
|
|
|
|
*
|
2005-09-11 04:56:37 +02:00
|
|
|
* Revision 1.39.2.3 2005/09/11 02:56:38 steve
|
|
|
|
|
* Attach line numbers to NetMux devices.
|
|
|
|
|
*
|
2005-08-22 03:00:41 +02:00
|
|
|
* Revision 1.39.2.2 2005/08/22 01:00:42 steve
|
|
|
|
|
* Add support for implicit defaults in case and conditions.
|
|
|
|
|
*
|
2005-08-22 00:49:54 +02:00
|
|
|
* Revision 1.39.2.1 2005/08/21 22:49:54 steve
|
|
|
|
|
* Handle statements in blocks overriding previous statement outputs.
|
|
|
|
|
*
|
2004-10-04 03:10:51 +02:00
|
|
|
* Revision 1.39 2004/10/04 01:10:55 steve
|
|
|
|
|
* Clean up spurious trailing white space.
|
|
|
|
|
*
|
2004-08-28 17:08:31 +02:00
|
|
|
* Revision 1.38 2004/08/28 15:08:32 steve
|
|
|
|
|
* Do not change reg to wire in NetAssign_ unless synthesizing.
|
|
|
|
|
*
|
2004-03-15 19:40:12 +01:00
|
|
|
* Revision 1.37 2004/03/15 18:40:12 steve
|
|
|
|
|
* Only include DEBUG_SYNTH2 if __FUNCTION__ defined.
|
|
|
|
|
*
|
2004-02-20 19:53:33 +01:00
|
|
|
* Revision 1.36 2004/02/20 18:53:35 steve
|
|
|
|
|
* Addtrbute keys are perm_strings.
|
|
|
|
|
*
|
2004-02-18 18:11:54 +01:00
|
|
|
* Revision 1.35 2004/02/18 17:11:58 steve
|
|
|
|
|
* Use perm_strings for named langiage items.
|
|
|
|
|
*
|
2003-12-20 01:59:31 +01:00
|
|
|
* Revision 1.34 2003/12/20 00:59:31 steve
|
|
|
|
|
* Synthesis debug messages.
|
|
|
|
|
*
|
2003-12-17 17:52:39 +01:00
|
|
|
* Revision 1.33 2003/12/17 16:52:39 steve
|
|
|
|
|
* Debug dumps for synth2.
|
|
|
|
|
*
|
2003-10-27 03:18:04 +01:00
|
|
|
* Revision 1.32 2003/10/27 02:18:04 steve
|
|
|
|
|
* Handle special case of FF with enable and constant data.
|
|
|
|
|
*
|
2003-08-28 06:11:17 +02:00
|
|
|
* Revision 1.31 2003/08/28 04:11:19 steve
|
|
|
|
|
* Spelling patch.
|
|
|
|
|
*
|
2003-08-15 04:23:52 +02:00
|
|
|
* Revision 1.30 2003/08/15 02:23:53 steve
|
|
|
|
|
* Add synthesis support for synchronous reset.
|
|
|
|
|
*
|
2003-08-14 04:41:05 +02:00
|
|
|
* Revision 1.29 2003/08/14 02:41:05 steve
|
|
|
|
|
* Fix dangling pointer in NexusSet handling blocks.
|
|
|
|
|
*
|
2003-08-10 19:04:23 +02:00
|
|
|
* Revision 1.28 2003/08/10 17:04:23 steve
|
|
|
|
|
* Detect asynchronous FF inputs that are expressions.
|
|
|
|
|
*
|
2003-06-23 02:14:44 +02:00
|
|
|
* Revision 1.27 2003/06/23 00:14:44 steve
|
|
|
|
|
* ivl_synthesis_cell cuts off synthesis within a module.
|
|
|
|
|
*
|
2003-06-21 03:21:42 +02:00
|
|
|
* Revision 1.26 2003/06/21 01:21:43 steve
|
|
|
|
|
* Harmless fixup of warnings.
|
|
|
|
|
*
|
2003-04-03 06:30:00 +02:00
|
|
|
* Revision 1.25 2003/04/03 04:30:00 steve
|
|
|
|
|
* Prevent overrun comparing verinums to zero.
|
|
|
|
|
*
|
2003-03-25 05:04:29 +01:00
|
|
|
* Revision 1.24 2003/03/25 04:04:29 steve
|
|
|
|
|
* Handle defaults in synthesized case statements.
|
|
|
|
|
*
|
2003-03-06 01:28:41 +01:00
|
|
|
* Revision 1.23 2003/03/06 00:28:42 steve
|
|
|
|
|
* All NetObj objects have lex_string base names.
|
|
|
|
|
*
|
2003-02-26 02:29:24 +01:00
|
|
|
* Revision 1.22 2003/02/26 01:29:24 steve
|
|
|
|
|
* LPM objects store only their base names.
|
|
|
|
|
*
|
2003-01-27 06:09:17 +01:00
|
|
|
* Revision 1.21 2003/01/27 05:09:17 steve
|
|
|
|
|
* Spelling fixes.
|
|
|
|
|
*
|
2002-11-10 00:29:29 +01:00
|
|
|
* Revision 1.20 2002/11/09 23:29:29 steve
|
|
|
|
|
* Handle nested-if chip enables.
|
|
|
|
|
*
|
2002-11-09 21:22:57 +01:00
|
|
|
* Revision 1.19 2002/11/09 20:22:57 steve
|
|
|
|
|
* Detect synthesis conflicts blocks statements share outputs.
|
2002-06-30 04:21:31 +02:00
|
|
|
*/
|
|
|
|
|
|