Merge branch 'master' into vec4-stack
Conflicts: vvp/vthread.cc Signed-off-by: Stephen Williams <steve@icarus.com>
This commit is contained in:
commit
ebed793dec
|
|
@ -788,7 +788,7 @@ unsigned PEBLeftWidth::test_width(Design*des, NetScope*scope, width_mode_t&mode)
|
||||||
case 'p': // **
|
case 'p': // **
|
||||||
if (lc && rc) {
|
if (lc && rc) {
|
||||||
verinum result = pow(lc->value(), rc->value());
|
verinum result = pow(lc->value(), rc->value());
|
||||||
use_width = result.len();
|
use_width = max(use_width, result.len());
|
||||||
} else {
|
} else {
|
||||||
if (signed_flag_) use_width -= 1;
|
if (signed_flag_) use_width -= 1;
|
||||||
use_width *= (unsigned)r_val;
|
use_width *= (unsigned)r_val;
|
||||||
|
|
|
||||||
|
|
@ -4029,7 +4029,7 @@ NetProc* PEventStatement::elaborate_st(Design*des, NetScope*scope,
|
||||||
ev, NetEvProbe::ANYEDGE,
|
ev, NetEvProbe::ANYEDGE,
|
||||||
nset->size());
|
nset->size());
|
||||||
for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
|
for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
|
||||||
connect(nset->at(idx).nex, pr->pin(idx));
|
connect(nset->at(idx).lnk, pr->pin(idx));
|
||||||
|
|
||||||
delete nset;
|
delete nset;
|
||||||
des->add_node(pr);
|
des->add_node(pr);
|
||||||
|
|
@ -4303,7 +4303,7 @@ NetProc* PEventStatement::elaborate_wait(Design*des, NetScope*scope,
|
||||||
wait_event, NetEvProbe::ANYEDGE,
|
wait_event, NetEvProbe::ANYEDGE,
|
||||||
wait_set->size());
|
wait_set->size());
|
||||||
for (unsigned idx = 0; idx < wait_set->size() ; idx += 1)
|
for (unsigned idx = 0; idx < wait_set->size() ; idx += 1)
|
||||||
connect(wait_set->at(idx).nex, wait_pr->pin(idx));
|
connect(wait_set->at(idx).lnk, wait_pr->pin(idx));
|
||||||
|
|
||||||
delete wait_set;
|
delete wait_set;
|
||||||
des->add_node(wait_pr);
|
des->add_node(wait_pr);
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
known to be 0. */
|
known to be 0. */
|
||||||
if ((op() == '&') && (lc->value() == verinum(0))) {
|
if ((op() == '&') && (lc->value() == verinum(0))) {
|
||||||
verinum res (verinum::V0, expr_width());
|
verinum res (verinum::V0, expr_width());
|
||||||
|
res.has_sign(has_sign());
|
||||||
NetEConst*tmp = new NetEConst(res);
|
NetEConst*tmp = new NetEConst(res);
|
||||||
ivl_assert(*this, tmp);
|
ivl_assert(*this, tmp);
|
||||||
eval_debug(this, tmp, false);
|
eval_debug(this, tmp, false);
|
||||||
|
|
@ -256,6 +257,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
|
|
||||||
if ((op() == '&') && (rc->value() == verinum(0))) {
|
if ((op() == '&') && (rc->value() == verinum(0))) {
|
||||||
verinum res (verinum::V0, expr_width());
|
verinum res (verinum::V0, expr_width());
|
||||||
|
res.has_sign(has_sign());
|
||||||
NetEConst*tmp = new NetEConst(res);
|
NetEConst*tmp = new NetEConst(res);
|
||||||
ivl_assert(*this, tmp);
|
ivl_assert(*this, tmp);
|
||||||
eval_debug(this, tmp, false);
|
eval_debug(this, tmp, false);
|
||||||
|
|
@ -306,6 +308,7 @@ NetEConst* NetEBBits::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.has_sign(has_sign());
|
||||||
NetEConst*tmp = new NetEConst(res);
|
NetEConst*tmp = new NetEConst(res);
|
||||||
ivl_assert(*this, tmp);
|
ivl_assert(*this, tmp);
|
||||||
eval_debug(this, tmp, false);
|
eval_debug(this, tmp, false);
|
||||||
|
|
@ -982,6 +985,7 @@ NetExpr* NetEBMinMax::eval_arguments_(const NetExpr*l, const NetExpr*r) const
|
||||||
} else {
|
} else {
|
||||||
res_val = verinum(verinum::Vx, wid);
|
res_val = verinum(verinum::Vx, wid);
|
||||||
}
|
}
|
||||||
|
res_val.has_sign(has_sign());
|
||||||
NetEConst*res = new NetEConst(res_val);
|
NetEConst*res = new NetEConst(res_val);
|
||||||
ivl_assert(*this, res);
|
ivl_assert(*this, res);
|
||||||
eval_debug(this, res, false);
|
eval_debug(this, res, false);
|
||||||
|
|
@ -1342,7 +1346,7 @@ NetExpr*NetETernary::blended_arguments_(const NetExpr*te, const NetExpr*fe) cons
|
||||||
if (t == 0 || f == 0) {
|
if (t == 0 || f == 0) {
|
||||||
verireal tv, fv;
|
verireal tv, fv;
|
||||||
if (!get_real_arg_(te, tv)) return 0;
|
if (!get_real_arg_(te, tv)) return 0;
|
||||||
if (!get_real_arg_(te, fv)) return 0;
|
if (!get_real_arg_(fe, fv)) return 0;
|
||||||
|
|
||||||
verireal val = verireal(0.0);
|
verireal val = verireal(0.0);
|
||||||
if (tv.as_double() == fv.as_double()) val = tv;
|
if (tv.as_double() == fv.as_double()) val = tv;
|
||||||
|
|
|
||||||
|
|
@ -1319,7 +1319,7 @@ static NetEvWait* make_func_trigger(Design*des, NetScope*scope, NetExpr*root)
|
||||||
nset->size());
|
nset->size());
|
||||||
pr->set_line(*root);
|
pr->set_line(*root);
|
||||||
for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
|
for (unsigned idx = 0 ; idx < nset->size() ; idx += 1)
|
||||||
connect(nset->at(idx).nex, pr->pin(idx));
|
connect(nset->at(idx).lnk, pr->pin(idx));
|
||||||
|
|
||||||
des->add_node(pr);
|
des->add_node(pr);
|
||||||
|
|
||||||
|
|
|
||||||
31
net_link.cc
31
net_link.cc
|
|
@ -524,6 +524,8 @@ NexusSet::NexusSet()
|
||||||
|
|
||||||
NexusSet::~NexusSet()
|
NexusSet::~NexusSet()
|
||||||
{
|
{
|
||||||
|
for (size_t idx = 0 ; idx < items_.size() ; idx += 1)
|
||||||
|
delete items_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NexusSet::size() const
|
size_t NexusSet::size() const
|
||||||
|
|
@ -534,7 +536,7 @@ size_t NexusSet::size() const
|
||||||
void NexusSet::add(Nexus*that, unsigned base, unsigned wid)
|
void NexusSet::add(Nexus*that, unsigned base, unsigned wid)
|
||||||
{
|
{
|
||||||
assert(that);
|
assert(that);
|
||||||
elem_t cur (that, base, wid);
|
elem_t*cur = new elem_t(that, base, wid);
|
||||||
|
|
||||||
if (items_.size() == 0) {
|
if (items_.size() == 0) {
|
||||||
items_.resize(1);
|
items_.resize(1);
|
||||||
|
|
@ -542,8 +544,9 @@ void NexusSet::add(Nexus*that, unsigned base, unsigned wid)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned ptr = bsearch_(cur);
|
unsigned ptr = bsearch_(*cur);
|
||||||
if (ptr < items_.size()) {
|
if (ptr < items_.size()) {
|
||||||
|
delete cur;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -552,26 +555,28 @@ void NexusSet::add(Nexus*that, unsigned base, unsigned wid)
|
||||||
items_.push_back(cur);
|
items_.push_back(cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NexusSet::add(const NexusSet&that)
|
void NexusSet::add(NexusSet&that)
|
||||||
{
|
{
|
||||||
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1)
|
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1)
|
||||||
add(that.items_[idx].nex, that.items_[idx].base, that.items_[idx].wid);
|
add(that.items_[idx]->lnk.nexus(), that.items_[idx]->base, that.items_[idx]->wid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NexusSet::rem_(const NexusSet::elem_t&that)
|
void NexusSet::rem_(const NexusSet::elem_t*that)
|
||||||
{
|
{
|
||||||
if (items_.empty())
|
if (items_.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
unsigned ptr = bsearch_(that);
|
unsigned ptr = bsearch_(*that);
|
||||||
if (ptr >= items_.size())
|
if (ptr >= items_.size())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (items_.size() == 1) {
|
if (items_.size() == 1) {
|
||||||
|
delete items_[0];
|
||||||
items_.clear();
|
items_.clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete items_[ptr];
|
||||||
for (unsigned idx = ptr ; idx < (items_.size()-1) ; idx += 1)
|
for (unsigned idx = ptr ; idx < (items_.size()-1) ; idx += 1)
|
||||||
items_[idx] = items_[idx+1];
|
items_[idx] = items_[idx+1];
|
||||||
|
|
||||||
|
|
@ -589,16 +594,16 @@ unsigned NexusSet::find_nexus(const NexusSet::elem_t&that) const
|
||||||
return bsearch_(that);
|
return bsearch_(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
const NexusSet::elem_t& NexusSet::at (unsigned idx) const
|
NexusSet::elem_t& NexusSet::at (unsigned idx)
|
||||||
{
|
{
|
||||||
assert(idx < items_.size());
|
assert(idx < items_.size());
|
||||||
return items_[idx];
|
return *items_[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const
|
size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const
|
||||||
{
|
{
|
||||||
for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
|
||||||
if (items_[idx]==that)
|
if (*items_[idx] == that)
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,7 +612,7 @@ size_t NexusSet::bsearch_(const NexusSet::elem_t&that) const
|
||||||
|
|
||||||
bool NexusSet::elem_t::contains(const struct elem_t&that) const
|
bool NexusSet::elem_t::contains(const struct elem_t&that) const
|
||||||
{
|
{
|
||||||
if (nex != that.nex)
|
if (! lnk.is_linked(that.lnk))
|
||||||
return false;
|
return false;
|
||||||
if (that.base < base)
|
if (that.base < base)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -620,7 +625,7 @@ bool NexusSet::elem_t::contains(const struct elem_t&that) const
|
||||||
bool NexusSet::contains_(const NexusSet::elem_t&that) const
|
bool NexusSet::contains_(const NexusSet::elem_t&that) const
|
||||||
{
|
{
|
||||||
for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < items_.size() ; idx += 1) {
|
||||||
if (items_[idx].contains(that))
|
if (items_[idx]->contains(that))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -629,7 +634,7 @@ bool NexusSet::contains_(const NexusSet::elem_t&that) const
|
||||||
bool NexusSet::contains(const NexusSet&that) const
|
bool NexusSet::contains(const NexusSet&that) const
|
||||||
{
|
{
|
||||||
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
|
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
|
||||||
if (! contains_(that.items_[idx]))
|
if (! contains_(*that.items_[idx]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -639,7 +644,7 @@ bool NexusSet::contains(const NexusSet&that) const
|
||||||
bool NexusSet::intersect(const NexusSet&that) const
|
bool NexusSet::intersect(const NexusSet&that) const
|
||||||
{
|
{
|
||||||
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
|
for (size_t idx = 0 ; idx < that.items_.size() ; idx += 1) {
|
||||||
size_t where = bsearch_(that.items_[idx]);
|
size_t where = bsearch_(*that.items_[idx]);
|
||||||
if (where == items_.size())
|
if (where == items_.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
||||||
63
netlist.h
63
netlist.h
|
|
@ -96,6 +96,7 @@ class Link {
|
||||||
friend void connect(Link&, Link&);
|
friend void connect(Link&, Link&);
|
||||||
friend class NetPins;
|
friend class NetPins;
|
||||||
friend class Nexus;
|
friend class Nexus;
|
||||||
|
friend class NexusSet;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum DIR { PASSIVE, INPUT, OUTPUT };
|
enum DIR { PASSIVE, INPUT, OUTPUT };
|
||||||
|
|
@ -409,17 +410,25 @@ class NexusSet {
|
||||||
public:
|
public:
|
||||||
struct elem_t {
|
struct elem_t {
|
||||||
inline elem_t(Nexus*n, unsigned b, unsigned w)
|
inline elem_t(Nexus*n, unsigned b, unsigned w)
|
||||||
: nex(n), base(b), wid(w)
|
: base(b), wid(w)
|
||||||
{ }
|
{
|
||||||
inline elem_t() : nex(0), base(0), wid(0) { }
|
lnk.set_dir(Link::PASSIVE);
|
||||||
|
n->connect(lnk);
|
||||||
|
}
|
||||||
|
inline elem_t() : base(0), wid(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
inline bool operator == (const struct elem_t&that) const
|
inline bool operator == (const struct elem_t&that) const
|
||||||
{ return nex==that.nex && base==that.base && wid==that.wid; }
|
{ return lnk.is_linked(that.lnk) && base==that.base && wid==that.wid; }
|
||||||
|
|
||||||
bool contains(const struct elem_t&that) const;
|
bool contains(const struct elem_t&that) const;
|
||||||
|
|
||||||
Nexus*nex;
|
Link lnk;
|
||||||
unsigned base;
|
unsigned base;
|
||||||
unsigned wid;
|
unsigned wid;
|
||||||
|
private:
|
||||||
|
elem_t(const elem_t&);
|
||||||
|
elem_t& operator= (elem_t&);
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -430,15 +439,15 @@ class NexusSet {
|
||||||
|
|
||||||
// Add the nexus/part to the set, if it is not already present.
|
// Add the nexus/part to the set, if it is not already present.
|
||||||
void add(Nexus*that, unsigned base, unsigned wid);
|
void add(Nexus*that, unsigned base, unsigned wid);
|
||||||
void add(const NexusSet&that);
|
void add(NexusSet&that);
|
||||||
|
|
||||||
// Remove the nexus from the set, if it is present.
|
// Remove the nexus from the set, if it is present.
|
||||||
void rem(const NexusSet&that);
|
void rem(const NexusSet&that);
|
||||||
|
|
||||||
unsigned find_nexus(const elem_t&that) const;
|
unsigned find_nexus(const elem_t&that) const;
|
||||||
|
|
||||||
const elem_t& at(unsigned idx) const;
|
elem_t& at(unsigned idx);
|
||||||
inline const elem_t& operator[] (unsigned idx) const { return at(idx); }
|
inline elem_t& operator[] (unsigned idx) { return at(idx); }
|
||||||
|
|
||||||
// Return true if this set contains every nexus/part in that
|
// Return true if this set contains every nexus/part in that
|
||||||
// set. That means that every bit of that set is accounted for
|
// set. That means that every bit of that set is accounted for
|
||||||
|
|
@ -450,11 +459,11 @@ class NexusSet {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// NexSet items are canonical part selects of vectors.
|
// NexSet items are canonical part selects of vectors.
|
||||||
std::vector<struct elem_t> items_;
|
std::vector<struct elem_t*> items_;
|
||||||
|
|
||||||
size_t bsearch_(const struct elem_t&that) const;
|
size_t bsearch_(const struct elem_t&that) const;
|
||||||
void rem_(const struct elem_t&that);
|
void rem_(const struct elem_t*that);
|
||||||
bool contains_(const elem_t&htat) const;
|
bool contains_(const elem_t&that) const;
|
||||||
|
|
||||||
private: // not implemented
|
private: // not implemented
|
||||||
NexusSet(const NexusSet&);
|
NexusSet(const NexusSet&);
|
||||||
|
|
@ -2493,9 +2502,14 @@ class NetProc : public virtual LineInfo {
|
||||||
// process. Most process types are not.
|
// process. Most process types are not.
|
||||||
virtual bool is_synchronous();
|
virtual bool is_synchronous();
|
||||||
|
|
||||||
// Synthesize as asynchronous logic, and return true.
|
// Synthesize as asynchronous logic, and return true. The
|
||||||
|
// nex_out is where this function attaches its output
|
||||||
|
// results. The accumulated_nex_out is used by sequential
|
||||||
|
// blocks to show outputs from the previous code.
|
||||||
virtual bool synth_async(Design*des, NetScope*scope,
|
virtual bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map,
|
||||||
|
NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
// Synthesize as synchronous logic, and return true. That
|
// Synthesize as synchronous logic, and return true. That
|
||||||
// means binding the outputs to the data port of a FF, and the
|
// means binding the outputs to the data port of a FF, and the
|
||||||
|
|
@ -2511,7 +2525,7 @@ class NetProc : public virtual LineInfo {
|
||||||
// the flipflop being generated.
|
// the flipflop being generated.
|
||||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clock, NetNet*ff_ce,
|
NetNet*ff_clock, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const std::vector<NetEvProbe*>&events);
|
const std::vector<NetEvProbe*>&events);
|
||||||
|
|
||||||
virtual void dump(ostream&, unsigned ind) const;
|
virtual void dump(ostream&, unsigned ind) const;
|
||||||
|
|
@ -2695,7 +2709,8 @@ class NetAssignBase : public NetProc {
|
||||||
unsigned lwidth() const;
|
unsigned lwidth() const;
|
||||||
|
|
||||||
bool synth_async(Design*des, NetScope*scope,
|
bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
// This dumps all the lval structures.
|
// This dumps all the lval structures.
|
||||||
void dump_lval(ostream&) const;
|
void dump_lval(ostream&) const;
|
||||||
|
|
@ -2780,11 +2795,12 @@ class NetBlock : public NetProc {
|
||||||
|
|
||||||
// synthesize as asynchronous logic, and return true.
|
// synthesize as asynchronous logic, and return true.
|
||||||
bool synth_async(Design*des, NetScope*scope,
|
bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
bool synth_sync(Design*des, NetScope*scope,
|
bool synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const std::vector<NetEvProbe*>&events);
|
const std::vector<NetEvProbe*>&events);
|
||||||
|
|
||||||
// This version of emit_recurse scans all the statements of
|
// This version of emit_recurse scans all the statements of
|
||||||
|
|
@ -2837,7 +2853,8 @@ class NetCase : public NetProc {
|
||||||
virtual void nex_output(NexusSet&out);
|
virtual void nex_output(NexusSet&out);
|
||||||
|
|
||||||
bool synth_async(Design*des, NetScope*scope,
|
bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
virtual bool emit_proc(struct target_t*) const;
|
virtual bool emit_proc(struct target_t*) const;
|
||||||
virtual void dump(ostream&, unsigned ind) const;
|
virtual void dump(ostream&, unsigned ind) const;
|
||||||
|
|
@ -2912,11 +2929,12 @@ class NetCondit : public NetProc {
|
||||||
|
|
||||||
bool is_asynchronous();
|
bool is_asynchronous();
|
||||||
bool synth_async(Design*des, NetScope*scope,
|
bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
bool synth_sync(Design*des, NetScope*scope,
|
bool synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const std::vector<NetEvProbe*>&events);
|
const std::vector<NetEvProbe*>&events);
|
||||||
|
|
||||||
virtual bool emit_proc(struct target_t*) const;
|
virtual bool emit_proc(struct target_t*) const;
|
||||||
|
|
@ -3187,11 +3205,12 @@ class NetEvWait : public NetProc {
|
||||||
virtual void nex_output(NexusSet&out);
|
virtual void nex_output(NexusSet&out);
|
||||||
|
|
||||||
virtual bool synth_async(Design*des, NetScope*scope,
|
virtual bool synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out);
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out);
|
||||||
|
|
||||||
virtual bool synth_sync(Design*des, NetScope*scope,
|
virtual bool synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const std::vector<NetEvProbe*>&events);
|
const std::vector<NetEvProbe*>&events);
|
||||||
|
|
||||||
virtual void dump(ostream&, unsigned ind) const;
|
virtual void dump(ostream&, unsigned ind) const;
|
||||||
|
|
|
||||||
509
parse.y
509
parse.y
|
|
@ -607,7 +607,7 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
|
||||||
%type <property_qualifier> class_item_qualifier_opt property_qualifier_opt
|
%type <property_qualifier> class_item_qualifier_opt property_qualifier_opt
|
||||||
%type <property_qualifier> random_qualifier
|
%type <property_qualifier> random_qualifier
|
||||||
|
|
||||||
%type <ranges> range range_opt variable_dimension
|
%type <ranges> variable_dimension
|
||||||
%type <ranges> dimensions_opt dimensions
|
%type <ranges> dimensions_opt dimensions
|
||||||
|
|
||||||
%type <nettype> net_type var_type net_type_opt
|
%type <nettype> net_type var_type net_type_opt
|
||||||
|
|
@ -973,7 +973,7 @@ data_declaration /* IEEE1800-2005: A.2.1.3 */
|
||||||
;
|
;
|
||||||
|
|
||||||
data_type /* IEEE1800-2005: A.2.2.1 */
|
data_type /* IEEE1800-2005: A.2.2.1 */
|
||||||
: integer_vector_type unsigned_signed_opt range_opt
|
: integer_vector_type unsigned_signed_opt dimensions_opt
|
||||||
{ ivl_variable_type_t use_vtype = $1;
|
{ ivl_variable_type_t use_vtype = $1;
|
||||||
bool reg_flag = false;
|
bool reg_flag = false;
|
||||||
if (use_vtype == IVL_VT_NO_TYPE) {
|
if (use_vtype == IVL_VT_NO_TYPE) {
|
||||||
|
|
@ -1012,7 +1012,7 @@ data_type /* IEEE1800-2005: A.2.2.1 */
|
||||||
tmp->reg_flag = true;
|
tmp->reg_flag = true;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| TYPE_IDENTIFIER range_opt
|
| TYPE_IDENTIFIER dimensions_opt
|
||||||
{ if ($2) $$ = new parray_type_t($1, $2);
|
{ if ($2) $$ = new parray_type_t($1, $2);
|
||||||
else $$ = $1;
|
else $$ = $1;
|
||||||
}
|
}
|
||||||
|
|
@ -1038,13 +1038,13 @@ data_type /* IEEE1800-2005: A.2.2.1 */
|
||||||
data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */
|
data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */
|
||||||
: data_type
|
: data_type
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| signing range_opt
|
| signing dimensions_opt
|
||||||
{ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2);
|
{ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2);
|
||||||
tmp->implicit_flag = true;
|
tmp->implicit_flag = true;
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| range
|
| dimensions
|
||||||
{ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1);
|
{ vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1);
|
||||||
tmp->implicit_flag = true;
|
tmp->implicit_flag = true;
|
||||||
FILE_NAME(tmp, @1);
|
FILE_NAME(tmp, @1);
|
||||||
|
|
@ -1796,7 +1796,7 @@ task_declaration /* IEEE1800-2005: A.2.7 */
|
||||||
|
|
||||||
|
|
||||||
tf_port_declaration /* IEEE1800-2005: A.2.7 */
|
tf_port_declaration /* IEEE1800-2005: A.2.7 */
|
||||||
: port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';'
|
: port_direction K_reg_opt unsigned_signed_opt dimensions_opt list_of_identifiers ';'
|
||||||
{ vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1,
|
{ vector<pform_tf_port_t>*tmp = pform_make_task_ports(@1, $1,
|
||||||
$2 ? IVL_VT_LOGIC :
|
$2 ? IVL_VT_LOGIC :
|
||||||
IVL_VT_NO_TYPE,
|
IVL_VT_NO_TYPE,
|
||||||
|
|
@ -1844,7 +1844,7 @@ tf_port_declaration /* IEEE1800-2005: A.2.7 */
|
||||||
|
|
||||||
tf_port_item /* IEEE1800-2005: A.2.7 */
|
tf_port_item /* IEEE1800-2005: A.2.7 */
|
||||||
|
|
||||||
: port_direction_opt data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt
|
: port_direction_opt data_type_or_implicit IDENTIFIER dimensions_opt tf_port_item_expr_opt
|
||||||
{ vector<pform_tf_port_t>*tmp;
|
{ vector<pform_tf_port_t>*tmp;
|
||||||
NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1;
|
NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1;
|
||||||
perm_string name = lex_strings.make($3);
|
perm_string name = lex_strings.make($3);
|
||||||
|
|
@ -2169,6 +2169,15 @@ type_declaration
|
||||||
pform_set_typedef(name, tmp);
|
pform_set_typedef(name, tmp);
|
||||||
delete[]$2;
|
delete[]$2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
| K_typedef data_type TYPE_IDENTIFIER ';'
|
||||||
|
{ yyerror(@3, "error: Typedef identifier is already a type name."); }
|
||||||
|
|
||||||
|
| K_typedef error ';'
|
||||||
|
{ yyerror(@2, "error: Syntax error in typedef clause.");
|
||||||
|
yyerrok;
|
||||||
|
}
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
/* The structure for an enumeration data type is the keyword "enum",
|
/* The structure for an enumeration data type is the keyword "enum",
|
||||||
|
|
@ -2204,7 +2213,7 @@ enum_data_type
|
||||||
enum_type->range.reset(make_range_from_width(integer_width));
|
enum_type->range.reset(make_range_from_width(integer_width));
|
||||||
$$ = enum_type;
|
$$ = enum_type;
|
||||||
}
|
}
|
||||||
| K_enum K_logic unsigned_signed_opt range '{' enum_name_list '}'
|
| K_enum K_logic unsigned_signed_opt dimensions '{' enum_name_list '}'
|
||||||
{ enum_type_t*enum_type = new enum_type_t;
|
{ enum_type_t*enum_type = new enum_type_t;
|
||||||
FILE_NAME(enum_type, @1);
|
FILE_NAME(enum_type, @1);
|
||||||
enum_type->names .reset($6);
|
enum_type->names .reset($6);
|
||||||
|
|
@ -2213,7 +2222,7 @@ enum_data_type
|
||||||
enum_type->range.reset($4);
|
enum_type->range.reset($4);
|
||||||
$$ = enum_type;
|
$$ = enum_type;
|
||||||
}
|
}
|
||||||
| K_enum K_reg unsigned_signed_opt range '{' enum_name_list '}'
|
| K_enum K_reg unsigned_signed_opt dimensions '{' enum_name_list '}'
|
||||||
{ enum_type_t*enum_type = new enum_type_t;
|
{ enum_type_t*enum_type = new enum_type_t;
|
||||||
FILE_NAME(enum_type, @1);
|
FILE_NAME(enum_type, @1);
|
||||||
enum_type->names .reset($6);
|
enum_type->names .reset($6);
|
||||||
|
|
@ -2222,7 +2231,7 @@ enum_data_type
|
||||||
enum_type->range.reset($4);
|
enum_type->range.reset($4);
|
||||||
$$ = enum_type;
|
$$ = enum_type;
|
||||||
}
|
}
|
||||||
| K_enum K_bit unsigned_signed_opt range '{' enum_name_list '}'
|
| K_enum K_bit unsigned_signed_opt dimensions '{' enum_name_list '}'
|
||||||
{ enum_type_t*enum_type = new enum_type_t;
|
{ enum_type_t*enum_type = new enum_type_t;
|
||||||
FILE_NAME(enum_type, @1);
|
FILE_NAME(enum_type, @1);
|
||||||
enum_type->names .reset($6);
|
enum_type->names .reset($6);
|
||||||
|
|
@ -2425,12 +2434,12 @@ defparam_assign
|
||||||
;
|
;
|
||||||
|
|
||||||
defparam_assign_list
|
defparam_assign_list
|
||||||
: defparam_assign
|
: defparam_assign
|
||||||
| range defparam_assign
|
| dimensions defparam_assign
|
||||||
{ yyerror(@1, "error: defparam may not include a range.");
|
{ yyerror(@1, "error: defparam may not include a range.");
|
||||||
delete $1;
|
delete $1;
|
||||||
}
|
}
|
||||||
| defparam_assign_list ',' defparam_assign
|
| defparam_assign_list ',' defparam_assign
|
||||||
;
|
;
|
||||||
|
|
||||||
delay1
|
delay1
|
||||||
|
|
@ -2782,209 +2791,209 @@ expression
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| inside_expression
|
| inside_expression
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| '+' expr_primary %prec UNARY_PREC
|
| '+' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ $$ = $2; }
|
{ $$ = $3; }
|
||||||
| '-' expr_primary %prec UNARY_PREC
|
| '-' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('-', $2);
|
{ PEUnary*tmp = new PEUnary('-', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '~' expr_primary %prec UNARY_PREC
|
| '~' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('~', $2);
|
{ PEUnary*tmp = new PEUnary('~', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '&' expr_primary %prec UNARY_PREC
|
| '&' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('&', $2);
|
{ PEUnary*tmp = new PEUnary('&', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '!' expr_primary %prec UNARY_PREC
|
| '!' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('!', $2);
|
{ PEUnary*tmp = new PEUnary('!', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '|' expr_primary %prec UNARY_PREC
|
| '|' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('|', $2);
|
{ PEUnary*tmp = new PEUnary('|', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '^' expr_primary %prec UNARY_PREC
|
| '^' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('^', $2);
|
{ PEUnary*tmp = new PEUnary('^', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '~' '&' expr_primary %prec UNARY_PREC
|
| '~' '&' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ yyerror(@1, "error: '~' '&' is not a valid expression. "
|
{ yyerror(@1, "error: '~' '&' is not a valid expression. "
|
||||||
"Please use operator '~&' instead.");
|
"Please use operator '~&' instead.");
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| '~' '|' expr_primary %prec UNARY_PREC
|
| '~' '|' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ yyerror(@1, "error: '~' '|' is not a valid expression. "
|
{ yyerror(@1, "error: '~' '|' is not a valid expression. "
|
||||||
"Please use operator '~|' instead.");
|
"Please use operator '~|' instead.");
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| '~' '^' expr_primary %prec UNARY_PREC
|
| '~' '^' attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ yyerror(@1, "error: '~' '^' is not a valid expression. "
|
{ yyerror(@1, "error: '~' '^' is not a valid expression. "
|
||||||
"Please use operator '~^' instead.");
|
"Please use operator '~^' instead.");
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| K_NAND expr_primary %prec UNARY_PREC
|
| K_NAND attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('A', $2);
|
{ PEUnary*tmp = new PEUnary('A', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| K_NOR expr_primary %prec UNARY_PREC
|
| K_NOR attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('N', $2);
|
{ PEUnary*tmp = new PEUnary('N', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| K_NXOR expr_primary %prec UNARY_PREC
|
| K_NXOR attribute_list_opt expr_primary %prec UNARY_PREC
|
||||||
{ PEUnary*tmp = new PEUnary('X', $2);
|
{ PEUnary*tmp = new PEUnary('X', $3);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| '!' error %prec UNARY_PREC
|
| '!' error %prec UNARY_PREC
|
||||||
{ yyerror(@1, "error: Operand of unary ! "
|
{ yyerror(@1, "error: Operand of unary ! "
|
||||||
"is not a primary expression.");
|
"is not a primary expression.");
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| '^' error %prec UNARY_PREC
|
| '^' error %prec UNARY_PREC
|
||||||
{ yyerror(@1, "error: Operand of reduction ^ "
|
{ yyerror(@1, "error: Operand of reduction ^ "
|
||||||
"is not a primary expression.");
|
"is not a primary expression.");
|
||||||
$$ = 0;
|
$$ = 0;
|
||||||
}
|
}
|
||||||
| expression '^' expression
|
| expression '^' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('^', $1, $3);
|
{ PEBinary*tmp = new PEBinary('^', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_POW expression
|
| expression K_POW attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBPower('p', $1, $3);
|
{ PEBinary*tmp = new PEBPower('p', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '*' expression
|
| expression '*' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('*', $1, $3);
|
{ PEBinary*tmp = new PEBinary('*', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '/' expression
|
| expression '/' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('/', $1, $3);
|
{ PEBinary*tmp = new PEBinary('/', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '%' expression
|
| expression '%' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('%', $1, $3);
|
{ PEBinary*tmp = new PEBinary('%', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '+' expression
|
| expression '+' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('+', $1, $3);
|
{ PEBinary*tmp = new PEBinary('+', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '-' expression
|
| expression '-' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('-', $1, $3);
|
{ PEBinary*tmp = new PEBinary('-', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '&' expression
|
| expression '&' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('&', $1, $3);
|
{ PEBinary*tmp = new PEBinary('&', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '|' expression
|
| expression '|' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('|', $1, $3);
|
{ PEBinary*tmp = new PEBinary('|', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_NAND expression
|
| expression K_NAND attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('A', $1, $3);
|
{ PEBinary*tmp = new PEBinary('A', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_NOR expression
|
| expression K_NOR attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('O', $1, $3);
|
{ PEBinary*tmp = new PEBinary('O', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_NXOR expression
|
| expression K_NXOR attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBinary('X', $1, $3);
|
{ PEBinary*tmp = new PEBinary('X', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '<' expression
|
| expression '<' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('<', $1, $3);
|
{ PEBinary*tmp = new PEBComp('<', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '>' expression
|
| expression '>' attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('>', $1, $3);
|
{ PEBinary*tmp = new PEBComp('>', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_LS expression
|
| expression K_LS attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBShift('l', $1, $3);
|
{ PEBinary*tmp = new PEBShift('l', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_RS expression
|
| expression K_RS attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBShift('r', $1, $3);
|
{ PEBinary*tmp = new PEBShift('r', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_RSS expression
|
| expression K_RSS attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBShift('R', $1, $3);
|
{ PEBinary*tmp = new PEBShift('R', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_EQ expression
|
| expression K_EQ attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('e', $1, $3);
|
{ PEBinary*tmp = new PEBComp('e', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_CEQ expression
|
| expression K_CEQ attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('E', $1, $3);
|
{ PEBinary*tmp = new PEBComp('E', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_LE expression
|
| expression K_LE attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('L', $1, $3);
|
{ PEBinary*tmp = new PEBComp('L', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_GE expression
|
| expression K_GE attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('G', $1, $3);
|
{ PEBinary*tmp = new PEBComp('G', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_NE expression
|
| expression K_NE attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('n', $1, $3);
|
{ PEBinary*tmp = new PEBComp('n', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_CNE expression
|
| expression K_CNE attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBComp('N', $1, $3);
|
{ PEBinary*tmp = new PEBComp('N', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_LOR expression
|
| expression K_LOR attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBLogic('o', $1, $3);
|
{ PEBinary*tmp = new PEBLogic('o', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression K_LAND expression
|
| expression K_LAND attribute_list_opt expression
|
||||||
{ PEBinary*tmp = new PEBLogic('a', $1, $3);
|
{ PEBinary*tmp = new PEBLogic('a', $1, $4);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| expression '?' expression ':' expression
|
| expression '?' attribute_list_opt expression ':' expression
|
||||||
{ PETernary*tmp = new PETernary($1, $3, $5);
|
{ PETernary*tmp = new PETernary($1, $4, $6);
|
||||||
FILE_NAME(tmp, @2);
|
FILE_NAME(tmp, @2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
expr_mintypmax
|
expr_mintypmax
|
||||||
: expression
|
: expression
|
||||||
|
|
@ -3471,7 +3480,7 @@ gate_instance
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
| IDENTIFIER range '(' expression_list_with_nuls ')'
|
| IDENTIFIER dimensions '(' expression_list_with_nuls ')'
|
||||||
{ lgate*tmp = new lgate;
|
{ lgate*tmp = new lgate;
|
||||||
list<pform_range_t>*rng = $2;
|
list<pform_range_t>*rng = $2;
|
||||||
tmp->name = $1;
|
tmp->name = $1;
|
||||||
|
|
@ -3497,7 +3506,7 @@ gate_instance
|
||||||
|
|
||||||
/* Degenerate modules can have no ports. */
|
/* Degenerate modules can have no ports. */
|
||||||
|
|
||||||
| IDENTIFIER range
|
| IDENTIFIER dimensions
|
||||||
{ lgate*tmp = new lgate;
|
{ lgate*tmp = new lgate;
|
||||||
list<pform_range_t>*rng = $2;
|
list<pform_range_t>*rng = $2;
|
||||||
tmp->name = $1;
|
tmp->name = $1;
|
||||||
|
|
@ -3526,7 +3535,7 @@ gate_instance
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
| IDENTIFIER range '(' port_name_list ')'
|
| IDENTIFIER dimensions '(' port_name_list ')'
|
||||||
{ lgate*tmp = new lgate;
|
{ lgate*tmp = new lgate;
|
||||||
list<pform_range_t>*rng = $2;
|
list<pform_range_t>*rng = $2;
|
||||||
tmp->name = $1;
|
tmp->name = $1;
|
||||||
|
|
@ -3555,7 +3564,7 @@ gate_instance
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
| IDENTIFIER range '(' error ')'
|
| IDENTIFIER dimensions '(' error ')'
|
||||||
{ lgate*tmp = new lgate;
|
{ lgate*tmp = new lgate;
|
||||||
tmp->name = $1;
|
tmp->name = $1;
|
||||||
tmp->parms = 0;
|
tmp->parms = 0;
|
||||||
|
|
@ -3773,7 +3782,7 @@ list_of_port_declarations
|
||||||
;
|
;
|
||||||
|
|
||||||
port_declaration
|
port_declaration
|
||||||
: attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER
|
: attribute_list_opt K_input net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
|
||||||
{ Module::port_t*ptmp;
|
{ Module::port_t*ptmp;
|
||||||
perm_string name = lex_strings.make($5);
|
perm_string name = lex_strings.make($5);
|
||||||
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
|
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
|
||||||
|
|
@ -3787,6 +3796,10 @@ port_declaration
|
||||||
port_declaration_context.range = 0;
|
port_declaration_context.range = 0;
|
||||||
port_declaration_context.data_type = $4;
|
port_declaration_context.data_type = $4;
|
||||||
delete[]$5;
|
delete[]$5;
|
||||||
|
if ($6) {
|
||||||
|
yyerror(@6, "sorry: Input ports with unpacked dimensions not supported.");
|
||||||
|
delete $6;
|
||||||
|
}
|
||||||
$$ = ptmp;
|
$$ = ptmp;
|
||||||
}
|
}
|
||||||
| attribute_list_opt
|
| attribute_list_opt
|
||||||
|
|
@ -3807,7 +3820,7 @@ port_declaration
|
||||||
delete[]$4;
|
delete[]$4;
|
||||||
$$ = ptmp;
|
$$ = ptmp;
|
||||||
}
|
}
|
||||||
| attribute_list_opt K_inout net_type_opt data_type_or_implicit IDENTIFIER
|
| attribute_list_opt K_inout net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
|
||||||
{ Module::port_t*ptmp;
|
{ Module::port_t*ptmp;
|
||||||
perm_string name = lex_strings.make($5);
|
perm_string name = lex_strings.make($5);
|
||||||
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
|
ptmp = pform_module_port_reference(name, @2.text, @2.first_line);
|
||||||
|
|
@ -3821,6 +3834,10 @@ port_declaration
|
||||||
port_declaration_context.range = 0;
|
port_declaration_context.range = 0;
|
||||||
port_declaration_context.data_type = $4;
|
port_declaration_context.data_type = $4;
|
||||||
delete[]$5;
|
delete[]$5;
|
||||||
|
if ($6) {
|
||||||
|
yyerror(@6, "sorry: Inout ports with unpacked dimensions not supported.");
|
||||||
|
delete $6;
|
||||||
|
}
|
||||||
$$ = ptmp;
|
$$ = ptmp;
|
||||||
}
|
}
|
||||||
| attribute_list_opt
|
| attribute_list_opt
|
||||||
|
|
@ -3841,7 +3858,7 @@ port_declaration
|
||||||
delete[]$4;
|
delete[]$4;
|
||||||
$$ = ptmp;
|
$$ = ptmp;
|
||||||
}
|
}
|
||||||
| attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER
|
| attribute_list_opt K_output net_type_opt data_type_or_implicit IDENTIFIER dimensions_opt
|
||||||
{ Module::port_t*ptmp;
|
{ Module::port_t*ptmp;
|
||||||
perm_string name = lex_strings.make($5);
|
perm_string name = lex_strings.make($5);
|
||||||
NetNet::Type use_type = $3;
|
NetNet::Type use_type = $3;
|
||||||
|
|
@ -3875,6 +3892,10 @@ port_declaration
|
||||||
port_declaration_context.range = 0;
|
port_declaration_context.range = 0;
|
||||||
port_declaration_context.data_type = $4;
|
port_declaration_context.data_type = $4;
|
||||||
delete[]$5;
|
delete[]$5;
|
||||||
|
if ($6) {
|
||||||
|
yyerror(@6, "sorry: Output ports with unpacked dimensions not supported.");
|
||||||
|
delete $6;
|
||||||
|
}
|
||||||
$$ = ptmp;
|
$$ = ptmp;
|
||||||
}
|
}
|
||||||
| attribute_list_opt
|
| attribute_list_opt
|
||||||
|
|
@ -4283,23 +4304,23 @@ module_item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
| K_trireg charge_strength_opt range_opt delay3_opt list_of_identifiers ';'
|
| K_trireg charge_strength_opt dimensions_opt delay3_opt list_of_identifiers ';'
|
||||||
{ yyerror(@1, "sorry: trireg nets not supported.");
|
{ yyerror(@1, "sorry: trireg nets not supported.");
|
||||||
delete $3;
|
delete $3;
|
||||||
delete $4;
|
delete $4;
|
||||||
}
|
}
|
||||||
|
|
||||||
| attribute_list_opt port_direction unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';'
|
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt list_of_identifiers ';'
|
||||||
{ pform_set_port_type(@2, $6, $4, $3, $2, $1); }
|
{ pform_set_port_type(@2, $6, $4, $3, $2, $1); }
|
||||||
|
|
||||||
/* The next two rules handle Verilog 2001 statements of the form:
|
/* The next two rules handle Verilog 2001 statements of the form:
|
||||||
input wire signed [h:l] <list>;
|
input wire signed [h:l] <list>;
|
||||||
This creates the wire and sets the port type all at once. */
|
This creates the wire and sets the port type all at once. */
|
||||||
|
|
||||||
| attribute_list_opt port_direction net_type unsigned_signed_opt range_opt list_of_identifiers ';'
|
| attribute_list_opt port_direction net_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
|
||||||
{ pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); }
|
{ pform_makewire(@2, $5, $4, $6, $3, $2, IVL_VT_NO_TYPE, $1, SR_BOTH); }
|
||||||
|
|
||||||
| attribute_list_opt K_output var_type unsigned_signed_opt range_opt list_of_port_identifiers ';'
|
| attribute_list_opt K_output var_type unsigned_signed_opt dimensions_opt list_of_port_identifiers ';'
|
||||||
{ list<pair<perm_string,PExpr*> >::const_iterator pp;
|
{ list<pair<perm_string,PExpr*> >::const_iterator pp;
|
||||||
list<perm_string>*tmp = new list<perm_string>;
|
list<perm_string>*tmp = new list<perm_string>;
|
||||||
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
|
for (pp = $6->begin(); pp != $6->end(); ++ pp ) {
|
||||||
|
|
@ -4324,19 +4345,19 @@ module_item
|
||||||
because the port declaration implies an external driver, which
|
because the port declaration implies an external driver, which
|
||||||
cannot be attached to a reg. These rules catch that error early. */
|
cannot be attached to a reg. These rules catch that error early. */
|
||||||
|
|
||||||
| attribute_list_opt K_input var_type unsigned_signed_opt range_opt list_of_identifiers ';'
|
| attribute_list_opt K_input var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
|
||||||
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT,
|
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINPUT,
|
||||||
IVL_VT_NO_TYPE, $1);
|
IVL_VT_NO_TYPE, $1);
|
||||||
yyerror(@3, "error: reg variables cannot be inputs.");
|
yyerror(@3, "error: reg variables cannot be inputs.");
|
||||||
}
|
}
|
||||||
|
|
||||||
| attribute_list_opt K_inout var_type unsigned_signed_opt range_opt list_of_identifiers ';'
|
| attribute_list_opt K_inout var_type unsigned_signed_opt dimensions_opt list_of_identifiers ';'
|
||||||
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT,
|
{ pform_makewire(@2, $5, $4, $6, $3, NetNet::PINOUT,
|
||||||
IVL_VT_NO_TYPE, $1);
|
IVL_VT_NO_TYPE, $1);
|
||||||
yyerror(@3, "error: reg variables cannot be inouts.");
|
yyerror(@3, "error: reg variables cannot be inouts.");
|
||||||
}
|
}
|
||||||
|
|
||||||
| attribute_list_opt port_direction unsigned_signed_opt range_opt delay3_opt error ';'
|
| attribute_list_opt port_direction unsigned_signed_opt dimensions_opt delay3_opt error ';'
|
||||||
{ yyerror(@2, "error: Invalid variable list in port declaration.");
|
{ yyerror(@2, "error: Invalid variable list in port declaration.");
|
||||||
if ($1) delete $1;
|
if ($1) delete $1;
|
||||||
if ($4) delete $4;
|
if ($4) delete $4;
|
||||||
|
|
@ -4720,7 +4741,7 @@ var_type
|
||||||
;
|
;
|
||||||
|
|
||||||
param_type
|
param_type
|
||||||
: bit_logic_opt unsigned_signed_opt range_opt
|
: bit_logic_opt unsigned_signed_opt dimensions_opt
|
||||||
{ param_active_range = $3;
|
{ param_active_range = $3;
|
||||||
param_active_signed = $2;
|
param_active_signed = $2;
|
||||||
if (($1 == IVL_VT_NO_TYPE) && ($3 != 0))
|
if (($1 == IVL_VT_NO_TYPE) && ($3 != 0))
|
||||||
|
|
@ -5112,24 +5133,6 @@ port_reference_list
|
||||||
;
|
;
|
||||||
|
|
||||||
/* The range is a list of variable dimensions. */
|
/* The range is a list of variable dimensions. */
|
||||||
range
|
|
||||||
: variable_dimension
|
|
||||||
{ $$ = $1; }
|
|
||||||
| range variable_dimension
|
|
||||||
{ list<pform_range_t>*tmp = $1;
|
|
||||||
if ($2) {
|
|
||||||
tmp->splice(tmp->end(), *$2);
|
|
||||||
delete $2;
|
|
||||||
}
|
|
||||||
$$ = tmp;
|
|
||||||
}
|
|
||||||
;
|
|
||||||
|
|
||||||
range_opt
|
|
||||||
: range
|
|
||||||
| { $$ = 0; }
|
|
||||||
;
|
|
||||||
|
|
||||||
dimensions_opt
|
dimensions_opt
|
||||||
: { $$ = 0; }
|
: { $$ = 0; }
|
||||||
| dimensions { $$ = $1; }
|
| dimensions { $$ = $1; }
|
||||||
|
|
@ -5479,7 +5482,7 @@ specparam_list
|
||||||
|
|
||||||
specparam_decl
|
specparam_decl
|
||||||
: specparam_list
|
: specparam_list
|
||||||
| range
|
| dimensions
|
||||||
{ param_active_range = $1; }
|
{ param_active_range = $1; }
|
||||||
specparam_list
|
specparam_list
|
||||||
{ param_active_range = 0; }
|
{ param_active_range = 0; }
|
||||||
|
|
|
||||||
130
synth2.cc
130
synth2.cc
|
|
@ -28,14 +28,14 @@
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
bool NetProc::synth_async(Design*, NetScope*, const NexusSet&, NetBus&)
|
bool NetProc::synth_async(Design*, NetScope*, NexusSet&, NetBus&, NetBus&)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetProc::synth_sync(Design*des, NetScope*scope,
|
bool NetProc::synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet* /* ff_clk */, NetNet* /* ff_ce */,
|
NetNet* /* ff_clk */, NetNet* /* ff_ce */,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const vector<NetEvProbe*>&events)
|
const vector<NetEvProbe*>&events)
|
||||||
{
|
{
|
||||||
if (events.size() > 0) {
|
if (events.size() > 0) {
|
||||||
|
|
@ -45,7 +45,8 @@ bool NetProc::synth_sync(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Synthesize the input to the DFF. */
|
/* Synthesize the input to the DFF. */
|
||||||
return synth_async(des, scope, nex_map, nex_out);
|
NetBus accumulated_nex_out (scope, nex_out.pin_count());
|
||||||
|
return synth_async(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -60,7 +61,8 @@ bool NetProc::synth_sync(Design*des, NetScope*scope,
|
||||||
* r-value.
|
* r-value.
|
||||||
*/
|
*/
|
||||||
bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out)
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&)
|
||||||
{
|
{
|
||||||
NetNet*rsig = rval_->synthesize(des, scope, rval_);
|
NetNet*rsig = rval_->synthesize(des, scope, rval_);
|
||||||
assert(rsig);
|
assert(rsig);
|
||||||
|
|
@ -138,7 +140,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||||
* substatements.
|
* substatements.
|
||||||
*/
|
*/
|
||||||
bool NetBlock::synth_async(Design*des, NetScope*scope,
|
bool NetBlock::synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out)
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out)
|
||||||
{
|
{
|
||||||
if (last_ == 0) {
|
if (last_ == 0) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -158,30 +161,48 @@ bool NetBlock::synth_async(Design*des, NetScope*scope,
|
||||||
output from the synthesis. */
|
output from the synthesis. */
|
||||||
NetBus tmp_out (scope, tmp_map.size());
|
NetBus tmp_out (scope, tmp_map.size());
|
||||||
|
|
||||||
bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out);
|
// Map (and move) the accumulated_nex_out for this block
|
||||||
|
// to the version that we can pass to the next
|
||||||
|
// statement. We will move the result back later.
|
||||||
|
NetBus accumulated_tmp_out (scope, tmp_map.size());
|
||||||
|
|
||||||
|
for (unsigned idx = 0 ; idx < accumulated_nex_out.pin_count() ; idx += 1) {
|
||||||
|
unsigned ptr = tmp_map.find_nexus(nex_map[idx]);
|
||||||
|
if (ptr >= tmp_map.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
connect(accumulated_tmp_out.pin(ptr), accumulated_nex_out.pin(idx));
|
||||||
|
accumulated_nex_out.pin(idx).unlink();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok_flag = cur->synth_async(des, scope, tmp_map, tmp_out, accumulated_tmp_out);
|
||||||
|
|
||||||
flag = flag && ok_flag;
|
flag = flag && ok_flag;
|
||||||
if (ok_flag == false)
|
if (ok_flag == false)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Now find the tmp_map pins in the nex_map global map,
|
// Now map the output from the substatement back to the
|
||||||
and use that to direct the connection to the nex_out
|
// accumulated_nex_out for this block. Look for the
|
||||||
output bus. Look for the nex_map pin that is linked
|
// nex_map pin that is linked to the tmp_map.pin(idx)
|
||||||
to the tmp_map.pin(idx) pin, and link that to the
|
// 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 = nex_map.find_nexus(tmp_map[idx]);
|
unsigned ptr = nex_map.find_nexus(tmp_map[idx]);
|
||||||
ivl_assert(*this, ptr < nex_out.pin_count());
|
ivl_assert(*this, ptr < accumulated_nex_out.pin_count());
|
||||||
connect(nex_out.pin(ptr), tmp_out.pin(idx));
|
connect(accumulated_nex_out.pin(ptr), tmp_out.pin(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (cur != last_);
|
} while (cur != last_);
|
||||||
|
|
||||||
|
// The output from the block is now the accumulated outputs.
|
||||||
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1)
|
||||||
|
connect(nex_out.pin(idx), accumulated_nex_out.pin(idx));
|
||||||
|
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetCase::synth_async(Design*des, NetScope*scope,
|
bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out)
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&)
|
||||||
{
|
{
|
||||||
/* Synthesize the select expression. */
|
/* Synthesize the select expression. */
|
||||||
NetNet*esig = expr_->synthesize(des, scope, expr_);
|
NetNet*esig = expr_->synthesize(des, scope, expr_);
|
||||||
|
|
@ -248,7 +269,8 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
|
|
||||||
if (statement_default) {
|
if (statement_default) {
|
||||||
|
|
||||||
statement_default->synth_async(des, scope, nex_map, default_bus);
|
NetBus tmp (scope, nex_out.pin_count());
|
||||||
|
statement_default->synth_async(des, scope, nex_map, default_bus, tmp);
|
||||||
|
|
||||||
// Get the signal from the synthesized statement. This
|
// Get the signal from the synthesized statement. This
|
||||||
// will be hooked to all the default cases.
|
// will be hooked to all the default cases.
|
||||||
|
|
@ -304,7 +326,8 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
NetBus tmp (scope, nex_map.size());
|
NetBus tmp (scope, nex_map.size());
|
||||||
stmt->synth_async(des, scope, nex_map, tmp);
|
NetBus accumulated_tmp (scope, nex_map.size());
|
||||||
|
stmt->synth_async(des, scope, nex_map, tmp, accumulated_tmp);
|
||||||
|
|
||||||
ivl_assert(*this, tmp.pin_count() == mux.size());
|
ivl_assert(*this, tmp.pin_count() == mux.size());
|
||||||
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) {
|
for (size_t mdx = 0 ; mdx < mux.size() ; mdx += 1) {
|
||||||
|
|
@ -329,20 +352,34 @@ bool NetCase::synth_async(Design*des, NetScope*scope,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A condit statement (if (cond) ... else ... ;) infers an A-B mux,
|
||||||
|
* with the cond expression acting as a select input. If the cond
|
||||||
|
* expression is true, the if_ clause is selected, and if false, the
|
||||||
|
* else_ clause is selected.
|
||||||
|
*/
|
||||||
bool NetCondit::synth_async(Design*des, NetScope*scope,
|
bool NetCondit::synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out)
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out)
|
||||||
{
|
{
|
||||||
if (if_ == 0) {
|
if (if_ == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (else_ == 0) {
|
if (else_ == 0) {
|
||||||
cerr << get_fileline() << ": error: Asynchronous if statement"
|
bool latch_flag = false;
|
||||||
<< " is missing the else clause." << endl;
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
|
||||||
return false;
|
if (! accumulated_nex_out.pin(idx).is_linked())
|
||||||
|
latch_flag = true;
|
||||||
|
}
|
||||||
|
if (latch_flag) {
|
||||||
|
cerr << get_fileline() << ": error: Asynchronous if statement"
|
||||||
|
<< " cannot synthesize missing \"else\""
|
||||||
|
<< " without generating latches." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(if_ != 0);
|
ivl_assert(*this, if_ != 0);
|
||||||
assert(else_ != 0);
|
|
||||||
|
|
||||||
// Synthesize the condition. This will act as a select signal
|
// Synthesize the condition. This will act as a select signal
|
||||||
// for a binary mux.
|
// for a binary mux.
|
||||||
|
|
@ -351,15 +388,25 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
|
||||||
|
|
||||||
bool flag;
|
bool flag;
|
||||||
NetBus asig(scope, nex_out.pin_count());
|
NetBus asig(scope, nex_out.pin_count());
|
||||||
flag = if_->synth_async(des, scope, nex_map, asig);
|
NetBus atmp(scope, nex_out.pin_count());
|
||||||
|
flag = if_->synth_async(des, scope, nex_map, asig, atmp);
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetBus btmp(scope, nex_out.pin_count());
|
||||||
NetBus bsig(scope, nex_out.pin_count());
|
NetBus bsig(scope, nex_out.pin_count());
|
||||||
flag = else_->synth_async(des, scope, nex_map, bsig);
|
|
||||||
if (!flag) {
|
if (else_==0) {
|
||||||
return false;
|
for (unsigned idx = 0 ; idx < nex_out.pin_count() ; idx += 1) {
|
||||||
|
connect(bsig.pin(idx), accumulated_nex_out.pin(idx));
|
||||||
|
accumulated_nex_out.pin(idx).unlink();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
flag = else_->synth_async(des, scope, nex_map, bsig, btmp);
|
||||||
|
if (!flag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ivl_assert(*this, nex_out.pin_count()==asig.pin_count());
|
ivl_assert(*this, nex_out.pin_count()==asig.pin_count());
|
||||||
|
|
@ -405,9 +452,10 @@ bool NetCondit::synth_async(Design*des, NetScope*scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetEvWait::synth_async(Design*des, NetScope*scope,
|
bool NetEvWait::synth_async(Design*des, NetScope*scope,
|
||||||
const NexusSet&nex_map, NetBus&nex_out)
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
|
NetBus&accumulated_nex_out)
|
||||||
{
|
{
|
||||||
bool flag = statement_->synth_async(des, scope, nex_map, nex_out);
|
bool flag = statement_->synth_async(des, scope, nex_map, nex_out, accumulated_nex_out);
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -431,11 +479,11 @@ bool NetProcTop::synth_async(Design*des)
|
||||||
|
|
||||||
NetBus nex_q (scope(), nex_set.size());
|
NetBus nex_q (scope(), nex_set.size());
|
||||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||||
const NexusSet::elem_t&item = nex_set[idx];
|
NexusSet::elem_t&item = nex_set[idx];
|
||||||
if (item.base != 0 || item.wid!=item.nex->vector_width()) {
|
if (item.base != 0 || item.wid!=item.lnk.nexus()->vector_width()) {
|
||||||
ivl_variable_type_t tmp_data_type = IVL_VT_LOGIC;
|
ivl_variable_type_t tmp_data_type = IVL_VT_LOGIC;
|
||||||
list<netrange_t>not_an_array;
|
list<netrange_t>not_an_array;
|
||||||
netvector_t*tmp_type = new netvector_t(tmp_data_type, item.nex->vector_width()-1,0);
|
netvector_t*tmp_type = new netvector_t(tmp_data_type, item.lnk.nexus()->vector_width()-1,0);
|
||||||
NetNet*tmp_sig = new NetNet(scope(), scope()->local_symbol(),
|
NetNet*tmp_sig = new NetNet(scope(), scope()->local_symbol(),
|
||||||
NetNet::WIRE, not_an_array, tmp_type);
|
NetNet::WIRE, not_an_array, tmp_type);
|
||||||
tmp_sig->local_flag(true);
|
tmp_sig->local_flag(true);
|
||||||
|
|
@ -445,14 +493,15 @@ bool NetProcTop::synth_async(Design*des)
|
||||||
des->add_node(tmp);
|
des->add_node(tmp);
|
||||||
tmp->set_line(*this);
|
tmp->set_line(*this);
|
||||||
connect(tmp->pin(0), nex_q.pin(idx));
|
connect(tmp->pin(0), nex_q.pin(idx));
|
||||||
connect(item.nex, tmp_sig->pin(0));
|
connect(item.lnk, tmp_sig->pin(0));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
connect(item.nex, nex_q.pin(idx));
|
connect(item.lnk, nex_q.pin(idx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flag = statement_->synth_async(des, scope(), nex_set, nex_q);
|
NetBus tmp_q (scope(), nex_set.size());
|
||||||
|
bool flag = statement_->synth_async(des, scope(), nex_set, nex_q, tmp_q);
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -472,7 +521,7 @@ bool NetProcTop::synth_async(Design*des)
|
||||||
*/
|
*/
|
||||||
bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const vector<NetEvProbe*>&events_in)
|
const vector<NetEvProbe*>&events_in)
|
||||||
{
|
{
|
||||||
bool flag = true;
|
bool flag = true;
|
||||||
|
|
@ -531,7 +580,7 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||||
*/
|
*/
|
||||||
bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const vector<NetEvProbe*>&events_in)
|
const vector<NetEvProbe*>&events_in)
|
||||||
{
|
{
|
||||||
/* First try to turn the condition expression into an
|
/* First try to turn the condition expression into an
|
||||||
|
|
@ -689,7 +738,8 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||||
/* If this is an if/then/else, then it is likely a
|
/* If this is an if/then/else, then it is likely a
|
||||||
combinational if, and I should synthesize it that way. */
|
combinational if, and I should synthesize it that way. */
|
||||||
if (if_ && else_) {
|
if (if_ && else_) {
|
||||||
bool flag = synth_async(des, scope, nex_map, nex_out);
|
NetBus tmp (scope, nex_out.pin_count());
|
||||||
|
bool flag = synth_async(des, scope, nex_map, nex_out, tmp);
|
||||||
return flag;
|
return flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -740,7 +790,7 @@ bool NetCondit::synth_sync(Design*des, NetScope*scope,
|
||||||
|
|
||||||
bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
bool NetEvWait::synth_sync(Design*des, NetScope*scope,
|
||||||
NetNet*ff_clk, NetNet*ff_ce,
|
NetNet*ff_clk, NetNet*ff_ce,
|
||||||
const NexusSet&nex_map, NetBus&nex_out,
|
NexusSet&nex_map, NetBus&nex_out,
|
||||||
const vector<NetEvProbe*>&events_in)
|
const vector<NetEvProbe*>&events_in)
|
||||||
{
|
{
|
||||||
if (events_in.size() > 0) {
|
if (events_in.size() > 0) {
|
||||||
|
|
@ -853,7 +903,7 @@ bool NetProcTop::synth_sync(Design*des)
|
||||||
pass the nex_q as a map to the statement's synth_sync
|
pass the nex_q as a map to the statement's synth_sync
|
||||||
method to map it to the correct nex_d pin. */
|
method to map it to the correct nex_d pin. */
|
||||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||||
connect(nex_set[idx].nex, nex_q.pin(idx));
|
connect(nex_set[idx].lnk, nex_q.pin(idx));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect the input later.
|
// Connect the input later.
|
||||||
|
|
@ -869,7 +919,7 @@ bool NetProcTop::synth_sync(Design*des)
|
||||||
|
|
||||||
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
for (unsigned idx = 0 ; idx < nex_set.size() ; idx += 1) {
|
||||||
|
|
||||||
ivl_assert(*this, nex_set[idx].nex);
|
//ivl_assert(*this, nex_set[idx].nex);
|
||||||
if (debug_synth2) {
|
if (debug_synth2) {
|
||||||
cerr << get_fileline() << ": debug: "
|
cerr << get_fileline() << ": debug: "
|
||||||
<< "Top level making a "
|
<< "Top level making a "
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,21 @@ static void scans_lpms_add(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&s
|
||||||
stats.gate_count += 2*wid;
|
stats.gate_count += 2*wid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Count mux devices as 2m gates.
|
||||||
|
*/
|
||||||
|
static void scan_lpms_mux(ivl_scope_t, ivl_lpm_t lpm, struct sizer_statistics&stats)
|
||||||
|
{
|
||||||
|
// For now, don't generate statistics for wide mux devices.
|
||||||
|
if (ivl_lpm_size(lpm) > 2) {
|
||||||
|
stats.lpm_bytype[ivl_lpm_type(lpm)] += 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned wid = ivl_lpm_width(lpm);
|
||||||
|
stats.gate_count += 2*wid;
|
||||||
|
}
|
||||||
|
|
||||||
void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
|
void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
|
||||||
{
|
{
|
||||||
for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) {
|
for (unsigned idx = 0 ; idx < ivl_scope_lpms(scope) ; idx += 1) {
|
||||||
|
|
@ -70,6 +85,10 @@ void scan_lpms(ivl_scope_t scope, struct sizer_statistics&stats)
|
||||||
scan_lpms_ff(scope, lpm, stats);
|
scan_lpms_ff(scope, lpm, stats);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IVL_LPM_MUX:
|
||||||
|
scan_lpms_mux(scope, lpm, stats);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
stats.lpm_bytype[ivl_lpm_type(lpm)] += 1;
|
stats.lpm_bytype[ivl_lpm_type(lpm)] += 1;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,15 @@ int target_design(ivl_design_t des)
|
||||||
*/
|
*/
|
||||||
static int process_scan_fun(ivl_process_t net, void* /*raw*/)
|
static int process_scan_fun(ivl_process_t net, void* /*raw*/)
|
||||||
{
|
{
|
||||||
|
for (unsigned idx = 0 ; idx < ivl_process_attr_cnt(net) ; idx += 1) {
|
||||||
|
ivl_attribute_t att = ivl_process_attr_val(net, idx);
|
||||||
|
|
||||||
|
// If synthesis is explicitly turned off for this
|
||||||
|
// process, then we just ignore it.
|
||||||
|
if (strcmp(att->key, "ivl_synthesis_off") == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s:%u: SIZER: Processes not synthesized for statistics.\n",
|
fprintf(stderr, "%s:%u: SIZER: Processes not synthesized for statistics.\n",
|
||||||
ivl_process_file(net), ivl_process_lineno(net));
|
ivl_process_file(net), ivl_process_lineno(net));
|
||||||
sizer_errors += 1;
|
sizer_errors += 1;
|
||||||
|
|
@ -124,6 +133,7 @@ static int process_scan_fun(ivl_process_t net, void* /*raw*/)
|
||||||
|
|
||||||
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t scope, struct sizer_statistics&stats)
|
static void emit_sizer_scope(ivl_design_t des, ivl_scope_t scope, struct sizer_statistics&stats)
|
||||||
{
|
{
|
||||||
|
|
||||||
fprintf(sizer_out, "**** module/scope: %s\n", ivl_scope_name(scope));
|
fprintf(sizer_out, "**** module/scope: %s\n", ivl_scope_name(scope));
|
||||||
|
|
||||||
scan_logs(scope, stats);
|
scan_logs(scope, stats);
|
||||||
|
|
|
||||||
106
verinum.cc
106
verinum.cc
|
|
@ -344,9 +344,11 @@ verinum::~verinum()
|
||||||
verinum& verinum::operator= (const verinum&that)
|
verinum& verinum::operator= (const verinum&that)
|
||||||
{
|
{
|
||||||
if (this == &that) return *this;
|
if (this == &that) return *this;
|
||||||
delete[]bits_;
|
if (nbits_ != that.nbits_) {
|
||||||
nbits_ = that.nbits_;
|
delete[]bits_;
|
||||||
bits_ = new V[that.nbits_];
|
nbits_ = that.nbits_;
|
||||||
|
bits_ = new V[that.nbits_];
|
||||||
|
}
|
||||||
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
|
for (unsigned idx = 0 ; idx < nbits_ ; idx += 1)
|
||||||
bits_[idx] = that.bits_[idx];
|
bits_[idx] = that.bits_[idx];
|
||||||
|
|
||||||
|
|
@ -1126,53 +1128,95 @@ verinum operator * (const verinum&left, const verinum&right)
|
||||||
return trim_vnum(result);
|
return trim_vnum(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static verinum make_p_one(unsigned len, bool has_len, bool has_sign)
|
||||||
|
{
|
||||||
|
verinum tmp (verinum::V0, has_len ? len : 2, has_len);
|
||||||
|
tmp.set(0, verinum::V1);
|
||||||
|
tmp.has_sign(has_sign);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static verinum make_m_one(unsigned len, bool has_len, bool has_sign)
|
||||||
|
{
|
||||||
|
verinum tmp (verinum::V1, has_len ? len : 1, has_len);
|
||||||
|
tmp.has_sign(has_sign);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static verinum recursive_pow(const verinum&left, verinum&right)
|
||||||
|
{
|
||||||
|
// If the exponent is zero, return a value of 1
|
||||||
|
if (right.is_zero()) {
|
||||||
|
return make_p_one(left.len(), left.has_len(), left.has_sign());
|
||||||
|
}
|
||||||
|
|
||||||
|
verinum res;
|
||||||
|
if (right.get(0) == 1) {
|
||||||
|
// The exponent is odd, so subtract 1 from it and recurse
|
||||||
|
right.set(0, verinum::V0);
|
||||||
|
res = pow(left, right);
|
||||||
|
res = left * res;
|
||||||
|
} else {
|
||||||
|
// The exponent is even, so divide it by 2 and recurse
|
||||||
|
right = right >> 1;
|
||||||
|
res = pow(left, right);
|
||||||
|
res = res * res;
|
||||||
|
}
|
||||||
|
if (left.has_len()) {
|
||||||
|
res = verinum(res, left.len());
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
verinum pow(const verinum&left, const verinum&right)
|
verinum pow(const verinum&left, const verinum&right)
|
||||||
{
|
{
|
||||||
verinum result = left;
|
verinum result;
|
||||||
long pow_count = right.as_long();
|
|
||||||
|
|
||||||
// We need positive and negative one in a few places.
|
// We need positive and negative one in a few places.
|
||||||
unsigned len = left.len();
|
verinum p_one = make_p_one(left.len(), left.has_len(), left.has_sign());
|
||||||
// Positive one must be at least two bits wide!
|
verinum m_one = make_m_one(left.len(), left.has_len(), left.has_sign());
|
||||||
verinum one (verinum::V0, (len<2) ? 2 : len, left.has_len());
|
|
||||||
one.has_sign(left.has_sign());
|
|
||||||
one.set(0, verinum::V1);
|
|
||||||
verinum m_one (verinum::V1, len, left.has_len());
|
|
||||||
m_one.has_sign(true);
|
|
||||||
|
|
||||||
// If either the right or left values are undefined we return 'bx.
|
// If either the right or left values are undefined we return 'bx.
|
||||||
if (!right.is_defined() || !left.is_defined()) {
|
if (!right.is_defined() || !left.is_defined()) {
|
||||||
result = verinum(verinum::Vx, len, left.has_len());
|
result = verinum(verinum::Vx, left.len(), left.has_len());
|
||||||
result.has_sign(left.has_sign());
|
result.has_sign(left.has_sign());
|
||||||
|
|
||||||
// If the right value is zero we need to set the result to 1.
|
// If the right value is zero we need to set the result to 1.
|
||||||
} else if (pow_count == 0) {
|
} else if (right.is_zero()) {
|
||||||
result = one;
|
result = p_one;
|
||||||
} else if (pow_count < 0) {
|
|
||||||
|
} else if (right.is_negative()) {
|
||||||
|
|
||||||
// 0 ** <negative> is 'bx.
|
// 0 ** <negative> is 'bx.
|
||||||
if (left.is_zero()) {
|
if (left.is_zero()) {
|
||||||
result = verinum(verinum::Vx, len, left.has_len());
|
result = verinum(verinum::Vx, left.len(), left.has_len());
|
||||||
result.has_sign(left.has_sign());
|
result.has_sign(left.has_sign());
|
||||||
// 1 ** <negative> is 1.
|
|
||||||
} else if (left == one) {
|
// -1 ** <negative> is 1 or -1. Note that this must be done
|
||||||
result = one;
|
// before testing for +1 in case 'left' has a width of 1.
|
||||||
// -1 ** <negative> is 1 or -1.
|
|
||||||
} else if (left.has_sign() && left == m_one) {
|
} else if (left.has_sign() && left == m_one) {
|
||||||
if (pow_count%2 == 0) {
|
if (right.get(0) == verinum::V0) {
|
||||||
result = one;
|
result = p_one;
|
||||||
} else {
|
} else {
|
||||||
result = m_one;
|
result = m_one;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1 ** <negative> is 1.
|
||||||
|
} else if (left == p_one) {
|
||||||
|
result = p_one;
|
||||||
|
|
||||||
// Everything else is 0.
|
// Everything else is 0.
|
||||||
} else {
|
} else {
|
||||||
result = verinum(verinum::V0, len, left.has_len());
|
result = verinum(verinum::V0, left.len(), left.has_len());
|
||||||
result.has_sign(left.has_sign());
|
result.has_sign(left.has_sign());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
verinum exponent = right;
|
||||||
|
result = recursive_pow(left, exponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (long idx = 1 ; idx < pow_count ; idx += 1)
|
return trim_vnum(result);
|
||||||
result = result * left;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verinum operator << (const verinum&that, unsigned shift)
|
verinum operator << (const verinum&that, unsigned shift)
|
||||||
|
|
|
||||||
16
vvp/arith.cc
16
vvp/arith.cc
|
|
@ -156,13 +156,13 @@ vvp_arith_div::~vvp_arith_div()
|
||||||
|
|
||||||
void vvp_arith_div::wide4_(vvp_net_ptr_t ptr)
|
void vvp_arith_div::wide4_(vvp_net_ptr_t ptr)
|
||||||
{
|
{
|
||||||
vvp_vector2_t a2 (op_a_);
|
vvp_vector2_t a2 (op_a_, true);
|
||||||
if (a2.is_NaN()) {
|
if (a2.is_NaN()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vvp_vector2_t b2 (op_b_);
|
vvp_vector2_t b2 (op_b_, true);
|
||||||
if (b2.is_NaN() || b2.is_zero()) {
|
if (b2.is_NaN() || b2.is_zero()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
return;
|
return;
|
||||||
|
|
@ -270,13 +270,13 @@ vvp_arith_mod::~vvp_arith_mod()
|
||||||
|
|
||||||
void vvp_arith_mod::wide_(vvp_net_ptr_t ptr)
|
void vvp_arith_mod::wide_(vvp_net_ptr_t ptr)
|
||||||
{
|
{
|
||||||
vvp_vector2_t a2 (op_a_);
|
vvp_vector2_t a2 (op_a_, true);
|
||||||
if (a2.is_NaN()) {
|
if (a2.is_NaN()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vvp_vector2_t b2 (op_b_);
|
vvp_vector2_t b2 (op_b_, true);
|
||||||
if (b2.is_NaN() || b2.is_zero()) {
|
if (b2.is_NaN() || b2.is_zero()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
return;
|
return;
|
||||||
|
|
@ -384,8 +384,8 @@ vvp_arith_mult::~vvp_arith_mult()
|
||||||
|
|
||||||
void vvp_arith_mult::wide_(vvp_net_ptr_t ptr)
|
void vvp_arith_mult::wide_(vvp_net_ptr_t ptr)
|
||||||
{
|
{
|
||||||
vvp_vector2_t a2 (op_a_);
|
vvp_vector2_t a2 (op_a_, true);
|
||||||
vvp_vector2_t b2 (op_b_);
|
vvp_vector2_t b2 (op_b_, true);
|
||||||
|
|
||||||
if (a2.is_NaN() || b2.is_NaN()) {
|
if (a2.is_NaN() || b2.is_NaN()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
|
|
@ -469,8 +469,8 @@ void vvp_arith_pow::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit,
|
||||||
|
|
||||||
res4 = vvp_vector4_t(wid_, resd);
|
res4 = vvp_vector4_t(wid_, resd);
|
||||||
} else {
|
} else {
|
||||||
vvp_vector2_t a2 (op_a_);
|
vvp_vector2_t a2 (op_a_, true);
|
||||||
vvp_vector2_t b2 (op_b_);
|
vvp_vector2_t b2 (op_b_, true);
|
||||||
|
|
||||||
if (a2.is_NaN() || b2.is_NaN()) {
|
if (a2.is_NaN() || b2.is_NaN()) {
|
||||||
ptr.ptr()->send_vec4(x_val_, 0);
|
ptr.ptr()->send_vec4(x_val_, 0);
|
||||||
|
|
|
||||||
|
|
@ -5068,6 +5068,7 @@ bool of_POW(vthread_t thr, vvp_code_t)
|
||||||
vvp_vector2_t xv2 = vvp_vector2_t(vala);
|
vvp_vector2_t xv2 = vvp_vector2_t(vala);
|
||||||
vvp_vector2_t yv2 = vvp_vector2_t(valb);
|
vvp_vector2_t yv2 = vvp_vector2_t(valb);
|
||||||
|
|
||||||
|
|
||||||
/* If we have an X or Z in the arguments return X. */
|
/* If we have an X or Z in the arguments return X. */
|
||||||
if (xv2.is_NaN() || yv2.is_NaN()) {
|
if (xv2.is_NaN() || yv2.is_NaN()) {
|
||||||
vvp_vector4_t tmp (wid, BIT4_X);
|
vvp_vector4_t tmp (wid, BIT4_X);
|
||||||
|
|
@ -5075,10 +5076,6 @@ bool of_POW(vthread_t thr, vvp_code_t)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To make the result more manageable trim off the extra bits. */
|
|
||||||
xv2.trim();
|
|
||||||
yv2.trim();
|
|
||||||
|
|
||||||
vvp_vector2_t result = pow(xv2, yv2);
|
vvp_vector2_t result = pow(xv2, yv2);
|
||||||
|
|
||||||
/* Copy only what we need of the result. If the result is too
|
/* Copy only what we need of the result. If the result is too
|
||||||
|
|
|
||||||
|
|
@ -2362,23 +2362,21 @@ bool vvp_vector2_t::is_zero() const
|
||||||
*/
|
*/
|
||||||
vvp_vector2_t pow(const vvp_vector2_t&x, vvp_vector2_t&y)
|
vvp_vector2_t pow(const vvp_vector2_t&x, vvp_vector2_t&y)
|
||||||
{
|
{
|
||||||
/* If we have a zero exponent just return a 1 bit wide 1. */
|
/* If we have a zero exponent just return 1. */
|
||||||
if (y == vvp_vector2_t(0L, 1)) {
|
if (y == vvp_vector2_t(0L, 1)) {
|
||||||
return vvp_vector2_t(1L, 1);
|
return vvp_vector2_t(1L, x.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Is the value odd? */
|
/* Is the value odd? */
|
||||||
if (y.value(0) == 1) {
|
if (y.value(0) == 1) {
|
||||||
y.set_bit(0, 0); // A quick subtract by 1.
|
y.set_bit(0, 0); // A quick subtract by 1.
|
||||||
vvp_vector2_t res = x * pow(x, y);
|
vvp_vector2_t res = x * pow(x, y);
|
||||||
res.trim(); // To keep the size under control trim extra zeros.
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
y >>= 1; // A fast divide by two. We know the LSB is zero.
|
y >>= 1; // A fast divide by two. We know the LSB is zero.
|
||||||
vvp_vector2_t z = pow(x, y);
|
vvp_vector2_t z = pow(x, y);
|
||||||
vvp_vector2_t res = z * z;
|
vvp_vector2_t res = z * z;
|
||||||
res.trim(); // To keep the size under control trim extra zeros.
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2422,25 +2420,22 @@ static void multiply_long(unsigned long a, unsigned long b,
|
||||||
low = (res[1] << 4UL*sizeof(unsigned long)) | res[0];
|
low = (res[1] << 4UL*sizeof(unsigned long)) | res[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Multiplication of two vector2 vectors returns a product as wide as
|
|
||||||
* the sum of the widths of the input vectors.
|
|
||||||
*/
|
|
||||||
vvp_vector2_t operator * (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
vvp_vector2_t operator * (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
||||||
{
|
{
|
||||||
const unsigned bits_per_word = 8 * sizeof(a.vec_[0]);
|
const unsigned bits_per_word = 8 * sizeof(a.vec_[0]);
|
||||||
vvp_vector2_t r (0, a.size() + b.size());
|
|
||||||
|
|
||||||
unsigned awords = (a.wid_ + bits_per_word - 1) / bits_per_word;
|
// The compiler ensures that the two operands are of equal size.
|
||||||
unsigned bwords = (b.wid_ + bits_per_word - 1) / bits_per_word;
|
assert(a.size() == b.size());
|
||||||
unsigned rwords = (r.wid_ + bits_per_word - 1) / bits_per_word;
|
vvp_vector2_t r (0, a.size());
|
||||||
|
|
||||||
for (unsigned bdx = 0 ; bdx < bwords ; bdx += 1) {
|
unsigned words = (r.wid_ + bits_per_word - 1) / bits_per_word;
|
||||||
|
|
||||||
|
for (unsigned bdx = 0 ; bdx < words ; bdx += 1) {
|
||||||
unsigned long tmpb = b.vec_[bdx];
|
unsigned long tmpb = b.vec_[bdx];
|
||||||
if (tmpb == 0)
|
if (tmpb == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (unsigned adx = 0 ; adx < awords ; adx += 1) {
|
for (unsigned adx = 0 ; adx < words ; adx += 1) {
|
||||||
unsigned long tmpa = a.vec_[adx];
|
unsigned long tmpa = a.vec_[adx];
|
||||||
if (tmpa == 0)
|
if (tmpa == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2450,7 +2445,7 @@ vvp_vector2_t operator * (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
||||||
|
|
||||||
unsigned long carry = 0;
|
unsigned long carry = 0;
|
||||||
for (unsigned sdx = 0
|
for (unsigned sdx = 0
|
||||||
; (adx+bdx+sdx) < rwords
|
; (adx+bdx+sdx) < words
|
||||||
; sdx += 1) {
|
; sdx += 1) {
|
||||||
|
|
||||||
r.vec_[adx+bdx+sdx] = add_carry(r.vec_[adx+bdx+sdx],
|
r.vec_[adx+bdx+sdx] = add_carry(r.vec_[adx+bdx+sdx],
|
||||||
|
|
@ -2461,7 +2456,6 @@ vvp_vector2_t operator * (const vvp_vector2_t&a, const vvp_vector2_t&b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -619,9 +619,11 @@ class vvp_vector2_t {
|
||||||
vvp_vector2_t(const vvp_vector2_t&);
|
vvp_vector2_t(const vvp_vector2_t&);
|
||||||
vvp_vector2_t(const vvp_vector2_t&, unsigned newsize);
|
vvp_vector2_t(const vvp_vector2_t&, unsigned newsize);
|
||||||
vvp_vector2_t(const vvp_vector2_t&, unsigned base, unsigned wid);
|
vvp_vector2_t(const vvp_vector2_t&, unsigned base, unsigned wid);
|
||||||
// Make a vvp_vector2_t from a vvp_vector4_t. If there are X
|
// Make a vvp_vector2_t from a vvp_vector4_t. If enable_NaN
|
||||||
// or Z bits, then the result becomes a NaN value.
|
// is true and there are X or Z bits, then the result becomes
|
||||||
vvp_vector2_t(const vvp_vector4_t&that);
|
// a NaN value. If enable_NaN is false then X or Z bits are
|
||||||
|
// converted to 0 as per the standard Verilog rules.
|
||||||
|
vvp_vector2_t(const vvp_vector4_t&that, bool allow_NaN = false);
|
||||||
// Make from a native long and a specified width.
|
// Make from a native long and a specified width.
|
||||||
vvp_vector2_t(unsigned long val, unsigned wid);
|
vvp_vector2_t(unsigned long val, unsigned wid);
|
||||||
// Make with the width, and filled with 1 or 0 bits.
|
// Make with the width, and filled with 1 or 0 bits.
|
||||||
|
|
@ -693,8 +695,13 @@ inline vvp_vector2_t::vvp_vector2_t(const vvp_vector2_t&that)
|
||||||
copy_from_that_(that);
|
copy_from_that_(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that)
|
inline vvp_vector2_t::vvp_vector2_t(const vvp_vector4_t&that, bool enable_NaN)
|
||||||
{
|
{
|
||||||
|
if (enable_NaN && that.has_xz()) {
|
||||||
|
vec_ = 0;
|
||||||
|
wid_ = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
copy_from_that_(that);
|
copy_from_that_(that);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue