Rework synchronous statement synthesis.

This changes the flow of the NetProc::synth_sync method, and
implements the NetBlock::synth_sync better.
This commit is contained in:
Stephen Williams 2013-08-23 18:22:32 -07:00
parent a47447610f
commit 1abf4f1aa1
5 changed files with 73 additions and 153 deletions

View File

@ -288,6 +288,19 @@ NetBus::~NetBus()
{ {
} }
unsigned NetBus::find_link(const Link&that) const
{
unsigned ptr = 0;
while (ptr < pin_count()) {
if (pin(ptr).is_linked(that))
return ptr;
ptr += 1;
}
return ptr;
}
NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins, NetDelaySrc::NetDelaySrc(NetScope*s, perm_string n, unsigned npins,
bool condit_src, bool conditional) bool condit_src, bool conditional)
: NetObj(s, n, npins + (condit_src?1:0)) : NetObj(s, n, npins + (condit_src?1:0))

View File

@ -449,6 +449,8 @@ class NetBus : public NetObj {
NetBus(NetScope*scope, unsigned pin_count); NetBus(NetScope*scope, unsigned pin_count);
~NetBus(); ~NetBus();
unsigned find_link(const Link&that) const;
private: // not implemented private: // not implemented
NetBus(const NetBus&); NetBus(const NetBus&);
NetBus& operator= (const NetBus&); NetBus& operator= (const NetBus&);
@ -2392,7 +2394,20 @@ class NetProc : public virtual LineInfo {
virtual bool synth_async(Design*des, NetScope*scope, virtual bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NetBus&nex_map, NetBus&nex_out);
virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff, // Synthesize as synchronous logic, and return true. That
// means binding the outputs to the data port of a FF, and the
// event inputs to a FF clock. Only some key NetProc sub-types
// that have specific meaning in synchronous statements. The
// remainder reduce to a call to synth_async that connects the
// output to the Data input of the FF.
//
// The events argument is filled in be the NetEvWait
// implementation of this method with the probes that it does
// not itself pick off as a clock. These events should be
// picked off by e.g. condit statements as set/reset inputs to
// the flipflop being generated.
virtual bool synth_sync(Design*des, NetScope*scope,
NetNet*clock,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
@ -2650,7 +2665,7 @@ class NetBlock : public NetProc {
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NetBus&nex_map, NetBus&nex_out);
bool synth_sync(Design*des, NetScope*scope, NetFF*ff, bool synth_sync(Design*des, NetScope*scope, NetNet*clock,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
@ -2781,7 +2796,7 @@ class NetCondit : public NetProc {
bool synth_async(Design*des, NetScope*scope, bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NetBus&nex_map, NetBus&nex_out);
bool synth_sync(Design*des, NetScope*scope, NetFF*ff, bool synth_sync(Design*des, NetScope*scope, NetNet*clock,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);
@ -3027,7 +3042,7 @@ class NetEvWait : public NetProc {
virtual bool synth_async(Design*des, NetScope*scope, virtual bool synth_async(Design*des, NetScope*scope,
const NetBus&nex_map, NetBus&nex_out); const NetBus&nex_map, NetBus&nex_out);
virtual bool synth_sync(Design*des, NetScope*scope, NetFF*ff, virtual bool synth_sync(Design*des, NetScope*scope, NetNet*clock,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const std::vector<NetEvProbe*>&events); const std::vector<NetEvProbe*>&events);

View File

@ -30,6 +30,9 @@ netvector_t netvector_t::atom2u16 (IVL_VT_BOOL, 15, 0, false);
netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 7, 0, true); netvector_t netvector_t::atom2s8 (IVL_VT_BOOL, 7, 0, true);
netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 7, 0, false); netvector_t netvector_t::atom2u8 (IVL_VT_BOOL, 7, 0, false);
//netvector_t netvector_t::scalar_bool (IVL_VT_BOOL);
netvector_t netvector_t::scalar_logic (IVL_VT_LOGIC);
netvector_t::netvector_t(ivl_variable_type_t type, long msb, long lsb, bool flag) netvector_t::netvector_t(ivl_variable_type_t type, long msb, long lsb, bool flag)
: type_(type), signed_(flag), isint_(false), is_scalar_(false) : type_(type), signed_(flag), isint_(false), is_scalar_(false)
{ {

View File

@ -75,6 +75,8 @@ class netvector_t : public ivl_type_s {
static netvector_t atom2u16; static netvector_t atom2u16;
static netvector_t atom2s8; static netvector_t atom2s8;
static netvector_t atom2u8; static netvector_t atom2u8;
static netvector_t scalar_bool;
static netvector_t scalar_logic;
private: private:
std::vector<netrange_t> packed_dims_; std::vector<netrange_t> packed_dims_;

185
synth2.cc
View File

@ -33,7 +33,7 @@ bool NetProc::synth_async(Design*, NetScope*, const NetBus&, NetBus&)
return false; return false;
} }
bool NetProc::synth_sync(Design*des, NetScope*scope, NetFF* /*ff*/, bool NetProc::synth_sync(Design*des, NetScope*scope, NetNet* /* clock */,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events) const vector<NetEvProbe*>&events)
{ {
@ -138,11 +138,7 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
to the tmp_map.pin(idx) pin, and link that to the to the tmp_map.pin(idx) pin, and link that to the
tmp_out.pin(idx) output link. */ tmp_out.pin(idx) output link. */
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = 0; unsigned ptr = nex_map.find_link(tmp_map.pin(idx));
while (ptr < nex_map.pin_count()
&& ! nex_map.pin(ptr).is_linked(tmp_map.pin(idx)))
ptr += 1;
assert(ptr < nex_out.pin_count()); assert(ptr < nex_out.pin_count());
connect(nex_out.pin(ptr), tmp_out.pin(idx)); connect(nex_out.pin(ptr), tmp_out.pin(idx));
} }
@ -395,30 +391,12 @@ bool NetProcTop::synth_async(Design*des)
* This needs to be split into a DFF bank for each statement, because * This needs to be split into a DFF bank for each statement, because
* the statements may each infer different reset and enable signals. * the statements may each infer different reset and enable signals.
*/ */
bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/, bool NetBlock::synth_sync(Design*des, NetScope*scope, NetNet*clk,
const NetBus& /*nex_map*/, NetBus& /*nex_out*/, const NetBus&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>& /*events_in*/) const vector<NetEvProbe*>&events_in)
{ {
if (last_ == 0) {
return true;
}
cerr << get_fileline() << ": sorry: "
<< "Forgot to implement NetBlock::synth_sync" << endl;
des->errors += 1;
return false;
#if 0
bool flag = true; bool flag = true;
const perm_string tmp1 = perm_string::literal("tmp1");
const perm_string tmp2 = perm_string::literal("tmp2");
/* 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;
NetProc*cur = last_; NetProc*cur = last_;
do { do {
cur = cur->next_; cur = cur->next_;
@ -426,10 +404,9 @@ bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
/* Create a temporary nex_map for the substatement. */ /* Create a temporary nex_map for the substatement. */
NexusSet tmp_set; NexusSet tmp_set;
cur->nex_output(tmp_set); cur->nex_output(tmp_set);
NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE, NetBus tmp_map (scope, tmp_set.count());
tmp_set.count()); for (unsigned idx = 0 ; idx < tmp_map.pin_count() ; idx += 1)
for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1) connect(tmp_set[idx], tmp_map.pin(idx));
connect(tmp_set[idx], tmp_map->pin(idx));
/* NOTE: After this point, tmp_set should not be used as /* NOTE: After this point, tmp_set should not be used as
the various functions I call do a lot of connecting, the various functions I call do a lot of connecting,
@ -440,85 +417,13 @@ bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
output. The tmp1 and tmp2 map and out sets together output. The tmp1 and tmp2 map and out sets together
are used to collect the outputs from the substatement are used to collect the outputs from the substatement
for the inputs of the FF bank. */ for the inputs of the FF bank. */
NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE, NetBus tmp_out (scope, tmp_set.count());
tmp_map->pin_count());
verinum tmp_aset = ff->aset_value();
verinum tmp_sset = ff->sset_value();
/* Create a new DFF to handle this part of the begin-end
block. Connect this NetFF to the associated pins of
the existing wide NetFF device. While I'm at it, also
copy the aset_value bits for the new ff device. */
NetFF*ff2 = new NetFF(scope, scope->local_symbol(),
tmp_out->pin_count());
des->add_node(ff2);
verinum aset_value2 (verinum::V1, ff2->width());
verinum sset_value2 (verinum::V1, ff2->width());
for (unsigned idx = 0 ; idx < ff2->width() ; idx += 1) {
unsigned ptr = find_nexus_in_set(nex_map,
tmp_map->pin(idx).nexus());
/* Connect Data and Q bits to the new FF. */
connect(ff->pin_Data(ptr), ff2->pin_Data(idx));
connect(ff->pin_Q(ptr), ff2->pin_Q(idx));
/* Copy the asynch set bit to the new device. */
if (ptr < tmp_aset.len())
aset_value2.set(idx, tmp_aset[ptr]);
/* Copy the synch set bit to the new device. */
if (ptr < tmp_sset.len())
sset_value2.set(idx, tmp_sset[ptr]);
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;
}
}
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());
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());
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());
/* 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()) {
if (aset_value2.is_zero()
&& 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);
}
}
/* Now go on with the synchronous synthesis for this /* Now go on with the synchronous synthesis for this
subset of the statement. The tmp_map is the output subset of the statement. The tmp_map is the output
nexa that we expect, and the tmp_out is where we want nexa that we expect, and the tmp_out is where we want
those outputs connected. */ those outputs connected. */
bool ok_flag = cur->synth_sync(des, scope, ff2, tmp_map, bool ok_flag = cur->synth_sync(des, scope, clk, tmp_map,
tmp_out, events_in); tmp_out, events_in);
flag = flag && ok_flag; flag = flag && ok_flag;
@ -530,28 +435,15 @@ bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
whole. It is occasionally possible to have outputs whole. It is occasionally possible to have outputs
beyond the input set, for example when the l-value of beyond the input set, for example when the l-value of
an assignment is smaller than the r-value. */ an assignment is smaller than the r-value. */
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) { for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = find_nexus_in_set(nex_map, unsigned ptr = nex_map.find_link(tmp_map.pin(idx));
tmp_map->pin(idx).nexus()); assert(ptr < nex_out.pin_count());
connect(nex_out.pin(ptr), tmp_out.pin(idx));
if (ptr < nex_out->pin_count())
connect(nex_out->pin(ptr), tmp_out->pin(idx));
} }
delete tmp_map;
delete tmp_out;
} while (cur != last_); } while (cur != last_);
delete[]pin_accounting;
/* Done. The large NetFF is no longer needed, as it has been
taken up by the smaller NetFF devices. */
delete ff;
return flag; return flag;
#endif
} }
/* /*
@ -560,7 +452,7 @@ bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
* asynchronous set/reset, depending on whether the pin of the * asynchronous set/reset, depending on whether the pin of the
* expression is connected to an event, or not. * expression is connected to an event, or not.
*/ */
bool NetCondit::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/, bool NetCondit::synth_sync(Design*des, NetScope* /*scope*/, NetNet* /*clk*/,
const NetBus& /*nex_map*/, NetBus& /*nex_out*/, const NetBus& /*nex_map*/, NetBus& /*nex_out*/,
const vector<NetEvProbe*>& /*events_in*/) const vector<NetEvProbe*>& /*events_in*/)
{ {
@ -775,7 +667,7 @@ bool NetCondit::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
#endif #endif
} }
bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff, bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetNet*clk,
const NetBus&nex_map, NetBus&nex_out, const NetBus&nex_map, NetBus&nex_out,
const vector<NetEvProbe*>&events_in) const vector<NetEvProbe*>&events_in)
{ {
@ -833,10 +725,10 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
return false; return false;
} }
connect(ff->pin_Clock(), pclk->pin(0)); connect(clk->pin(0), pclk->pin(0));
if (pclk->edge() == NetEvProbe::NEGEDGE) { if (pclk->edge() == NetEvProbe::NEGEDGE) {
perm_string polarity = perm_string::literal("Clock:LPM_Polarity"); perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
ff->attribute(polarity, verinum("INVERT")); clk->attribute(polarity, verinum("INVERT"));
if (debug_synth2) { if (debug_synth2) {
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": debug: "
@ -846,7 +738,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
} }
/* Synthesize the input to the DFF. */ /* Synthesize the input to the DFF. */
bool flag = statement_->synth_sync(des, scope, ff, bool flag = statement_->synth_sync(des, scope, clk,
nex_map, nex_out, events); nex_map, nex_out, events);
return flag; return flag;
@ -872,17 +764,10 @@ bool NetProcTop::synth_sync(Design*des)
set, and will also take the initial connection of clocks set, and will also take the initial connection of clocks
and resets. */ and resets. */
if (debug_synth2) { // Create a net to carry the clock for the synthesized FFs.
cerr << get_fileline() << ": debug: " NetNet*clock = new NetNet(scope(), scope()->local_symbol(),
<< "Top level making a " NetNet::TRI, &netvector_t::scalar_logic);
<< nex_set[0]->vector_width() << "-wide " clock->local_flag(true);
<< "NetFF device." << endl;
}
NetFF*ff = new NetFF(scope(), scope()->local_symbol(),
nex_set[0]->vector_width());
des->add_node(ff);
ff->attribute(perm_string::literal("LPM_FFType"), verinum("DFF"));
NetBus nex_d (scope(), nex_set.count()); NetBus nex_d (scope(), nex_set.count());
NetBus nex_q (scope(), nex_set.count()); NetBus nex_q (scope(), nex_set.count());
@ -898,28 +783,28 @@ bool NetProcTop::synth_sync(Design*des)
// Connect the input later. // Connect the input later.
/* Synthesize the input to the DFF. */ /* Synthesize the input to the DFF. */
bool flag = statement_->synth_sync(des, scope(), ff, bool flag = statement_->synth_sync(des, scope(), clock,
nex_q, nex_d, nex_q, nex_d,
vector<NetEvProbe*>()); vector<NetEvProbe*>());
if (! flag) { if (! flag) {
delete ff; delete clock;
return false; return false;
} }
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
NetNet*tmp = nex_d.pin(0).nexus()->pick_any_net(); if (debug_synth2) {
assert(tmp); cerr << get_fileline() << ": debug: "
<< "Top level making a "
<< nex_set[idx]->vector_width() << "-wide "
<< "NetFF device." << endl;
}
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(), NetFF*ff2 = new NetFF(scope(), scope()->local_symbol(),
nex_set[idx]->vector_width()); nex_set[idx]->vector_width());
des->add_node(ff2); des->add_node(ff2);
tmp = nex_d.pin(idx).nexus()->pick_any_net(); NetNet*tmp = nex_d.pin(idx).nexus()->pick_any_net();
assert(tmp); assert(tmp);
tmp = crop_to_width(des, tmp, ff2->width()); tmp = crop_to_width(des, tmp, ff2->width());
@ -927,7 +812,8 @@ bool NetProcTop::synth_sync(Design*des)
connect(nex_q.pin(idx), ff2->pin_Q()); connect(nex_q.pin(idx), ff2->pin_Q());
connect(tmp->pin(0), ff2->pin_Data()); connect(tmp->pin(0), ff2->pin_Data());
connect(ff->pin_Clock(), ff2->pin_Clock()); connect(clock->pin(0), ff2->pin_Clock());
#if 0
if (ff->pin_Enable().is_linked()) if (ff->pin_Enable().is_linked())
connect(ff->pin_Enable(), ff2->pin_Enable()); connect(ff->pin_Enable(), ff2->pin_Enable());
if (ff->pin_Aset().is_linked()) if (ff->pin_Aset().is_linked())
@ -938,6 +824,7 @@ bool NetProcTop::synth_sync(Design*des)
connect(ff->pin_Sset(), ff2->pin_Sset()); connect(ff->pin_Sset(), ff2->pin_Sset());
if (ff->pin_Sclr().is_linked()) if (ff->pin_Sclr().is_linked())
connect(ff->pin_Sclr(), ff2->pin_Sclr()); connect(ff->pin_Sclr(), ff2->pin_Sclr());
#endif
} }
return true; return true;