2002-06-30 04:21:31 +02:00
|
|
|
/*
|
2005-04-25 03:35:58 +02:00
|
|
|
* Copyright (c) 2002-2005 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
|
2007-03-22 17:08:14 +01:00
|
|
|
#ident "$Id: synth2.cc,v 1.46 2007/03/22 16:08:17 steve Exp $"
|
2002-06-30 04:21:31 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
# include "config.h"
|
|
|
|
|
|
|
|
|
|
# include "functor.h"
|
|
|
|
|
# include "netlist.h"
|
2005-04-25 01:44:01 +02:00
|
|
|
# include "netmisc.h"
|
2002-07-01 02:54:21 +02:00
|
|
|
# include "compiler.h"
|
2002-06-30 04:21:31 +02:00
|
|
|
# include <assert.h>
|
|
|
|
|
|
2004-03-15 19:40:12 +01:00
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
bool NetProc::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF*ff,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2002-09-26 03:13:14 +02:00
|
|
|
if (events.count() > 0) {
|
|
|
|
|
cerr << get_line() << ": error: Events are unaccounted"
|
|
|
|
|
<< " for in process synthesis." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
/* Synthesize the input to the DFF. */
|
|
|
|
|
return synth_async(des, scope, nex_map, nex_out);
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
#if 0
|
2005-04-25 01:44:01 +02:00
|
|
|
static unsigned find_nexus_in_set(const NetBus&nset, const Nexus*nex)
|
2002-07-01 02:54:21 +02:00
|
|
|
{
|
|
|
|
|
unsigned idx = 0;
|
2005-04-25 01:44:01 +02:00
|
|
|
for (idx = 0 ; idx < nset.pin_count() ; idx += 1)
|
|
|
|
|
if (nset.pin(idx).nexus() == nex)
|
2002-07-01 02:54:21 +02:00
|
|
|
return idx;
|
|
|
|
|
|
|
|
|
|
return idx;
|
|
|
|
|
}
|
2005-04-25 03:35:58 +02:00
|
|
|
#endif
|
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
|
|
|
*/
|
2002-07-01 02:54:21 +02:00
|
|
|
bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
|
|
|
|
NetNet*rsig = rval_->synthesize(des);
|
2002-07-01 02:54:21 +02:00
|
|
|
assert(rsig);
|
2002-06-30 04:21:31 +02:00
|
|
|
|
|
|
|
|
NetNet*lsig = lval_->sig();
|
2003-12-20 01:59:31 +01:00
|
|
|
if (!lsig) {
|
2005-04-25 01:44:01 +02:00
|
|
|
cerr << get_line() << ": error: "
|
|
|
|
|
<< "NetAssignBase::synth_async on unsupported lval ";
|
2003-12-20 01:59:31 +01:00
|
|
|
dump_lval(cerr);
|
|
|
|
|
cerr << endl;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
2003-12-20 01:59:31 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2002-06-30 04:21:31 +02:00
|
|
|
assert(lval_->more == 0);
|
|
|
|
|
|
2005-05-15 06:45:50 +02:00
|
|
|
if (debug_synth2) {
|
|
|
|
|
cerr << get_line() << ": debug: l-value signal is "
|
|
|
|
|
<< lsig->vector_width() << " bits, r-value signal is "
|
|
|
|
|
<< rsig->vector_width() << " bits." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
#if 0
|
|
|
|
|
/* The l-value and r-value map must have the same width. */
|
|
|
|
|
if (lval_->lwidth() != nex_map->vector_width()) {
|
|
|
|
|
cerr << get_line() << ": error: Assignment synthesis: "
|
|
|
|
|
<< "vector width mismatch, "
|
|
|
|
|
<< lval_->lwidth() << " bits != "
|
|
|
|
|
<< nex_map->vector_width() << " bits." << endl;
|
2003-12-20 01:59:31 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2005-04-25 01:44:01 +02:00
|
|
|
#else
|
|
|
|
|
/* For now, assume there is exactly one output. */
|
|
|
|
|
assert(nex_out.pin_count() == 1);
|
|
|
|
|
#endif
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
connect(nex_out.pin(0), rsig->pin(0));
|
2002-06-30 04:21:31 +02:00
|
|
|
|
2004-08-28 17:08:31 +02:00
|
|
|
/* 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. */
|
|
|
|
|
lval_->turn_sig_to_wire_on_release();
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
bool NetBlock::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-07-29 02:00:28 +02:00
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
if (last_ == 0) {
|
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
|
|
|
|
|
|
|
|
bool flag = true;
|
|
|
|
|
NetProc*cur = last_;
|
|
|
|
|
do {
|
|
|
|
|
cur = cur->next_;
|
|
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
/* Create a temporary map of the output only from this
|
|
|
|
|
statement. */
|
2002-07-29 02:00:28 +02:00
|
|
|
NexusSet tmp_set;
|
|
|
|
|
cur->nex_output(tmp_set);
|
2005-04-25 03:35:58 +02:00
|
|
|
NetBus tmp_map (scope, tmp_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp_set.count() ; idx += 1)
|
|
|
|
|
connect(tmp_set[idx], tmp_map.pin(idx));
|
2002-07-29 02:00:28 +02:00
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
/* Create also a temporary NetBus to collect the
|
|
|
|
|
output from the synthesis. */
|
|
|
|
|
NetBus tmp_out (scope, tmp_set.count());
|
2002-09-17 06:40:28 +02:00
|
|
|
|
|
|
|
|
bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out);
|
2002-07-29 02:00:28 +02:00
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
flag = flag && ok_flag;
|
2002-07-29 02:00:28 +02:00
|
|
|
if (ok_flag == false)
|
|
|
|
|
continue;
|
|
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
/* Now find the tmp_map pins in the nex_map global map,
|
|
|
|
|
and use that to direct the connection to the nex_out
|
|
|
|
|
output bus. Look for the nex_map pin that is linked
|
|
|
|
|
to the tmp_map.pin(idx) pin, and link that to the
|
|
|
|
|
tmp_out.pin(idx) output link. */
|
|
|
|
|
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
|
|
|
|
|
unsigned ptr = 0;
|
|
|
|
|
while (ptr < nex_map.pin_count()
|
|
|
|
|
&& ! nex_map.pin(ptr).is_linked(tmp_map.pin(idx)))
|
|
|
|
|
ptr += 1;
|
|
|
|
|
|
|
|
|
|
assert(ptr < nex_out.pin_count());
|
|
|
|
|
connect(nex_out.pin(ptr), tmp_out.pin(idx));
|
2002-07-29 02:00:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} while (cur != last_);
|
|
|
|
|
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-08 00:32:15 +02:00
|
|
|
bool NetCase::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-07-08 00:32:15 +02:00
|
|
|
{
|
2005-08-27 06:32:08 +02:00
|
|
|
/* Synthesize the select expression. */
|
2002-07-08 00:32:15 +02:00
|
|
|
NetNet*esig = expr_->synthesize(des);
|
|
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
unsigned sel_width = esig->vector_width();
|
|
|
|
|
assert(sel_width > 0);
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
unsigned mux_width = 0;
|
|
|
|
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
|
|
|
|
|
mux_width += nex_out.pin(idx).nexus()->vector_width();
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
/* Collect all the statements into a map of index to
|
|
|
|
|
statement. The guard expression it evaluated to be the
|
|
|
|
|
index of the mux value, and the statement is bound to that
|
|
|
|
|
index. */
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
unsigned long max_guard_value = 0;
|
|
|
|
|
map<unsigned long,NetProc*>statement_map;
|
|
|
|
|
NetProc*statement_default = 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
|
|
|
if (items_[item].guard == 0) {
|
2005-08-27 06:32:08 +02:00
|
|
|
statement_default = items_[item].statement;
|
2003-03-25 05:04:29 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
|
|
|
|
|
NetEConst*ge = dynamic_cast<NetEConst*>(items_[item].guard);
|
|
|
|
|
assert(ge);
|
|
|
|
|
verinum gval = ge->value();
|
2005-08-27 06:32:08 +02:00
|
|
|
|
|
|
|
|
unsigned sel_idx = gval.as_ulong();
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2003-03-25 05:04:29 +01:00
|
|
|
assert(items_[item].statement);
|
|
|
|
|
statement_map[sel_idx] = items_[item].statement;
|
2005-08-27 06:32:08 +02:00
|
|
|
|
|
|
|
|
if (sel_idx > max_guard_value)
|
|
|
|
|
max_guard_value = sel_idx;
|
2003-03-25 05:04:29 +01:00
|
|
|
}
|
|
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
unsigned mux_size = max_guard_value + 1;
|
2003-03-25 05:04:29 +01:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
|
|
|
|
mux_width, mux_size, sel_width);
|
|
|
|
|
des->add_node(mux);
|
2003-03-25 05:04:29 +01:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
/* The select signal is already synthesized. Simply hook it up. */
|
|
|
|
|
connect(mux->pin_Sel(), esig->pin(0));
|
|
|
|
|
|
|
|
|
|
/* For now, assume that the output is only 1 signal. */
|
|
|
|
|
assert(nex_out.pin_count() == 1);
|
|
|
|
|
connect(mux->pin_Result(), nex_out.pin(0));
|
|
|
|
|
|
|
|
|
|
/* For now, only support logic types. */
|
|
|
|
|
ivl_variable_type_t mux_data_type = IVL_VT_LOGIC;
|
2003-03-25 05:04:29 +01:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
/* Forgot to support default statements? */
|
|
|
|
|
assert(statement_default == 0);
|
|
|
|
|
|
|
|
|
|
NetNet*isig;
|
|
|
|
|
for (unsigned idx = 0 ; idx < mux_size ; idx += 1) {
|
|
|
|
|
|
|
|
|
|
NetProc*stmt = statement_map[idx];
|
|
|
|
|
if (stmt == 0) {
|
|
|
|
|
cerr << get_line() << ": error: case " << idx
|
|
|
|
|
<< " is not accounted for in asynchronous mux." << endl;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
2005-08-27 06:32:08 +02:00
|
|
|
continue;
|
2003-12-20 01:59:31 +01:00
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
isig = new NetNet(scope, scope->local_symbol(),
|
|
|
|
|
NetNet::TRI, mux_width);
|
|
|
|
|
isig->local_flag(true);
|
|
|
|
|
isig->data_type(mux_data_type);
|
2004-10-04 03:10:51 +02:00
|
|
|
|
2005-08-27 06:32:08 +02:00
|
|
|
connect(mux->pin_Data(idx), isig->pin(0));
|
|
|
|
|
|
|
|
|
|
NetBus tmp (scope, 1);
|
|
|
|
|
connect(tmp.pin(0), isig->pin(0));
|
|
|
|
|
stmt->synth_async(des, scope, tmp, tmp);
|
|
|
|
|
}
|
2002-07-08 00:32:15 +02:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
bool NetCondit::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
2005-04-25 01:44:01 +02:00
|
|
|
#if 0
|
2002-07-01 02:54:21 +02:00
|
|
|
NetNet*ssig = expr_->synthesize(des);
|
|
|
|
|
assert(ssig);
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
if (if_ == 0) {
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",false)
|
2002-10-20 21:19:37 +02:00
|
|
|
return false;
|
2003-12-17 17:52:39 +01:00
|
|
|
}
|
2002-10-20 21:19:37 +02:00
|
|
|
if (else_ == 0) {
|
|
|
|
|
cerr << get_line() << ": error: Asynchronous if statement"
|
|
|
|
|
<< " is missing the else clause." << endl;
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",false)
|
2002-10-20 21:19:37 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
assert(if_ != 0);
|
|
|
|
|
assert(else_ != 0);
|
|
|
|
|
|
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);
|
|
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
bool flag;
|
|
|
|
|
flag = if_->synth_async(des, scope, nex_map, asig);
|
|
|
|
|
if (!flag) {
|
|
|
|
|
delete asig;
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",false)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
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);
|
|
|
|
|
|
2003-12-20 01:59:31 +01:00
|
|
|
flag = else_->synth_async(des, scope, nex_map, bsig);
|
|
|
|
|
if (!flag) {
|
|
|
|
|
delete asig;
|
|
|
|
|
delete bsig;
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",false)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2003-02-26 02:29:24 +01:00
|
|
|
NetMux*mux = new NetMux(scope, scope->local_symbol(),
|
2005-02-12 07:25:40 +01:00
|
|
|
nex_out->vector_width(), 2, 1);
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2005-02-12 07:25:40 +01:00
|
|
|
connect(mux->pin_Sel(), ssig->pin(0));
|
|
|
|
|
connect(mux->pin_Data(1), asig->pin(0));
|
|
|
|
|
connect(mux->pin_Data(0), bsig->pin(0));
|
|
|
|
|
connect(nex_out->pin(0), mux->pin_Result());
|
2002-07-01 02:54:21 +02:00
|
|
|
|
|
|
|
|
des->add_node(mux);
|
|
|
|
|
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",true)
|
2002-07-01 02:54:21 +02:00
|
|
|
return true;
|
2005-04-25 01:44:01 +02:00
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
cerr << get_line() << ": sorry: "
|
|
|
|
|
<< "Forgot to implement NetCondit::synth_async" << endl;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
2005-04-25 01:44:01 +02:00
|
|
|
return false;
|
|
|
|
|
#endif
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
2002-07-01 02:54:21 +02:00
|
|
|
bool NetEvWait::synth_async(Design*des, NetScope*scope,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out)
|
2002-06-30 04:21:31 +02:00
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
bool flag = statement_->synth_async(des, scope, nex_map, nex_out);
|
|
|
|
|
return flag;
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
/*
|
|
|
|
|
* This method is called when the process is shown to be
|
|
|
|
|
* asynchronous. Figure out the nexus set of outputs from this
|
|
|
|
|
* process, and pass that to the synth_async method for the statement
|
|
|
|
|
* of the process. The statement will connect its output to the
|
|
|
|
|
* nex_out set, using the nex_map as a guide. Starting from the top,
|
|
|
|
|
* the nex_map is the same as the nex_map.
|
|
|
|
|
*/
|
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);
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
if (debug_synth2) {
|
|
|
|
|
cerr << get_line() << ": debug: Process has "
|
|
|
|
|
<< nex_set.count() << " outputs." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
NetBus nex_q (scope(), nex_set.count());
|
|
|
|
|
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
|
|
|
|
|
connect(nex_set[idx], nex_q.pin(idx));
|
|
|
|
|
}
|
2002-07-01 02:54:21 +02:00
|
|
|
|
2005-04-25 03:35:58 +02:00
|
|
|
bool flag = statement_->synth_async(des, scope(), nex_q, nex_q);
|
2002-07-01 02:54:21 +02:00
|
|
|
return flag;
|
2002-06-30 04:21:31 +02:00
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
bool NetBlock::synth_sync(Design*des, NetScope*scope, NetFF*ff,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out,
|
2002-10-21 03:42:08 +02:00
|
|
|
const svector<NetEvProbe*>&events_in)
|
|
|
|
|
{
|
2003-12-17 17:52:39 +01:00
|
|
|
if (last_ == 0) {
|
2002-10-21 03:42:08 +02:00
|
|
|
return true;
|
2003-12-17 17:52:39 +01:00
|
|
|
}
|
2002-10-21 03:42:08 +02:00
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
#if 0
|
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-11-09 21:22:57 +01:00
|
|
|
/* Keep an accounting of which statement accounts for which
|
|
|
|
|
bit slice of the FF bank. This is used for error checking. */
|
|
|
|
|
NetProc**pin_accounting = new NetProc* [ff->pin_count()];
|
|
|
|
|
for (unsigned idx = 0 ; idx < ff->pin_count() ; idx += 1)
|
|
|
|
|
pin_accounting[idx] = 0;
|
|
|
|
|
|
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());
|
|
|
|
|
des->add_node(ff2);
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
/* Connect Data and Q bits to the new FF. */
|
2002-10-23 03:45:24 +02:00
|
|
|
connect(ff->pin_Data(ptr), ff2->pin_Data(idx));
|
|
|
|
|
connect(ff->pin_Q(ptr), ff2->pin_Q(idx));
|
|
|
|
|
|
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]);
|
|
|
|
|
|
2002-11-09 21:22:57 +01:00
|
|
|
if (pin_accounting[ptr] != 0) {
|
|
|
|
|
cerr << cur->get_line() << ": error: "
|
|
|
|
|
<< "Synchronous output conflicts with "
|
|
|
|
|
<< pin_accounting[ptr]->get_line()
|
|
|
|
|
<< "." << endl;
|
|
|
|
|
flag = false;
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
pin_accounting[ptr] = cur;
|
|
|
|
|
}
|
2002-10-21 03:42:08 +02:00
|
|
|
}
|
2003-08-15 04:23:52 +02:00
|
|
|
|
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()) {
|
|
|
|
|
|
|
|
|
|
connect(ff2->pin_Aclr(), ff2->pin_Aset());
|
|
|
|
|
ff2->pin_Aset().unlink();
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
ff2->aset_value(aset_value2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/* Now go on with the synchronous synthesis for this
|
2003-08-14 04:41:05 +02:00
|
|
|
subset of the statement. The tmp_map is the output
|
|
|
|
|
nexa that we expect, and the tmp_out is where we want
|
|
|
|
|
those outputs connected. */
|
2002-10-21 03:42:08 +02:00
|
|
|
bool ok_flag = cur->synth_sync(des, scope, ff2, tmp_map,
|
|
|
|
|
tmp_out, events_in);
|
|
|
|
|
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) {
|
2003-08-14 04:41:05 +02:00
|
|
|
unsigned ptr = find_nexus_in_set(nex_map,
|
|
|
|
|
tmp_map->pin(idx).nexus());
|
|
|
|
|
|
2002-11-06 04:22:28 +01:00
|
|
|
if (ptr < nex_out->pin_count())
|
|
|
|
|
connect(nex_out->pin(ptr), tmp_out->pin(idx));
|
2002-10-21 03:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete tmp_map;
|
|
|
|
|
delete tmp_out;
|
|
|
|
|
|
|
|
|
|
} while (cur != last_);
|
|
|
|
|
|
2002-11-09 21:22:57 +01:00
|
|
|
delete[]pin_accounting;
|
|
|
|
|
|
2002-10-21 03:42:08 +02:00
|
|
|
/* Done. The large NetFF is no longer needed, as it has been
|
|
|
|
|
taken up by the smaller NetFF devices. */
|
|
|
|
|
delete ff;
|
|
|
|
|
|
|
|
|
|
return flag;
|
2005-04-25 01:44:01 +02:00
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
cerr << get_line() << ": sorry: "
|
|
|
|
|
<< "Forgot to implement NetBlock::synth_sync"
|
|
|
|
|
<< endl;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
2005-04-25 01:44:01 +02:00
|
|
|
return false;
|
|
|
|
|
#endif
|
2002-10-21 03:42:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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.
|
|
|
|
|
*/
|
2002-09-16 02:30:33 +02:00
|
|
|
bool NetCondit::synth_sync(Design*des, NetScope*scope, NetFF*ff,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events_in)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2005-04-25 01:44:01 +02:00
|
|
|
#if 0
|
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
|
|
|
|
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);
|
2003-08-10 19:04:23 +02:00
|
|
|
bool flag = if_->synth_async(des, scope, nex_map, asig);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
assert(events_in.count() == 1);
|
2003-10-27 03:18:04 +01:00
|
|
|
assert(else_ != 0);
|
2003-12-17 17:52:39 +01:00
|
|
|
flag = else_->synth_sync(des, scope, ff, nex_map,
|
2003-08-10 19:04:23 +02:00
|
|
|
nex_out, svector<NetEvProbe*>(0))
|
|
|
|
|
&& flag;
|
2003-12-17 17:52:39 +01:00
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",flag)
|
|
|
|
|
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
|
|
|
|
|
met if the assignments are of all constant values. */
|
|
|
|
|
assert(if_ != 0);
|
2003-08-15 04:23:52 +02:00
|
|
|
NexusSet*a_set = if_->nex_input();
|
|
|
|
|
|
2003-10-27 03:18:04 +01:00
|
|
|
if ((a_set->count() == 0) && if_ && else_) {
|
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);
|
|
|
|
|
bool flag = if_->synth_async(des, scope, nex_map, asig);
|
|
|
|
|
|
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
|
|
|
|
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);
|
|
|
|
|
flag = else_->synth_sync(des, scope, ff, nex_map,
|
|
|
|
|
nex_out, svector<NetEvProbe*>(0))
|
|
|
|
|
&& flag;
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",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
|
|
|
|
|
input are probably in error. */
|
|
|
|
|
if (events_in.count() > 0) {
|
|
|
|
|
cerr << get_line() << ": error: Events are unaccounted"
|
|
|
|
|
<< " for in process synthesis." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
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_) {
|
2003-12-17 17:52:39 +01:00
|
|
|
bool flag = synth_async(des, scope, nex_map, nex_out);
|
|
|
|
|
DEBUG_SYNTH2_EXIT("NetCondit",flag)
|
|
|
|
|
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,
|
2004-12-11 03:31:25 +01:00
|
|
|
NetLogic::AND, 1);
|
2002-11-10 00:29:29 +01:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool flag = if_->synth_sync(des, scope, 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;
|
2005-04-25 01:44:01 +02:00
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
cerr << get_line() << ": sorry: "
|
|
|
|
|
<< "Forgot to implement NetCondit::synth_sync" << endl;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
2005-04-25 01:44:01 +02:00
|
|
|
return false;
|
|
|
|
|
#endif
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
|
2005-04-25 01:44:01 +02:00
|
|
|
const NetBus&nex_map, NetBus&nex_out,
|
2002-09-26 03:13:14 +02:00
|
|
|
const svector<NetEvProbe*>&events_in)
|
2002-09-16 02:30:33 +02:00
|
|
|
{
|
2002-09-26 03:13:14 +02:00
|
|
|
if (events_in.count() > 0) {
|
|
|
|
|
cerr << get_line() << ": error: Events are unaccounted"
|
|
|
|
|
<< " for in process synthesis." << endl;
|
|
|
|
|
des->errors += 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(events_in.count() == 0);
|
|
|
|
|
|
2007-03-22 17:08:14 +01:00
|
|
|
/* This can't be other than one unless there are named events,
|
2002-09-24 02:58:35 +02:00
|
|
|
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
|
2005-04-25 01:44:01 +02:00
|
|
|
to figure out which of the probes is the clock. */
|
2002-09-24 02:58:35 +02:00
|
|
|
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;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
|
|
|
|
|
connect(ff->pin_Clock(), pclk->pin(0));
|
2005-04-25 01:44:01 +02:00
|
|
|
if (pclk->edge() == NetEvProbe::NEGEDGE) {
|
|
|
|
|
perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
|
|
|
|
|
ff->attribute(polarity, verinum("INVERT"));
|
|
|
|
|
|
|
|
|
|
if (debug_synth2) {
|
|
|
|
|
cerr << get_line() << ": debug: "
|
|
|
|
|
<< "Detected a NEGEDGE clock for the synthesized ff."
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2002-09-24 02:58:35 +02:00
|
|
|
/* Synthesize the input to the DFF. */
|
2002-09-26 03:13:14 +02:00
|
|
|
bool flag = statement_->synth_sync(des, scope, ff,
|
|
|
|
|
nex_map, nex_out, events);
|
2002-09-24 02:58:35 +02:00
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
/*
|
|
|
|
|
* This method is called for a process that is determined to be
|
|
|
|
|
* synchronous. Create a NetFF device to hold the output from the
|
|
|
|
|
* statement, and synthesize that statement in place.
|
|
|
|
|
*/
|
2002-09-16 02:30:33 +02:00
|
|
|
bool NetProcTop::synth_sync(Design*des)
|
|
|
|
|
{
|
2005-04-25 01:44:01 +02:00
|
|
|
if (debug_synth2) {
|
|
|
|
|
cerr << get_line() << ": debug: "
|
|
|
|
|
<< "Process is apparently synchronous. Making NetFFs."
|
|
|
|
|
<< endl;
|
|
|
|
|
}
|
|
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
NexusSet nex_set;
|
|
|
|
|
statement_->nex_output(nex_set);
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
/* Make a model FF that will connect to the first item in the
|
|
|
|
|
set, and will also take the initial connection of clocks
|
|
|
|
|
and resets. */
|
2005-05-15 06:45:50 +02:00
|
|
|
|
|
|
|
|
if (debug_synth2) {
|
|
|
|
|
cerr << get_line() << ": debug: "
|
|
|
|
|
<< "Top level making a "
|
|
|
|
|
<< nex_set[0]->vector_width() << "-wide "
|
|
|
|
|
<< "NetFF device." << endl;
|
|
|
|
|
}
|
|
|
|
|
|
2004-02-18 18:11:54 +01:00
|
|
|
NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
|
2005-04-25 01:44:01 +02:00
|
|
|
nex_set[0]->vector_width());
|
2002-09-16 02:30:33 +02:00
|
|
|
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
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
NetBus nex_d (scope(), nex_set.count());
|
|
|
|
|
NetBus nex_q (scope(), nex_set.count());
|
2002-09-16 02:30:33 +02:00
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
/* The Q of the NetFF devices is connected to the output that
|
|
|
|
|
we are. The nex_q is a bundle of the outputs. We will also
|
|
|
|
|
pass the nex_q as a map to the statement's synth_sync
|
|
|
|
|
method to map it to the correct nex_d pin. */
|
2002-09-16 02:30:33 +02:00
|
|
|
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
|
2005-04-25 01:44:01 +02:00
|
|
|
connect(nex_set[idx], nex_q.pin(idx));
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
// Connect the input later.
|
|
|
|
|
|
2002-09-16 02:30:33 +02:00
|
|
|
/* Synthesize the input to the DFF. */
|
2002-09-26 03:13:14 +02:00
|
|
|
bool flag = statement_->synth_sync(des, scope(), ff,
|
|
|
|
|
nex_q, nex_d,
|
|
|
|
|
svector<NetEvProbe*>());
|
2005-04-25 01:44:01 +02:00
|
|
|
if (! flag) {
|
|
|
|
|
delete ff;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2002-09-16 02:30:33 +02:00
|
|
|
|
|
|
|
|
|
2005-04-25 01:44:01 +02:00
|
|
|
NetNet*tmp = nex_d.pin(0).nexus()->pick_any_net();
|
|
|
|
|
assert(tmp);
|
|
|
|
|
|
|
|
|
|
tmp = crop_to_width(des, tmp, ff->width());
|
|
|
|
|
connect(tmp->pin(0), ff->pin_Data());
|
|
|
|
|
connect(nex_q.pin(0), ff->pin_Q());
|
|
|
|
|
|
|
|
|
|
for (unsigned idx = 1 ; idx < nex_set.count() ; idx += 1) {
|
|
|
|
|
NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
|
|
|
|
|
nex_set[idx]->vector_width());
|
|
|
|
|
des->add_node(ff2);
|
|
|
|
|
|
|
|
|
|
tmp = nex_d.pin(idx).nexus()->pick_any_net();
|
|
|
|
|
assert(tmp);
|
|
|
|
|
|
|
|
|
|
tmp = crop_to_width(des, tmp, ff2->width());
|
|
|
|
|
|
|
|
|
|
connect(nex_q.pin(idx), ff2->pin_Q());
|
|
|
|
|
connect(tmp->pin(0), ff2->pin_Data());
|
|
|
|
|
|
|
|
|
|
connect(ff->pin_Clock(), ff2->pin_Clock());
|
|
|
|
|
if (ff->pin_Enable().is_linked())
|
|
|
|
|
connect(ff->pin_Enable(), ff2->pin_Enable());
|
|
|
|
|
if (ff->pin_Aset().is_linked())
|
|
|
|
|
connect(ff->pin_Aset(), ff2->pin_Aset());
|
|
|
|
|
if (ff->pin_Aclr().is_linked())
|
|
|
|
|
connect(ff->pin_Aclr(), ff2->pin_Aclr());
|
|
|
|
|
if (ff->pin_Sset().is_linked())
|
|
|
|
|
connect(ff->pin_Sset(), ff2->pin_Sset());
|
|
|
|
|
if (ff->pin_Sclr().is_linked())
|
|
|
|
|
connect(ff->pin_Sclr(), ff2->pin_Sclr());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
2002-09-16 02:30:33 +02:00
|
|
|
}
|
|
|
|
|
|
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;
|
2007-11-17 03:10:16 +01:00
|
|
|
des->errors += 1;
|
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)
|
|
|
|
|
{
|
|
|
|
|
synth2_f synth_obj;
|
|
|
|
|
des->functor(&synth_obj);
|
|
|
|
|
}
|
|
|
|
|
|