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,
bool condit_src, bool conditional)
: 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();
unsigned find_link(const Link&that) const;
private: // not implemented
NetBus(const NetBus&);
NetBus& operator= (const NetBus&);
@ -2392,7 +2394,20 @@ class NetProc : public virtual LineInfo {
virtual bool synth_async(Design*des, NetScope*scope,
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 std::vector<NetEvProbe*>&events);
@ -2650,7 +2665,7 @@ class NetBlock : public NetProc {
bool synth_async(Design*des, NetScope*scope,
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 std::vector<NetEvProbe*>&events);
@ -2781,7 +2796,7 @@ class NetCondit : public NetProc {
bool synth_async(Design*des, NetScope*scope,
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 std::vector<NetEvProbe*>&events);
@ -3027,7 +3042,7 @@ class NetEvWait : public NetProc {
virtual bool synth_async(Design*des, NetScope*scope,
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 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::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)
: 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 atom2s8;
static netvector_t atom2u8;
static netvector_t scalar_bool;
static netvector_t scalar_logic;
private:
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;
}
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 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
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;
unsigned ptr = nex_map.find_link(tmp_map.pin(idx));
assert(ptr < nex_out.pin_count());
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
* the statements may each infer different reset and enable signals.
*/
bool NetBlock::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
const NetBus& /*nex_map*/, NetBus& /*nex_out*/,
const vector<NetEvProbe*>& /*events_in*/)
bool NetBlock::synth_sync(Design*des, NetScope*scope, NetNet*clk,
const NetBus&nex_map, NetBus&nex_out,
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;
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_;
do {
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. */
NexusSet tmp_set;
cur->nex_output(tmp_set);
NetNet*tmp_map = new NetNet(scope, tmp1, NetNet::WIRE,
tmp_set.count());
for (unsigned idx = 0 ; idx < tmp_map->pin_count() ; idx += 1)
connect(tmp_set[idx], tmp_map->pin(idx));
NetBus tmp_map (scope, tmp_set.count());
for (unsigned idx = 0 ; idx < tmp_map.pin_count() ; idx += 1)
connect(tmp_set[idx], tmp_map.pin(idx));
/* NOTE: After this point, tmp_set should not be used as
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
are used to collect the outputs from the substatement
for the inputs of the FF bank. */
NetNet*tmp_out = new NetNet(scope, tmp2, NetNet::WIRE,
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);
}
}
NetBus tmp_out (scope, tmp_set.count());
/* Now go on with the synchronous synthesis for this
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. */
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);
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
beyond the input set, for example when the l-value of
an assignment is smaller than the r-value. */
for (unsigned idx = 0 ; idx < tmp_out->pin_count() ; idx += 1) {
unsigned ptr = find_nexus_in_set(nex_map,
tmp_map->pin(idx).nexus());
if (ptr < nex_out->pin_count())
connect(nex_out->pin(ptr), tmp_out->pin(idx));
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
unsigned ptr = nex_map.find_link(tmp_map.pin(idx));
assert(ptr < nex_out.pin_count());
connect(nex_out.pin(ptr), tmp_out.pin(idx));
}
delete tmp_map;
delete tmp_out;
} 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;
#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
* 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 vector<NetEvProbe*>& /*events_in*/)
{
@ -775,7 +667,7 @@ bool NetCondit::synth_sync(Design*des, NetScope* /*scope*/, NetFF* /*ff*/,
#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 vector<NetEvProbe*>&events_in)
{
@ -833,10 +725,10 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
return false;
}
connect(ff->pin_Clock(), pclk->pin(0));
connect(clk->pin(0), pclk->pin(0));
if (pclk->edge() == NetEvProbe::NEGEDGE) {
perm_string polarity = perm_string::literal("Clock:LPM_Polarity");
ff->attribute(polarity, verinum("INVERT"));
clk->attribute(polarity, verinum("INVERT"));
if (debug_synth2) {
cerr << get_fileline() << ": debug: "
@ -846,7 +738,7 @@ bool NetEvWait::synth_sync(Design*des, NetScope*scope, NetFF*ff,
}
/* 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);
return flag;
@ -872,17 +764,10 @@ bool NetProcTop::synth_sync(Design*des)
set, and will also take the initial connection of clocks
and resets. */
if (debug_synth2) {
cerr << get_fileline() << ": debug: "
<< "Top level making a "
<< nex_set[0]->vector_width() << "-wide "
<< "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"));
// Create a net to carry the clock for the synthesized FFs.
NetNet*clock = new NetNet(scope(), scope()->local_symbol(),
NetNet::TRI, &netvector_t::scalar_logic);
clock->local_flag(true);
NetBus nex_d (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.
/* 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,
vector<NetEvProbe*>());
if (! flag) {
delete ff;
delete clock;
return false;
}
for (unsigned idx = 0 ; idx < nex_set.count() ; idx += 1) {
NetNet*tmp = nex_d.pin(0).nexus()->pick_any_net();
assert(tmp);
if (debug_synth2) {
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(),
nex_set[idx]->vector_width());
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);
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(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())
connect(ff->pin_Enable(), ff2->pin_Enable());
if (ff->pin_Aset().is_linked())
@ -938,6 +824,7 @@ bool NetProcTop::synth_sync(Design*des)
connect(ff->pin_Sset(), ff2->pin_Sset());
if (ff->pin_Sclr().is_linked())
connect(ff->pin_Sclr(), ff2->pin_Sclr());
#endif
}
return true;