Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Replace the NetPartSelect:BI with NetTran(VP).

Fold the bi-directional part select into the pass switch (tran) support
so that it can be really bi-directional. This involves adding a new
tranvp device that does part select in tran islands, and reworking the
tran island resolution to handle non-identical nodes. This will be needed
for resistive tran devices anyhow.
  • Loading branch information...
commit 73e2b297df13e925fe6ee3901d18960afd9c2ee4 1 parent 6e5373c
@steveicarus authored
View
14 design_dump.cc
@@ -109,6 +109,9 @@ ostream& operator << (ostream&o, ivl_switch_type_t val)
case IVL_SW_RTRANIF1:
o << "rtranif1";
break;
+ case IVL_SW_TRAN_VP:
+ o << "tran(VP)";
+ break;
}
return o;
}
@@ -518,9 +521,6 @@ void NetPartSelect::dump_node(ostream&o, unsigned ind) const
case PV:
pt = "PV";
break;
- case BI:
- pt = "BI";
- break;
}
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
<< name();
@@ -639,7 +639,13 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const
void NetTran::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << type_ << " " << name()
- << " island " << island << endl;
+ << " island " << island;
+ if (type_ == IVL_SW_TRAN_VP) {
+ o << " width=" << vector_width()
+ << " part=" << part_width()
+ << " offset=" << part_offset();
+ }
+ o << endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
}
View
87 elab_net.cc
@@ -2375,29 +2375,54 @@ NetNet* PEConcat::elaborate_lnet_common_(Design*des, NetScope*scope,
osig->local_flag(true);
osig->set_line(*this);
- if (debug_elaborate) {
- cerr << get_fileline() << ": debug: Generating part selects "
- << "to connect input l-value to subexpressions."
- << endl;
- }
+ if (bidirectional_flag) {
+ if (debug_elaborate) {
+ cerr << get_fileline() << ": debug: Generating tran(VP) "
+ << "to connect input l-value to subexpressions."
+ << endl;
+ }
- NetPartSelect::dir_t part_dir = bidirectional_flag
- ? NetPartSelect::BI
- : NetPartSelect::VP;
+ for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
+ unsigned wid = nets[idx]->vector_width();
+ unsigned off = width - wid;
+ NetTran*ps = new NetTran(scope, scope->local_symbol(),
+ osig->vector_width(), wid, off);
+ des->add_node(ps);
+ ps->set_line(*this);
- for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
- unsigned wid = nets[idx]->vector_width();
- unsigned off = width - wid;
- NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
- des->add_node(ps);
+ connect(ps->pin(0), osig->pin(0));
+ connect(ps->pin(1), nets[idx]->pin(0));
- connect(ps->pin(1), osig->pin(0));
- connect(ps->pin(0), nets[idx]->pin(0));
+ join_island(ps);
+
+ ivl_assert(*this, wid <= width);
+ width -= wid;
+ }
+
+ } else {
+ if (debug_elaborate) {
+ cerr << get_fileline() << ": debug: Generating part selects "
+ << "to connect input l-value to subexpressions."
+ << endl;
+ }
- assert(wid <= width);
- width -= wid;
+ NetPartSelect::dir_t part_dir = NetPartSelect::VP;
+
+ for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
+ unsigned wid = nets[idx]->vector_width();
+ unsigned off = width - wid;
+ NetPartSelect*ps = new NetPartSelect(osig, off, wid, part_dir);
+ des->add_node(ps);
+ ps->set_line(*this);
+
+ connect(ps->pin(1), osig->pin(0));
+ connect(ps->pin(0), nets[idx]->pin(0));
+
+ assert(wid <= width);
+ width -= wid;
+ }
+ assert(width == 0);
}
- assert(width == 0);
osig->data_type(nets[0]->data_type());
osig->local_flag(true);
@@ -2751,11 +2776,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
/* If we are processing a tran or inout, then the
partselect is bi-directional. Otherwise, it is a
Part-to-Vector select. */
- NetPartSelect::dir_t part_dir;
- if (bidirectional_flag)
- part_dir = NetPartSelect::BI;
- else
- part_dir = NetPartSelect::PV;
if (debug_elaborate)
cerr << get_fileline() << ": debug: "
@@ -2772,11 +2792,24 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
subsig->local_flag(true);
subsig->set_line(*this);
- NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
- part_dir);
- des->add_node(sub);
- connect(sub->pin(0), subsig->pin(0));
+ if (bidirectional_flag) {
+ // Make a tran(VP)
+ NetTran*sub = new NetTran(scope, scope->local_symbol(),
+ sig->vector_width(),
+ subnet_wid, lidx);
+ sub->set_line(*this);
+ des->add_node(sub);
+ connect(sub->pin(0), sig->pin(0));
+ connect(sub->pin(1), subsig->pin(0));
+ join_island(sub);
+ } else {
+ NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
+ NetPartSelect::PV);
+ des->add_node(sub);
+ sub->set_line(*this);
+ connect(sub->pin(0), subsig->pin(0));
+ }
sig = subsig;
}
View
36 elaborate.cc
@@ -889,6 +889,32 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
tmp->local_flag(true);
tmp->set_line(*sig);
+ // Handle the special case of a bi-directional part
+ // select. Create a NetTran(VP) instead of a uni-directional
+ // NetPartSelect node.
+ if (dir == NetNet::PINOUT) {
+ unsigned wida = sig->vector_width();
+ unsigned widb = tmp->vector_width();
+ bool part_b = widb < wida;
+ NetTran*node = new NetTran(scope, scope->local_symbol(),
+ part_b? wida : widb,
+ part_b? widb : wida,
+ 0);
+ if (part_b) {
+ connect(node->pin(0), tmp->pin(0));
+ connect(node->pin(1), sig->pin(0));
+ } else {
+ connect(node->pin(0), sig->pin(0));
+ connect(node->pin(1), tmp->pin(0));
+ }
+
+ node->set_line(*this);
+ des->add_node(node);
+ join_island(node);
+
+ return tmp;
+ }
+
NetPartSelect*node = 0;
switch (dir) {
@@ -917,15 +943,7 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope,
break;
case NetNet::PINOUT:
- if (sig->vector_width() > tmp->vector_width()) {
- node = new NetPartSelect(sig, 0, tmp->vector_width(),
- NetPartSelect::BI);
- connect(node->pin(0), tmp->pin(0));
- } else {
- node = new NetPartSelect(tmp, 0, sig->vector_width(),
- NetPartSelect::BI);
- connect(node->pin(0), sig->pin(0));
- }
+ ivl_assert(*this, 0);
break;
default:
View
3  ivl.def
@@ -226,8 +226,11 @@ ivl_switch_enable
ivl_switch_file
ivl_switch_island
ivl_switch_lineno
+ivl_switch_offset
+ivl_switch_part
ivl_switch_scope
ivl_switch_type
+ivl_switch_width
ivl_udp_init
ivl_udp_name
View
20 ivl_target.h
@@ -245,7 +245,8 @@ typedef enum ivl_switch_type_e {
IVL_SW_TRANIF1 = 2,
IVL_SW_RTRAN = 3,
IVL_SW_RTRANIF0 = 4,
- IVL_SW_RTRANIF1 = 5
+ IVL_SW_RTRANIF1 = 5,
+ IVL_SW_TRAN_VP = 6
} ivl_switch_type_t;
/* This is the type of an LPM object. */
@@ -265,7 +266,7 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_MOD = 13,
IVL_LPM_MULT = 4,
IVL_LPM_MUX = 5,
- IVL_LPM_PART_BI= 28, /* part select: bi-directional (part on 0) */
+ /* IVL_LPM_PART_BI= 28, / obsolete */
IVL_LPM_PART_VP= 15, /* part select: vector to part */
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
IVL_LPM_POW = 31,
@@ -728,8 +729,8 @@ extern unsigned ivl_file_table_size(void);
* Allow the user to test or set a boolean flag associated with the
* island.
*/
-extern int ivl_island_flag_set(ivl_island_t net, int flag, int value);
-extern int ivl_island_flag_test(ivl_island_t net, int flag);
+extern int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value);
+extern int ivl_island_flag_test(ivl_island_t net, unsigned flag);
/* LOGIC
* These types and functions support manipulation of logic gates. The
@@ -1883,7 +1884,11 @@ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net);
*
* SEMANTIC NOTES
* The a/b ports can be any type, but the types must exactly
- * match. The enable must be a scalar.
+ * match, including vector widths. The enable must be a scalar.
+ *
+ * The IVL_SW_TRAN_VP is an exception to the above. In this case,
+ * the B side may be a different size, and the a side will have a
+ * a fixed width. The unused bits are padded to Z on the A side.
*/
extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net);
extern ivl_scope_t ivl_switch_scope(ivl_switch_t net);
@@ -1893,6 +1898,11 @@ extern ivl_nexus_t ivl_switch_b(ivl_switch_t net);
extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net);
extern ivl_island_t ivl_switch_island(ivl_switch_t net);
+ /* These are only support for IVL_SW_TRAN_VP switches. */
+extern unsigned ivl_switch_width(ivl_switch_t net);
+extern unsigned ivl_switch_part(ivl_switch_t net);
+extern unsigned ivl_switch_offset(ivl_switch_t net);
+
/* Not implemented yet
extern unsigned ivl_switch_attr_cnt(ivl_switch_t net);
extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx);
View
24 net_tran.cc
@@ -43,7 +43,7 @@ static bool has_enable(ivl_switch_type_t tt)
}
NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
- : NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
+: NetNode(scope, n, has_enable(tt)? 3 : 2), type_(tt)
{
pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
@@ -53,10 +53,32 @@ NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt)
}
}
+NetTran::NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off)
+: NetNode(scope, n, 2), type_(IVL_SW_TRAN_VP), wid_(wid), part_(part), off_(off)
+{
+ pin(0).set_dir(Link::PASSIVE); pin(0).set_name(perm_string::literal("A"), 0);
+ pin(1).set_dir(Link::PASSIVE); pin(1).set_name(perm_string::literal("B"), 0);
+}
+
NetTran::~NetTran()
{
}
+unsigned NetTran::vector_width() const
+{
+ return wid_;
+}
+
+unsigned NetTran::part_width() const
+{
+ return part_;
+}
+
+unsigned NetTran::part_offset() const
+{
+ return off_;
+}
+
void join_island(NetObj*obj)
{
IslandBranch*branch = dynamic_cast<IslandBranch*> (obj);
View
22 netlist.h
@@ -1379,16 +1379,28 @@ class NetSysFunc : public NetNode {
class NetTran : public NetNode, public IslandBranch {
public:
+ // Tran devices other then TRAN_VP
NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type);
+ // Create a TRAN_VP
+ NetTran(NetScope*scope, perm_string n, unsigned wid,
+ unsigned part, unsigned off);
~NetTran();
ivl_switch_type_t type() const { return type_; }
+ // These are only used for IVL_SW_TRAN_PV
+ unsigned vector_width() const;
+ unsigned part_width() const;
+ unsigned part_offset() const;
+
virtual void dump_node(ostream&, unsigned ind) const;
virtual bool emit_node(struct target_t*) const;
private:
ivl_switch_type_t type_;
+ unsigned wid_;
+ unsigned part_;
+ unsigned off_;
};
/* =========
@@ -1605,8 +1617,8 @@ class NetECRealParam : public NetECReal {
* selector as the input.
*
* The NetPartSelect can be output from the signal (i.e. reading a
- * part), input into the signal, or bi-directional. The DIR method
- * gives the type of the node.
+ * part) or input into the signal. The DIR method gives the type of
+ * the node.
*
* VP (Vector-to-Part)
* Output pin 0 is the part select, and input pin 1 is connected to
@@ -1616,10 +1628,6 @@ class NetECRealParam : public NetECReal {
* Output pin 1 is connected to the NetNet, and input pin 0 is the
* part select. In this case, the node is driving the NetNet.
*
- * BI (BI-directional)
- * Pin 0 is the part select and pin 1 is connected to the NetNet, but
- * the ports are intended to be bi-directional.
- *
* Note that whatever the direction that data is intended to flow,
* pin-0 is the part select and pin-1 is connected to the NetNet.
*/
@@ -1627,7 +1635,7 @@ class NetPartSelect : public NetNode {
public:
// enum for the device direction
- enum dir_t { VP, PV, BI };
+ enum dir_t { VP, PV};
explicit NetPartSelect(NetNet*sig,
unsigned off, unsigned wid, dir_t dir);
View
23 t-dll-api.cc
@@ -555,7 +555,7 @@ extern "C" unsigned ivl_file_table_size()
return fn_vector.size();
}
-extern "C" int ivl_island_flag_set(ivl_island_t net, int flag, int value)
+extern "C" int ivl_island_flag_set(ivl_island_t net, unsigned flag, int value)
{
if (flag >= net->flags.size()) {
if (value == 0)
@@ -569,7 +569,7 @@ extern "C" int ivl_island_flag_set(ivl_island_t net, int flag, int value)
return old_flag;
}
-extern "C" int ivl_island_flag_test(ivl_island_t net, int flag)
+extern "C" int ivl_island_flag_test(ivl_island_t net, unsigned flag)
{
if (flag >= net->flags.size())
return 0;
@@ -804,7 +804,6 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
switch (net->type) {
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
- case IVL_LPM_PART_BI:
return net->u_.part.base;
default:
assert(0);
@@ -940,7 +939,6 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
- case IVL_LPM_PART_BI:
assert(idx <= 1);
if (idx == 0)
return net->u_.part.a;
@@ -1083,7 +1081,6 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
- case IVL_LPM_PART_BI:
assert(idx == 0);
return net->u_.part.q;
@@ -1179,7 +1176,6 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
- case IVL_LPM_PART_BI:
return net->u_.part.signed_flag;
case IVL_LPM_REPEAT:
return 0;
@@ -2218,6 +2214,21 @@ extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net)
return net->pins[2];
}
+extern "C" unsigned ivl_switch_width(ivl_switch_t net)
+{
+ return net->width;
+}
+
+extern "C" unsigned ivl_switch_part(ivl_switch_t net)
+{
+ return net->part;
+}
+
+extern "C" unsigned ivl_switch_offset(ivl_switch_t net)
+{
+ return net->offset;
+}
+
extern "C" const char* ivl_switch_file(ivl_switch_t net)
{
return net->file;
View
37 t-dll.cc
@@ -1037,6 +1037,9 @@ bool dll_target::tran(const NetTran*net)
{
struct ivl_switch_s*obj = new struct ivl_switch_s;
obj->type = net->type();
+ obj->width = 0;
+ obj->part = 0;
+ obj->offset = 0;
obj->name = net->name();
obj->scope = find_scope(des_, net->scope());
obj->island = net->island;
@@ -1065,6 +1068,12 @@ bool dll_target::tran(const NetTran*net)
obj->pins[2] = 0;
}
+ if (obj->type == IVL_SW_TRAN_VP) {
+ obj->width = net->vector_width();
+ obj->part = net->part_width();
+ obj->offset= net->part_offset();
+ }
+
obj->file = net->get_file();
obj->lineno = net->get_lineno();
@@ -1996,9 +2005,6 @@ bool dll_target::part_select(const NetPartSelect*net)
case NetPartSelect::PV:
obj->type = IVL_LPM_PART_PV;
break;
- case NetPartSelect::BI:
- obj->type = IVL_LPM_PART_BI;
- break;
}
obj->name = net->name(); // NetPartSelect names are permallocated.
assert(net->scope());
@@ -2052,35 +2058,12 @@ bool dll_target::part_select(const NetPartSelect*net)
obj->u_.part.a = nex->t_cookie();
break;
- case IVL_LPM_PART_BI:
- /* For now, handle this exactly the same as a PV */
-
- /* NetPartSelect:pin(0) is the output pin. */
- nex = net->pin(0).nexus();
- assert(nex->t_cookie());
-
- obj->u_.part.q = nex->t_cookie();
-
- /* NetPartSelect:pin(1) is the input pin. */
- nex = net->pin(1).nexus();
- assert(nex->t_cookie());
-
- obj->u_.part.a = nex->t_cookie();
- break;
-
default:
assert(0);
}
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
-
- /* If the device is a PART_BI, then the "input" is also a
- strength aware output, so attach it to the nexus with
- strong driver. */
- if (obj->type == IVL_LPM_PART_BI)
- nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
- else
- nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
+ nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
/* The select input is optional. */
if (obj->u_.part.s)
View
3  t-dll.h
@@ -451,6 +451,9 @@ struct ivl_net_logic_s {
struct ivl_switch_s {
ivl_switch_type_t type;
+ unsigned width;
+ unsigned part;
+ unsigned offset;
perm_string name;
ivl_scope_t scope;
View
37 tgt-stub/stub.c
@@ -555,38 +555,6 @@ static void show_lpm_part(ivl_lpm_t net)
}
}
-static void show_lpm_part_bi(ivl_lpm_t net)
-{
- unsigned width = ivl_lpm_width(net);
- unsigned base = ivl_lpm_base(net);
- ivl_nexus_t port_p = ivl_lpm_q(net,0);
- ivl_nexus_t port_v = ivl_lpm_data(net,0);
-
- fprintf(out, " LPM_PART_BI %s: <width=%u, base=%u, signed=%d>\n",
- ivl_lpm_basename(net), width, base, ivl_lpm_signed(net));
- fprintf(out, " P: %s\n", ivl_nexus_name(port_p));
- fprintf(out, " V: %s <width=%u>\n", ivl_nexus_name(port_v),
- width_of_nexus(port_v));
-
-
- /* The data(0) port must be large enough for the part select. */
- if (width_of_nexus(ivl_lpm_data(net,0)) < (width+base)) {
- fprintf(out, " ERROR: Part select is out of range."
- " Data nexus width=%u, width+base=%u\n",
- width_of_nexus(ivl_lpm_data(net,0)), width+base);
- stub_errors += 1;
- }
-
- /* The Q vector must be exactly the width of the part select. */
- if (width_of_nexus(ivl_lpm_q(net,0)) != width) {
- fprintf(out, " ERROR: Part select input mismatch."
- " Nexus width=%u, expect width=%u\n",
- width_of_nexus(ivl_lpm_q(net,0)), width);
- stub_errors += 1;
- }
-}
-
-
/*
* The reduction operators have similar characteristics and are
* displayed here.
@@ -905,11 +873,6 @@ static void show_lpm(ivl_lpm_t net)
show_lpm_part(net);
break;
- /* The BI part select is slightly special. */
- case IVL_LPM_PART_BI:
- show_lpm_part_bi(net);
- break;
-
case IVL_LPM_REPEAT:
show_lpm_repeat(net);
break;
View
52 tgt-stub/switches.c
@@ -52,18 +52,23 @@ void show_switch(ivl_switch_t net)
fprintf(out, " rtranif1 %s", name);
has_enable = 1;
break;
+ case IVL_SW_TRAN_VP:
+ fprintf(out, " tran(PV wid=%u, part=%u, off=%u) %s",
+ ivl_switch_width(net), ivl_switch_part(net),
+ ivl_switch_offset(net), name);
+ break;
}
fprintf(out, " island=%p\n", ivl_switch_island(net));
- ivl_nexus_t nex = ivl_switch_a(net);
- const char*nex_name = nex? ivl_nexus_name(nex) : "";
- ivl_variable_type_t nex_type_a = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
+ ivl_nexus_t nexa = ivl_switch_a(net);
+ const char*nex_name = nexa? ivl_nexus_name(nexa) : "";
+ ivl_variable_type_t nex_type_a = nexa? type_of_nexus(nexa) : IVL_VT_NO_TYPE;
fprintf(out, " A: %s <type=%s>\n", nex_name, data_type_string(nex_type_a));
- nex = ivl_switch_b(net);
- nex_name = nex? ivl_nexus_name(nex) : "";
- ivl_variable_type_t nex_type_b = nex? type_of_nexus(nex) : IVL_VT_NO_TYPE;
+ ivl_nexus_t nexb = ivl_switch_b(net);
+ nex_name = nexb? ivl_nexus_name(nexb) : "";
+ ivl_variable_type_t nex_type_b = nexb? type_of_nexus(nexb) : IVL_VT_NO_TYPE;
fprintf(out, " B: %s <type=%s>\n", nex_name, data_type_string(nex_type_b));
/* The A/B pins of the switch must be present, and must match. */
@@ -80,13 +85,40 @@ void show_switch(ivl_switch_t net)
stub_errors += 1;
}
+ if (ivl_switch_type(net) == IVL_SW_TRAN_VP) {
+ /* The TRAN_VP nodes are special in that the specific
+ width matters for each port and should be exactly
+ right for both. */
+ if (width_of_nexus(nexa) != ivl_switch_width(net)) {
+ fprintf(out, " A: ERROR: part vector nexus "
+ "width=%u, expecting width=%u\n",
+ width_of_nexus(nexa), ivl_switch_width(net));
+ stub_errors += 1;
+ }
+ if (width_of_nexus(nexb) != ivl_switch_part(net)) {
+ fprintf(out, " B: ERROR: part select nexus "
+ "width=%u, expecting width=%u\n",
+ width_of_nexus(nexb), ivl_switch_part(net));
+ stub_errors += 1;
+ }
+ } else {
+ /* All other TRAN nodes will have matching vector
+ widths, but the actual value doesn't matter. */
+ if (width_of_nexus(nexa) != width_of_nexus(nexb)) {
+ fprintf(out, " A/B: ERROR: Width of ports don't match"
+ ": A=%u, B=%u\n",
+ width_of_nexus(nexa), width_of_nexus(nexb));
+ stub_errors += 1;
+ }
+ }
+
if (has_enable) {
- nex = ivl_switch_enable(net);
- nex_name = nex? ivl_nexus_name(nex) : "";
+ ivl_nexus_t nexe = ivl_switch_enable(net);
+ nex_name = nexe? ivl_nexus_name(nexe) : "";
fprintf(out, " E: %s\n", nex_name);
- if (width_of_nexus(nex) != 1) {
+ if (width_of_nexus(nexe) != 1) {
fprintf(out, " E: ERROR: Nexus width is %u\n",
- width_of_nexus(nex));
+ width_of_nexus(nexe));
}
}
}
View
25 tgt-vvp/draw_net_input.c
@@ -421,17 +421,6 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
}
break;
- case IVL_LPM_PART_BI:
- if (ivl_lpm_q(lpm, 0) == nex) {
- char tmp[128];
- snprintf(tmp, sizeof tmp, "L_%p/P", lpm);
- return strdup(tmp);
- } else if (ivl_lpm_data(lpm,0) == nex) {
- char tmp[128];
- snprintf(tmp, sizeof tmp, "L_%p/V", lpm);
- return strdup(tmp);
- }
- break;
}
fprintf(stderr, "internal error: no input to nexus %s\n",
@@ -440,7 +429,8 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
return strdup("C<z>");
}
-static char* draw_island_port(ivl_island_t island, ivl_nexus_t nex, const char*src)
+static char* draw_island_port(ivl_island_t island,
+ ivl_nexus_t nex, const char*src)
{
char result[64];
if (ivl_island_flag_test(island,0) == 0) {
@@ -450,6 +440,7 @@ static char* draw_island_port(ivl_island_t island, ivl_nexus_t nex, const char*s
fprintf(vvp_out, "p%p .port I%p, %s;\n", nex, island, src);
snprintf(result, sizeof result, "p%p", nex);
+
return strdup(result);
}
@@ -517,13 +508,14 @@ char* draw_net_input_x(ivl_nexus_t nex,
for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
ivl_lpm_t lpm_tmp;
- ivl_switch_t sw;
+ ivl_switch_t sw = 0;
ivl_nexus_ptr_t nptr = ivl_nexus_ptr(nex, idx);
/* If this object is part of an island, then we'll be
making a port. Save the island cookie. */
- if ( (sw = ivl_nexus_ptr_switch(nptr)) )
+ if ( (sw = ivl_nexus_ptr_switch(nptr)) ) {
island = ivl_switch_island(sw);
+ }
/* If we are supposed to skip LPM_PART_BI data pins,
check that this driver is that. */
@@ -589,6 +581,11 @@ char* draw_net_input_x(ivl_nexus_t nex,
}
*tmp++ = '>';
*tmp = 0;
+ if (island) {
+ char*tmp = draw_island_port(island, nex, nex_private);
+ free(nex_private);
+ nex_private = tmp;
+ }
return nex_private;
}
View
11 tgt-vvp/draw_switch.c
@@ -53,14 +53,19 @@ void draw_switch_in_scope(ivl_switch_t sw)
switch (ivl_switch_type(sw)) {
case IVL_SW_TRAN:
- fprintf(vvp_out, " .tran ");
+ fprintf(vvp_out, " .tran");
break;
case IVL_SW_TRANIF0:
- fprintf(vvp_out, " .tranif0 ");
+ fprintf(vvp_out, " .tranif0");
break;
case IVL_SW_TRANIF1:
- fprintf(vvp_out, " .tranif1 ");
+ fprintf(vvp_out, " .tranif1");
break;
+ case IVL_SW_TRAN_VP:
+ fprintf(vvp_out, " .tranvp %u %u %u,",
+ ivl_switch_width(sw), ivl_switch_part(sw), ivl_switch_offset(sw));
+ break;
+
default:
fprintf(stderr, "%s:%u: sorry: vvp target does not support switch modeling.\n",
ivl_switch_file(sw), ivl_switch_lineno(sw));
View
92 tgt-vvp/vvp_scope.c
@@ -1612,94 +1612,6 @@ static void draw_lpm_part_pv(ivl_lpm_t net)
}
/*
- * Handle the drawing of a bi-directional part select. The two ports
- * are simultaneously input and output. A simple minded connect of the
- * input to the output causes a functor cycle which will lock into an
- * X value, so something special is needed.
- *
- * NOTE: The inputs of the tran device at this point need to be from
- * all the drivers of the nexus *except* the tran itself. This
- * function will draw three labels that can be linked:
- *
- * The ivl_lpm_q of a part(bi) may be a smaller vector then the
- * ivl_lpm_data, the tran acts like a forward part select in that
- * way.
- *
- * The device creates these nodes:
- *
- * - L_%p/i
- * This is the Q port of the tran resolved and padded to the maximum
- * width of the tran. The tran itself is not included in the
- * resolution of this port.
- *
- * - L_%p/V
- * This is the Q and D parts resolved together, still without the tran
- * driving anything.
- *
- * - L_%p/P
- * This is the /V node part-selected back to the dimensions of the Q
- * side.
- */
-static void draw_lpm_part_bi(ivl_lpm_t net)
-{
- unsigned width = ivl_lpm_width(net);
- unsigned base = ivl_lpm_base(net);
- unsigned signal_width = width_of_nexus(ivl_lpm_data(net,0));
-
- unsigned idx;
- ivl_nexus_t nex;
- ivl_nexus_ptr_t ptr = 0;
-
- char*p_str;
- char*v_str;
-
- /* It seems implausible that the two inputs of a tran will be
- connected together. So assert that this is so to simplify
- the code to look for the nexus_ptr_t objects. */
- assert(ivl_lpm_q(net,0) != ivl_lpm_data(net,0));
-
- nex = ivl_lpm_q(net,0);
- for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
- ptr = ivl_nexus_ptr(nex, idx);
- if (ivl_nexus_ptr_lpm(ptr) == net)
- break;
- }
- assert(ptr != 0);
- p_str = draw_net_input_x(nex, ptr, 0, 0);
-
- nex = ivl_lpm_data(net,0);
- for (idx = 0 ; idx < ivl_nexus_ptrs(nex) ; idx += 1) {
- ptr = ivl_nexus_ptr(nex, idx);
- if (ivl_nexus_ptr_lpm(ptr) == net)
- break;
- }
- v_str = draw_net_input_x(nex, ptr, OMIT_PART_BI_DATA, 0);
-
- /* Pad the part-sized input out to a common width...
- The /i label is the Q side of the tran, resolved except for
- the tran itself and padded (with z) to the larger width. */
- fprintf(vvp_out, "L_%p/i .part/pv %s, %u, %u, %u;\n",
- net, p_str, base, width, signal_width);
-
- /* Resolve together the two halves of the tran...
- The /V label is the ports of the tran (now the same width)
- resolved together. Neither input to this resolver includes
- the tran itself. */
- fprintf(vvp_out, "L_%p/V .resolv tri, L_%p/i, %s;\n",
- net, net, v_str);
-
- /* The full-width side is created by the tran device, all we
- have left to to is take a part select of that for the
- smaller output, and this becomes the part select output of
- the BI device. */
- fprintf(vvp_out, "L_%p/P .part L_%p/V, %u, %u;\n", net,
- net, base, width);
-
- free(p_str);
- free(v_str);
-}
-
-/*
* Draw unary reduction devices.
*/
static void draw_lpm_re(ivl_lpm_t net, const char*type)
@@ -1745,10 +1657,6 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_array(net);
return;
- case IVL_LPM_PART_BI:
- draw_lpm_part_bi(net);
- return;
-
case IVL_LPM_PART_VP:
draw_lpm_part(net);
return;
View
2  vvp/compile.h
@@ -460,6 +460,8 @@ extern void compile_island_export(char*label, char*island);
extern void compile_island_tranif(int sense, char*island,
char*ba, char*bb, char*src);
+extern void compile_island_tranvp(char*island, char*ba, char*bb,
+ unsigned width, unsigned part, unsigned off);
extern void compile_island_cleanup(void);
View
1  vvp/lexor.lex
@@ -160,6 +160,7 @@
".tran" { return K_TRAN; }
".tranif0" { return K_TRANIF0; }
".tranif1" { return K_TRANIF1; }
+".tranvp" { return K_TRANVP; }
".ufunc" { return K_UFUNC; }
".var" { return K_VAR; }
".var/real" { return K_VAR_R; }
View
5 vvp/parse.y
@@ -81,7 +81,7 @@ static struct __vpiModPath*modpath_dst = 0;
%token K_PART_V K_PORT K_PV K_REDUCE_AND K_REDUCE_OR K_REDUCE_XOR
%token K_REDUCE_NAND K_REDUCE_NOR K_REDUCE_XNOR K_REPEAT
%token K_RESOLV K_SCOPE K_SFUNC K_SHIFTL K_SHIFTR K_SHIFTRS
-%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_UFUNC
+%token K_THREAD K_TIMESCALE K_TRAN K_TRANIF0 K_TRANIF1 K_TRANVP K_UFUNC
%token K_UDP K_UDP_C K_UDP_S
%token K_VAR K_VAR_S K_VAR_I K_VAR_R K_vpi_call K_vpi_func K_vpi_func_r
%token K_disable K_fork
@@ -697,6 +697,9 @@ statement
| K_TRANIF1 T_SYMBOL ',' T_SYMBOL T_SYMBOL ',' T_SYMBOL ';'
{ compile_island_tranif(1, $2, $4, $5, $7); }
+ | K_TRANVP T_NUMBER T_NUMBER T_NUMBER ',' T_SYMBOL ',' T_SYMBOL T_SYMBOL ';'
+ { compile_island_tranvp($6, $8, $9, $2, $3, $4); }
+
/* Oh and by the way, empty statements are OK as well. */
| ';'
View
185 vvp/vvp_island.cc
@@ -166,6 +166,7 @@ struct vvp_island_branch {
bool enabled_flag;
vvp_net_t*en;
int flags;
+ unsigned width, part, offset;
};
/*
@@ -321,7 +322,7 @@ bool vvp_island_branch::run_test_enabled()
{
flags = 0;
- vvp_island_port*ep = dynamic_cast<vvp_island_port*> (en->fun);
+ vvp_island_port*ep = en? dynamic_cast<vvp_island_port*> (en->fun) : 0;
// If there is no ep port (no "enabled" input) then this is a
// tran branch. Assume it is always enabled.
@@ -343,63 +344,138 @@ bool vvp_island_branch::run_test_enabled()
return true;
}
-void collect_connections(list<vvp_net_t*>&connections, vvp_branch_ptr_t cur)
+static vvp_branch_ptr_t next(vvp_branch_ptr_t cur)
{
vvp_island_branch*ptr = cur.ptr();
unsigned ab = cur.port();
- unsigned other_ab = ab^1;
+ return ptr->link[ab];
+}
- int ab_mask = 1 << ab;
+static void collect_node(list<vvp_branch_ptr_t>&conn, vvp_branch_ptr_t cur)
+{
+ conn .push_back(cur);
+ for (vvp_branch_ptr_t idx = next(cur) ; idx != cur ; idx = next(idx))
+ conn.push_back(idx);
+}
- if ( (ptr->flags&ab_mask) != 0)
- return;
+static vvp_vector8_t get_value(vvp_net_t*net)
+{
+ vvp_island_port*fun = dynamic_cast<vvp_island_port*>(net->fun);
+ return fun->invalue;
+}
+
+static vvp_vector8_t get_value_from_branch(vvp_branch_ptr_t cur)
+{
+ vvp_island_branch*ptr = cur.ptr();
+ unsigned ab = cur.port();
+ unsigned ab_other = ab^1;
+
+ // If the branch link is disabled, return nil.
+ if (ptr->enabled_flag == false)
+ return vvp_vector8_t();
+
+ // If the branch other side is already visited, return nil.
+ if (ptr->flags & (1<<ab_other))
+ return vvp_vector8_t();
- ptr->flags |= ab_mask;
- connections.push_back( ab? ptr->b : ptr->a );
+ vvp_branch_ptr_t other (ptr, ab_other);
- if (ptr->enabled_flag)
- collect_connections(connections, vvp_branch_ptr_t(ptr, other_ab));
- collect_connections(connections, ptr->link[ab]);
+ // Other side net, and port value.
+ vvp_net_t*net = ab? ptr->a : ptr->b;
+ vvp_vector8_t val_other = get_value(net);
+
+ // Temporarily mark as visited.
+ ptr->flags |= 1<<ab_other;
+
+ // recurse
+ list<vvp_branch_ptr_t> connections;
+ collect_node(connections, other);
+
+ for (list<vvp_branch_ptr_t>::iterator idx = connections.begin()
+ ; idx != connections.end() ; idx ++ ) {
+ vvp_vector8_t tmp = get_value_from_branch(*idx);
+ if (val_other.size() == 0)
+ val_other = tmp;
+ else if (tmp.size() != 0)
+ val_other = resolve(val_other, tmp);
+ }
+
+ // Remove visited flag
+ ptr->flags &= ~(1<<ab_other);
+
+ if (val_other.size() == 0)
+ return val_other;
+
+ if (ptr->width) {
+ if (ab == 0) {
+ val_other = part_expand(val_other, ptr->width, ptr->offset);
+ } else {
+ val_other = val_other.subvalue(ptr->offset, ptr->part);
+ }
+ }
+
+ return val_other;
}
-
+
void vvp_island_branch::run_resolution()
{
- if ( (flags&1) == 0) {
- list<vvp_net_t*>collection;
- collect_connections(collection, vvp_branch_ptr_t(this, 0));
- vvp_vector8_t tmp;
- for (list<vvp_net_t*>::iterator cur = collection.begin()
- ; cur != collection.end() ; cur ++ ) {
- vvp_island_port*fun = dynamic_cast<vvp_island_port*>((*cur)->fun);
- if (tmp.size() == 0)
- tmp = fun->invalue;
- else if (fun->invalue.size() != 0)
- tmp = resolve(tmp, fun->invalue);
- }
+ // Collect all the branch endpoints that are joined to my A
+ // side.
+ list<vvp_branch_ptr_t> connections;
+ collect_node(connections, vvp_branch_ptr_t(this, 0));
+
+ // Mark my A side as done. Do this early to prevent recursing
+ // back.
+ flags |= 1;
+
+ // Prime the resolution with the port value for this node.
+ vvp_vector8_t val = get_value(a);
+
+ // Now scan the other sides of all the branches connected to
+ // my A side. The get_value_from_branch() will recurse as
+ // necessary to depth-first walk the graph.
+ for (list<vvp_branch_ptr_t>::iterator idx = connections.begin()
+ ; idx != connections.end() ; idx ++ ) {
+ vvp_vector8_t tmp = get_value_from_branch(*idx);
+ if (val.size() == 0)
+ val = tmp;
+ else if (tmp.size() != 0)
+ val = resolve(val, tmp);
+ }
+
+ // A side is done.
+ vvp_send_vec8(a->out, val);
+
+ flags &= ~1;
- for (list<vvp_net_t*>::iterator cur = collection.begin()
- ; cur != collection.end() ; cur ++ )
- vvp_send_vec8((*cur)->out, tmp);
+ // If this is a connected branch without a part select, then
+ // we know from the start that the other side has the same
+ // value as this. Mark it and finish.
+ if (enabled_flag && width==0) {
+ vvp_send_vec8(b->out, val);
+ return;
}
- if ( (flags&2) == 0) {
- list<vvp_net_t*>collection;
- collect_connections(collection, vvp_branch_ptr_t(this, 1));
- vvp_vector8_t tmp;
- for (list<vvp_net_t*>::iterator cur = collection.begin()
- ; cur != collection.end() ; cur ++ ) {
- vvp_island_port*fun = dynamic_cast<vvp_island_port*>((*cur)->fun);
- if (tmp.size() == 0)
- tmp = fun->invalue;
- else if (fun->invalue.size() != 0)
- tmp = resolve(tmp, fun->invalue);
- }
+ // Repeat the above for the B side.
+
+ connections.clear();
+ collect_node(connections, vvp_branch_ptr_t(this, 1));
- for (list<vvp_net_t*>::iterator cur = collection.begin()
- ; cur != collection.end() ; cur ++ )
- vvp_send_vec8((*cur)->out, tmp);
+ flags |= 2;
+
+ val = get_value(b);
+
+ for (list<vvp_branch_ptr_t>::iterator idx = connections.begin()
+ ; idx != connections.end() ; idx ++ ) {
+ vvp_vector8_t tmp = get_value_from_branch(*idx);
+ if (val.size() == 0)
+ val = tmp;
+ else if (tmp.size() != 0)
+ val = resolve(val, tmp);
}
+ flags &= ~2;
+ vvp_send_vec8(b->out, val);
}
/* **** COMPILE/LINK SUPPORT **** */
@@ -502,6 +578,31 @@ void compile_island_tranif(int sense, char*island, char*pa, char*pb, char*pe)
free(pe);
}
+ br->width = 0;
+ br->part = 0;
+ br->offset = 0;
+
+ use_island->add_branch(br, pa, pb);
+
+ free(pa);
+ free(pb);
+}
+
+void compile_island_tranvp(char*island, char*pa, char*pb,
+ unsigned wid, unsigned par, unsigned off)
+{
+ assert(island_table);
+ vvp_island*use_island = island_table->sym_get_value(island);
+ assert(use_island);
+ free(island);
+
+ vvp_island_branch*br = new vvp_island_branch;
+ br->active_high = false;
+ br->en = 0;
+ br->width = wid;
+ br->part = par;
+ br->offset = off;
+
use_island->add_branch(br, pa, pb);
free(pa);
View
2  vvp/vvp_net.h
@@ -556,7 +556,7 @@ class vvp_vector8_t {
unsigned size() const { return size_; }
vvp_scalar_t value(unsigned idx) const;
- vvp_vector8_t subvalue(unsigned idx, unsigned size) const;
+ vvp_vector8_t subvalue(unsigned adr, unsigned width) const;
void set_bit(unsigned idx, vvp_scalar_t val);
// Test that the vectors are exactly equal
Please sign in to comment.
Something went wrong with that request. Please try again.