diff --git a/cprop.cc b/cprop.cc index 9345b9ea8..56e3a7bf7 100644 --- a/cprop.cc +++ b/cprop.cc @@ -897,7 +897,7 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - NetObj*cur; + NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); @@ -923,7 +923,7 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) for (Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - NetObj*cur; + NetPins*cur; unsigned pin; clnk->cur_link(cur, pin); diff --git a/design_dump.cc b/design_dump.cc index 98378628f..17c0af847 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -188,6 +188,10 @@ void NetNet::dump_net(ostream&o, unsigned ind) const o << " inout"; break; } + + if (discipline_t*dis = get_discipline()) + o << " discipline=" << dis->name(); + o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); @@ -237,7 +241,7 @@ void NetNode::dump_node(ostream&o, unsigned ind) const /* This is the generic dumping of all the signals connected to each pin of the object. The "this" object is not printed, only the signals connected to this. */ -void NetObj::dump_node_pins(ostream&o, unsigned ind) const +void NetPins::dump_node_pins(ostream&o, unsigned ind) const { for (unsigned idx = 0 ; idx < pin_count() ; idx += 1) { o << setw(ind) << "" << idx << " " << pin(idx).get_name() @@ -1186,6 +1190,12 @@ void NetExpr::dump(ostream&o) const void NetEAccess::dump(ostream&o) const { o << nature_->name() << "." << nature_->access() << "("; + assert(branch_); + if (branch_->pin(0).is_linked()) + o << branch_->pin(0).nexus()->name(); + o << ", "; + if (branch_->pin(1).is_linked()) + o << branch_->pin(1).nexus()->name(); o << ")"; } diff --git a/dup_expr.cc b/dup_expr.cc index 96a721543..ad4bb7b0a 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -25,7 +25,7 @@ NetEAccess* NetEAccess::dup_expr() const { - NetEAccess*tmp = new NetEAccess(nature_); + NetEAccess*tmp = new NetEAccess(branch_, nature_); ivl_assert(*this, tmp); tmp->set_line(*this); return tmp; diff --git a/elab_expr.cc b/elab_expr.cc index 9f3cc228b..b4160e5d8 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -616,7 +616,36 @@ NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope, if (nature == 0) return 0; - NetEAccess*tmp = new NetEAccess(nature); + // An access function must have 1 or 2 arguments. + ivl_assert(*this, parms_.size()==2 || parms_.size()==1); + + NetBranch*branch = 0; + + if (parms_.size() == 1) { + PExpr*arg1 = parms_[0]; + PEIdent*arg_ident = dynamic_cast (arg1); + ivl_assert(*this, arg_ident); + + const pform_name_t&path = arg_ident->path(); + ivl_assert(*this, path.size()==1); + perm_string name = peek_tail_name(path); + + NetNet*sig = scope->find_signal(name); + ivl_assert(*this, sig); + + discipline_t*dis = sig->get_discipline(); + ivl_assert(*this, dis); + ivl_assert(*this, nature == dis->potential() || nature == dis->flow()); + + branch = new NetBranch(dis); + branch->set_line(*this); + connect(branch->pin(0), sig->pin(0)); + + } else { + ivl_assert(*this, 0); + } + + NetEAccess*tmp = new NetEAccess(branch, nature); tmp->set_line(*this); return tmp; diff --git a/elab_sig.cc b/elab_sig.cc index 8faa7f2c9..c01fdd81e 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1029,6 +1029,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const sig->set_signed(get_signed()); sig->set_isint(get_isint()); + if (discipline_t*dis = get_discipline()) { + sig->set_discipline(dis); + } + if (pull) connect(sig->pin(0), pull->pin(0)); diff --git a/ivl_target.h b/ivl_target.h index 7535bd0d4..c019acf04 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -193,6 +193,7 @@ typedef enum ivl_drive_e { typedef enum ivl_expr_type_e { IVL_EX_NONE = 0, IVL_EX_ARRAY = 18, + IVL_EX_BACCESS= 19, IVL_EX_BINARY = 2, IVL_EX_CONCAT = 3, IVL_EX_EVENT = 17, diff --git a/link_const.cc b/link_const.cc index 60b68afa6..212fbf9e7 100644 --- a/link_const.cc +++ b/link_const.cc @@ -60,8 +60,9 @@ bool Nexus::drivers_constant() const if (cur_dir == Link::PASSIVE) { - const NetObj*obj = cur->get_obj(); - if (obj->scope()->parent() != 0) + const NetPins*obj = cur->get_obj(); + const NetObj*as_obj = dynamic_cast(obj); + if (as_obj == 0 || as_obj->scope()->parent() != 0) continue; sig = dynamic_cast(cur->get_obj()); diff --git a/net_event.cc b/net_event.cc index a214cdd48..3535e7ea9 100644 --- a/net_event.cc +++ b/net_event.cc @@ -299,7 +299,7 @@ void NetEvProbe::find_similar_probes(list&plist) Nexus*nex = pin(0).nexus(); for (Link*lcur = nex->first_nlink(); lcur; lcur = lcur->next_nlink()) { - NetObj*obj = lcur->get_obj(); + NetPins*obj = lcur->get_obj(); if (obj->pin_count() != pin_count()) continue; diff --git a/net_expr.cc b/net_expr.cc index 4d3818099..e749cdca1 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -589,8 +589,8 @@ ivl_variable_type_t NetESFunc::expr_type() const return type_; } -NetEAccess::NetEAccess(nature_t*nat) -: nature_(nat) +NetEAccess::NetEAccess(NetBranch*br, nature_t*nat) +: branch_(br), nature_(nat) { } diff --git a/net_link.cc b/net_link.cc index 228add8c0..9b892a152 100644 --- a/net_link.cc +++ b/net_link.cc @@ -134,13 +134,13 @@ verinum::V Link::get_init() const } -void Link::cur_link(NetObj*&net, unsigned &pin) +void Link::cur_link(NetPins*&net, unsigned &pin) { net = node_; pin = pin_; } -void Link::cur_link(const NetObj*&net, unsigned &pin) const +void Link::cur_link(const NetPins*&net, unsigned &pin) const { net = node_; pin = pin_; @@ -186,12 +186,12 @@ const Link* Link::next_nlink() const return next_; } -const NetObj*Link::get_obj() const +const NetPins*Link::get_obj() const { return node_; } -NetObj*Link::get_obj() +NetPins*Link::get_obj() { return node_; } @@ -253,7 +253,10 @@ void Nexus::drivers_delays(NetExpr*rise, NetExpr*fall, NetExpr*decay) if (cur->get_dir() != Link::OUTPUT) continue; - NetObj*obj = cur->get_obj(); + NetObj*obj = dynamic_cast(cur->get_obj()); + if (obj == 0) + continue; + obj->rise_time(rise); obj->fall_time(fall); obj->decay_time(decay); @@ -397,7 +400,7 @@ const char* Nexus::name() const if (sig == 0) { const Link*lnk = first_nlink(); - const NetObj*obj = lnk->get_obj(); + const NetObj*obj = dynamic_cast(lnk->get_obj()); pin = lnk->get_pin(); cerr << "internal error: No signal for nexus of " << obj->name() << " pin " << pin << "(" << diff --git a/net_tran.cc b/net_tran.cc index b28a28753..42b726307 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -100,8 +100,12 @@ void join_island(NetObj*obj) Nexus*nex = obj->pin(idx).nexus(); for (Link*cur = nex->first_nlink() ; cur ; cur = cur->next_nlink()) { unsigned pin; - NetObj*tmp; - cur->cur_link(tmp, pin); + NetPins*tmp_pins; + cur->cur_link(tmp_pins, pin); + + NetObj*tmp = dynamic_cast (tmp_pins); + if (tmp == 0) + continue; // Skip self. if (tmp == obj) diff --git a/netlist.cc b/netlist.cc index 51cf898f6..ece7adf45 100644 --- a/netlist.cc +++ b/netlist.cc @@ -91,7 +91,7 @@ unsigned count_inputs(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (cur->pin(cpin).get_dir() == Link::INPUT) @@ -108,7 +108,7 @@ unsigned count_outputs(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (cur->pin(cpin).get_dir() == Link::OUTPUT) @@ -125,7 +125,7 @@ unsigned count_signals(const Link&pin) const Nexus*nex = pin.nexus(); for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); if (dynamic_cast(cur)) @@ -142,7 +142,7 @@ const NetNet* find_link_signal(const NetObj*net, unsigned pin, unsigned&bidx) for (const Link*clnk = nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { - const NetObj*cur; + const NetPins*cur; unsigned cpin; clnk->cur_link(cur, cpin); @@ -171,8 +171,8 @@ Link* find_next_output(Link*lnk) return 0; } -NetObj::NetObj(NetScope*s, perm_string n, unsigned np) -: scope_(s), name_(n), npins_(np), delay1_(0), delay2_(0), delay3_(0) +NetPins::NetPins(unsigned npins) +: npins_(npins) { pins_ = new Link[npins_]; for (unsigned idx = 0 ; idx < npins_ ; idx += 1) { @@ -181,22 +181,12 @@ NetObj::NetObj(NetScope*s, perm_string n, unsigned np) } } -NetObj::~NetObj() +NetPins::~NetPins() { delete[]pins_; } -NetScope* NetObj::scope() -{ - return scope_; -} - -const NetScope* NetObj::scope() const -{ - return scope_; -} - -Link& NetObj::pin(unsigned idx) +Link& NetPins::pin(unsigned idx) { if (idx >= npins_) { cerr << get_fileline() << ": internal error: pin("<del_node(this); } +NetBranch::NetBranch(discipline_t*dis) +: NetPins(2), discipline_(dis) +{ + pin(0).set_name(perm_string::literal("A"), 0); + pin(0).set_dir(Link::PASSIVE); + pin(1).set_name(perm_string::literal("B"), 0); + pin(1).set_dir(Link::PASSIVE); +} + +NetBranch::~NetBranch() +{ +} + NetBus::NetBus(NetScope*s, unsigned pin_count) : NetObj(s, perm_string::literal(""), pin_count) { @@ -622,6 +644,17 @@ void NetNet::set_isint(bool flag) isint_ = flag; } +discipline_t* NetNet::get_discipline() const +{ + return discipline_; +} + +void NetNet::set_discipline(discipline_t*dis) +{ + ivl_assert(*this, discipline_ == 0); + discipline_ = dis; +} + long NetNet::lsb() const { return lsb_; diff --git a/netlist.h b/netlist.h index d3af7febd..6a3488b46 100644 --- a/netlist.h +++ b/netlist.h @@ -69,6 +69,7 @@ class NetEvTrig; class NetEvWait; class nature_t; +class discipline_t; struct target; struct functor_t; @@ -77,6 +78,24 @@ ostream& operator << (ostream&o, ivl_variable_type_t val); extern void join_island(NetObj*obj); +class NetPins : public LineInfo { + + public: + explicit NetPins(unsigned npins); + virtual ~NetPins(); + + unsigned pin_count() const { return npins_; } + + Link&pin(unsigned idx); + const Link&pin(unsigned idx) const; + + void dump_node_pins(ostream&, unsigned) const; + + private: + Link*pins_; + const unsigned npins_; +}; + /* ========= * A NetObj is anything that has any kind of behavior in the * netlist. Nodes can be gates, registers, etc. and are linked @@ -97,7 +116,7 @@ extern void join_island(NetObj*obj); * interpretation of the rise/fall/decay times is typically left to * the target to properly interpret. */ -class NetObj : public Attrib, public virtual LineInfo { +class NetObj : public NetPins, public Attrib { public: public: @@ -111,8 +130,6 @@ class NetObj : public Attrib, public virtual LineInfo { perm_string name() const { return name_; } - unsigned pin_count() const { return npins_; } - const NetExpr* rise_time() const { return delay1_; } const NetExpr* fall_time() const { return delay2_; } const NetExpr* decay_time() const { return delay3_; } @@ -121,17 +138,11 @@ class NetObj : public Attrib, public virtual LineInfo { void fall_time(const NetExpr* d) { delay2_ = d; } void decay_time(const NetExpr* d) { delay3_ = d; } - Link&pin(unsigned idx); - const Link&pin(unsigned idx) const; - - void dump_node_pins(ostream&, unsigned) const; void dump_obj_attr(ostream&, unsigned) const; private: NetScope*scope_; perm_string name_; - Link*pins_; - const unsigned npins_; const NetExpr* delay1_; const NetExpr* delay2_; const NetExpr* delay3_; @@ -151,11 +162,31 @@ class IslandBranch { struct ivl_island_s* island; }; +/* + * A NetBranch is a construct of Verilog-A that is a branch between + * two nodes. The branch has exactly 2 pins and a discipline. + * + * pin(0) is the source of flow through a branch and the plus side of + * potential. Pin(1) is the sink of flow and the minus (or ground) of + * potential. + */ +class NetBranch : public NetPins { + + public: + explicit NetBranch(discipline_t*dis); + explicit NetBranch(discipline_t*dis, perm_string name); + ~NetBranch(); + + private: + discipline_t*discipline_; + perm_string name_; +}; + class Link { friend void connect(Link&, Link&); friend void connect(Nexus*, Link&); - friend class NetObj; + friend class NetPins; friend class Nexus; public: @@ -189,8 +220,8 @@ class Link { void set_init(verinum::V val); verinum::V get_init() const; - void cur_link(NetObj*&net, unsigned &pin); - void cur_link(const NetObj*&net, unsigned &pin) const; + void cur_link(NetPins*&net, unsigned &pin); + void cur_link(const NetPins*&net, unsigned &pin) const; // Get a pointer to the nexus that represents all the links // connected to me. @@ -217,8 +248,8 @@ class Link { // Return information about the object that this link is // a part of. - const NetObj*get_obj() const; - NetObj*get_obj(); + const NetPins*get_obj() const; + NetPins*get_obj(); unsigned get_pin() const; // A link of an object (sometimes called a "pin") has a @@ -231,7 +262,7 @@ class Link { private: // The NetNode manages these. They point back to the // NetNode so that following the links can get me here. - NetObj *node_; + NetPins *node_; unsigned pin_; DIR dir_; @@ -521,6 +552,10 @@ class NetNet : public NetObj { bool get_isint() const; void set_isint(bool); + /* Attach a discipline to the net. */ + discipline_t* get_discipline() const; + void set_discipline(discipline_t*dis); + /* These methods return the msb and lsb indices for the most significant and least significant bits. These are signed longs, and may be different from pin numbers. For example, @@ -588,6 +623,7 @@ class NetNet : public NetObj { ivl_variable_type_t data_type_; bool signed_; bool isint_; // original type of integer + discipline_t*discipline_; long msb_, lsb_; const unsigned dimensions_; @@ -2880,7 +2916,7 @@ class NetEUFunc : public NetExpr { class NetEAccess : public NetExpr { public: - explicit NetEAccess(nature_t*nat); + explicit NetEAccess(NetBranch*br, nature_t*nat); ~NetEAccess(); virtual ivl_variable_type_t expr_type() const; @@ -2891,6 +2927,7 @@ class NetEAccess : public NetExpr { virtual NexusSet* nex_input(bool rem_out = true); private: + NetBranch*branch_; nature_t*nature_; }; diff --git a/pform_disciplines.cc b/pform_disciplines.cc index cca4cc0ac..2ce7aeedd 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -205,6 +205,7 @@ void pform_attach_discipline(const struct vlltype&loc, error_count += 1; } else { + cur_net->set_data_type(IVL_VT_REAL); cur_net->set_discipline(discipline); } } diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 51f9d4ea9..cbba20ded 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -152,10 +152,14 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val) void dll_target::expr_access_func(const NetEAccess*net) { assert(expr_ == 0); - - cerr << net->get_fileline() << ": internal error: " - << "Nature access functions not implemented yet." << endl; - + // Make a stub Branch Access Function expression node. + expr_ = (ivl_expr_t)calloc(1, sizeof(struct ivl_expr_s)); + expr_->type_ = IVL_EX_BACCESS; + expr_->value_ = IVL_VT_REAL; + expr_->file = net->get_file(); + expr_->lineno = net->get_lineno(); + expr_->width_ = 1; + expr_->signed_= 1; } void dll_target::expr_binary(const NetEBinary*net) diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 791b14b75..98092d127 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -43,6 +43,17 @@ static void show_array_expression(ivl_expr_t net, unsigned ind) ivl_signal_dimensions(sig), width, vt); } +static void show_branch_access_expression(ivl_expr_t net, unsigned ind) +{ + fprintf(out, "%*s\n", ind, ""); + + if (ivl_expr_value(net) != IVL_VT_REAL) { + fprintf(out, "%*sERROR: Expecting type IVL_VT_REAL, got %s\n", + ind, "", vt_type_string(net)); + stub_errors += 1; + } +} + static void show_binary_expression(ivl_expr_t net, unsigned ind) { unsigned width = ivl_expr_width(net); @@ -216,6 +227,10 @@ void show_expression(ivl_expr_t net, unsigned ind) show_array_expression(net, ind); break; + case IVL_EX_BACCESS: + show_branch_access_expression(net, ind); + break; + case IVL_EX_BINARY: show_binary_expression(net, ind); break;