diff --git a/Makefile.in b/Makefile.in index 90b9d4aaf..3df9bb21b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -106,7 +106,7 @@ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ load_module.o netlist.o netmisc.o net_assign.o \ net_design.o net_event.o net_expr.o net_force.o net_func.o \ net_link.o net_modulo.o net_nex_input.o net_nex_output.o \ -net_proc.o net_scope.o net_udp.o pad_to_width.o \ +net_proc.o net_scope.o net_tran.o net_udp.o pad_to_width.o \ parse.o parse_misc.o pform.o pform_disciplines.o pform_dump.o pform_types.o \ set_width.o symbol_search.o sync.o sys_funcs.o \ verinum.o verireal.o target.o targets.o \ diff --git a/design_dump.cc b/design_dump.cc index 3c00083a8..b191a25fe 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -88,6 +88,31 @@ ostream& operator << (ostream&o, ivl_variable_type_t val) return o; } +ostream& operator << (ostream&o, ivl_switch_type_t val) +{ + switch (val) { + case IVL_SW_TRAN: + o << "tran"; + break; + case IVL_SW_TRANIF0: + o << "tranif0"; + break; + case IVL_SW_TRANIF1: + o << "tranif1"; + break; + case IVL_SW_RTRAN: + o << "rtran"; + break; + case IVL_SW_RTRANIF0: + o << "rtranif0"; + break; + case IVL_SW_RTRANIF1: + o << "rtranif1"; + break; + } + return o; +} + static inline void dump_scope_path(ostream&o, const NetScope*scope) { if (const NetScope*parent = scope->parent()) { @@ -611,6 +636,13 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const o << setw(ind) << "" << "endtask" << endl; } +void NetTran::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << type_ << " " << name() << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetUDP::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "UDP (" << udp_name() << "): "; diff --git a/elaborate.cc b/elaborate.cc index abc12b2ca..d7180f4b5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -419,7 +419,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const } /* Allocate all the netlist nodes for the gates. */ - NetLogic**cur = new NetLogic*[count]; + NetNode**cur = new NetNode*[count]; assert(cur); /* Calculate the gate delays from the delay expressions @@ -659,6 +659,67 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const cur[idx] = new NetLogic(scope, inm, pin_count(), NetLogic::XOR, instance_width); break; + case TRAN: + if (pin_count() != 2) { + cerr << get_fileline() << ": error: Pin count for " + << "tran device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN); + } + break; + case RTRAN: + if (pin_count() != 2) { + cerr << get_fileline() << ": error: Pin count for " + << "rtran device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN); + return; + } + break; + case TRANIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "tranif0 device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0); + } + break; + case RTRANIF0: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "rtranif0 device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0); + } + break; + case TRANIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "tranif1 device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1); + } + break; + case RTRANIF1: + if (pin_count() != 3) { + cerr << get_fileline() << ": error: Pin count for " + << "rtranif1 device." << endl; + des->errors += 1; + return; + } else { + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1); + } + break; default: cerr << get_fileline() << ": internal error: unhandled " "gate type." << endl; @@ -670,13 +731,18 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const cur[idx]->attribute(attrib_list[adx].key, attrib_list[adx].val); - cur[idx]->rise_time(rise_time); - cur[idx]->fall_time(fall_time); - cur[idx]->decay_time(decay_time); + /* The logic devices have some uniform processing. Then + all may have output delays and output drive strength. */ + if (NetLogic*log = dynamic_cast (cur[idx])) { + log->rise_time(rise_time); + log->fall_time(fall_time); + log->decay_time(decay_time); - cur[idx]->pin(0).drive0(drive_type(strength0())); - cur[idx]->pin(0).drive1(drive_type(strength1())); + log->pin(0).drive0(drive_type(strength0())); + log->pin(0).drive1(drive_type(strength1())); + } + cur[idx]->set_line(*this); des->add_node(cur[idx]); } diff --git a/emit.cc b/emit.cc index c52190684..079a41c84 100644 --- a/emit.cc +++ b/emit.cc @@ -165,6 +165,11 @@ bool NetUserFunc::emit_node(struct target_t*tgt) const return tgt->net_function(this); } +bool NetTran::emit_node(struct target_t*tgt) const +{ + return tgt->tran(this); +} + bool NetBUFZ::emit_node(struct target_t*tgt) const { return tgt->bufz(this); diff --git a/ivl.def b/ivl.def index 8e151f590..48b798910 100644 --- a/ivl.def +++ b/ivl.def @@ -152,6 +152,8 @@ ivl_scope_port ivl_scope_ports ivl_scope_sigs ivl_scope_sig +ivl_scope_switch +ivl_scope_switches ivl_scope_time_precision ivl_scope_time_units ivl_scope_type @@ -216,6 +218,15 @@ ivl_stmt_parm_count ivl_stmt_rval ivl_stmt_sub_stmt +ivl_switch_a +ivl_switch_b +ivl_switch_basename +ivl_switch_enable +ivl_switch_scope +ivl_switch_type +ivl_switch_attr_cnt; +ivl_switch_attr_val; + ivl_udp_init ivl_udp_name ivl_udp_nin diff --git a/ivl_target.h b/ivl_target.h index 785fd0dcb..a39366a18 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -123,6 +123,9 @@ _BEGIN_DECL * ivl_process_t object holds one of these, but a statement may in * turn contain other statements. * + * ivl_switch_t + * Switches are the tran/tranif devices in the design. + * * -- A Note About Bit Sets -- * Some objects hold a value as an array of bits. In these cases there * is some method that retrieves the width of the value and another @@ -155,6 +158,7 @@ typedef struct ivl_parameter_s*ivl_parameter_t; typedef struct ivl_process_s *ivl_process_t; typedef struct ivl_scope_s *ivl_scope_t; typedef struct ivl_signal_s *ivl_signal_t; +typedef struct ivl_switch_s *ivl_switch_t; typedef struct ivl_memory_s *ivl_memory_t; /* DEPRECATED */ typedef struct ivl_statement_s*ivl_statement_t; @@ -226,6 +230,16 @@ typedef enum ivl_logic_e { IVL_LO_UDP = 21 } ivl_logic_t; +/* This is the type of a ivl_switch_t object */ +typedef enum ivl_switch_type_e { + IVL_SW_TRAN = 0, + IVL_SW_TRANIF0 = 1, + IVL_SW_TRANIF1 = 2, + IVL_SW_RTRAN = 3, + IVL_SW_RTRANIF0 = 4, + IVL_SW_RTRANIF1 = 5 +} ivl_switch_type_t; + /* This is the type of an LPM object. */ typedef enum ivl_lpm_type_e { IVL_LPM_ABS = 32, @@ -1501,6 +1515,8 @@ extern unsigned ivl_scope_ports(ivl_scope_t net); extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx); extern unsigned ivl_scope_sigs(ivl_scope_t net); extern ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx); +extern unsigned ivl_scope_switches(ivl_scope_t net); +extern ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx); extern ivl_scope_type_t ivl_scope_type(ivl_scope_t net); extern const char* ivl_scope_tname(ivl_scope_t net); extern int ivl_scope_time_precision(ivl_scope_t net); @@ -1826,6 +1842,42 @@ extern ivl_expr_t ivl_stmt_rval(ivl_statement_t net); IVL_ST_WAIT, IVL_ST_WHILE */ extern ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net); +/* SWITCHES + * + * The switches represent the tran devices in the design. + * + * FUNCTION SUMMARY + * + * ivl_switch_type + * Return the enumerated value that is the type of the switch. + * + * ivl_switch_basename + * This is the name given to the device in the source code. + * + * ivl_switch_scope + * The scope where the switch device appears. + * + * ivl_switch_a + * ivl_switch_b + * The a and b ports are the two ports of the switch. + * + * ivl_switch_enable + * If the device has an enable (tranifX) then this is the enable + * port. + * + * SEMANTIC NOTES + * The a/b ports can be any type, but the types must exactly + * match. The enable must be a scalar. + */ +extern ivl_switch_type_t ivl_switch_type(ivl_switch_t net); +extern const char*ivl_switch_basename(ivl_switch_t net); +extern ivl_scope_t ivl_switch_scope(ivl_switch_t net); +extern ivl_nexus_t ivl_switch_a(ivl_switch_t net); +extern ivl_nexus_t ivl_switch_b(ivl_switch_t net); +extern ivl_nexus_t ivl_switch_enable(ivl_switch_t net); + +extern unsigned ivl_switch_attr_cnt(ivl_switch_t net); +extern ivl_attribute_t ivl_switch_attr_val(ivl_switch_t net, unsigned idx); #if defined(__MINGW32__) || defined (__CYGWIN32__) # define DLLEXPORT __declspec(dllexport) diff --git a/net_tran.cc b/net_tran.cc new file mode 100644 index 000000000..88067769b --- /dev/null +++ b/net_tran.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "config.h" + +# include + +# include +# include +# include "compiler.h" +# include "netlist.h" +# include "netmisc.h" +# include "ivl_assert.h" + +static bool has_enable(ivl_switch_type_t tt) +{ + switch (tt) { + case IVL_SW_TRANIF0: + case IVL_SW_TRANIF1: + case IVL_SW_RTRANIF0: + case IVL_SW_RTRANIF1: + return true; + default: + return false; + } +} + +NetTran::NetTran(NetScope*scope, perm_string n, ivl_switch_type_t tt) +: NetNode(scope, n, has_enable(tt)? 3 : 2) +{ + 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); + if (pin_count() == 3) { + pin(2).set_dir(Link::INPUT); + pin(2).set_name(perm_string::literal("E"), 0); + } +} + +NetTran::~NetTran() +{ +} diff --git a/netlist.h b/netlist.h index 691311301..191d91e08 100644 --- a/netlist.h +++ b/netlist.h @@ -1359,6 +1359,21 @@ class NetSysFunc : public NetNode { const struct sfunc_return_type*def_; }; +class NetTran : public NetNode { + + public: + NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type); + ~NetTran(); + + ivl_switch_type_t type() const { return type_; } + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + ivl_switch_type_t type_; +}; + /* ========= * There are cases where expressions need to be represented. The * NetExpr class is the root of a hierarchy that serves that purpose. diff --git a/t-dll-api.cc b/t-dll-api.cc index b7eb79e26..aa2733854 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -1627,6 +1627,19 @@ extern "C" ivl_signal_t ivl_scope_sig(ivl_scope_t net, unsigned idx) return net->sigs_[idx]; } +extern "C" unsigned ivl_scope_switches(ivl_scope_t net) +{ + assert(net); + return net->switches.size(); +} + +extern "C" ivl_switch_t ivl_scope_switch(ivl_scope_t net, unsigned idx) +{ + assert(net); + assert(idx < net->switches.size()); + return net->switches[idx]; +} + extern "C" int ivl_scope_time_precision(ivl_scope_t net) { assert(net); @@ -2143,3 +2156,28 @@ extern "C" ivl_statement_t ivl_stmt_sub_stmt(ivl_statement_t net) return 0; } + +extern "C" const char*ivl_switch_basename(ivl_switch_t net) +{ + return net->name; +} + +extern "C" ivl_switch_type_t ivl_switch_type(ivl_switch_t net) +{ + return net->type; +} + +extern "C" ivl_nexus_t ivl_switch_a(ivl_switch_t net) +{ + return net->pins[0]; +} + +extern "C" ivl_nexus_t ivl_switch_b(ivl_switch_t net) +{ + return net->pins[1]; +} + +extern "C" ivl_nexus_t ivl_switch_enable(ivl_switch_t net) +{ + return net->pins[2]; +} diff --git a/t-dll.cc b/t-dll.cc index c7c383342..15cc19eac 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -380,6 +380,19 @@ static void nexus_lpm_add(ivl_nexus_t nex, ivl_lpm_t net, unsigned pin, nex->ptrs_[top-1].l.lpm= net; } +static void nexus_switch_add(ivl_nexus_t nex, ivl_switch_t net, unsigned pin) +{ + unsigned top = nex->nptr_ + 1; + nex->ptrs_ = (struct ivl_nexus_ptr_s*) + realloc(nex->ptrs_, top*sizeof(struct ivl_nexus_ptr_s)); + nex->nptr_ = top; + + nex->ptrs_[top-1].type_= __NEXUS_PTR_SWI; + nex->ptrs_[top-1].drive0 = IVL_DR_HiZ; + nex->ptrs_[top-1].drive1 = IVL_DR_HiZ; + nex->ptrs_[top-1].pin_ = pin; + nex->ptrs_[top-1].l.swi= net; +} void scope_add_logic(ivl_scope_t scope, ivl_net_logic_t net) { @@ -431,6 +444,11 @@ static void scope_add_lpm(ivl_scope_t scope, ivl_lpm_t net) } } +static void scope_add_switch(ivl_scope_t scope, ivl_switch_t net) +{ + scope->switches.push_back(net); +} + ivl_parameter_t dll_target::scope_find_param(ivl_scope_t scope, const char*name) { @@ -621,6 +639,13 @@ int dll_target::end_design(const Design*) return rc; } +void dll_target::switch_attributes(struct ivl_switch_s *obj, + const NetNode*net) +{ + obj->nattr = net->attr_cnt(); + obj->attr = fill_in_attributes(net); +} + void dll_target::logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net) { @@ -1008,6 +1033,42 @@ void dll_target::logic(const NetLogic*net) scope_add_logic(scope, obj); } +bool dll_target::tran(const NetTran*net) +{ + struct ivl_switch_s*obj = new struct ivl_switch_s; + obj->type = net->type(); + obj->name = net->name(); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + + const Nexus*nex; + + nex = net->pin(0).nexus(); + assert(nex->t_cookie()); + obj->pins[0] = nex->t_cookie(); + + nex = net->pin(1).nexus(); + assert(nex->t_cookie()); + obj->pins[1] = nex->t_cookie(); + + nexus_switch_add(obj->pins[0], obj, 0); + nexus_switch_add(obj->pins[1], obj, 1); + + if (net->pin_count() > 2) { + nex = net->pin(2).nexus(); + assert(nex->t_cookie()); + obj->pins[2] = nex->t_cookie(); + nexus_switch_add(obj->pins[2], obj, 2); + } else { + obj->pins[2] = 0; + } + + switch_attributes(obj, net); + scope_add_switch(obj->scope, obj); + + return true; +} + bool dll_target::sign_extend(const NetSignExtend*net) { struct ivl_lpm_s*obj = new struct ivl_lpm_s; diff --git a/t-dll.h b/t-dll.h index 76b2443f5..247a5dae7 100644 --- a/t-dll.h +++ b/t-dll.h @@ -23,6 +23,7 @@ # include "ivl_target.h" # include "StringHeap.h" # include "netlist.h" +# include #if defined(__MINGW32__) #include @@ -67,6 +68,7 @@ struct dll_target : public target_t, public expr_scan_t { bool bufz(const NetBUFZ*); void event(const NetEvent*); void logic(const NetLogic*); + bool tran(const NetTran*); bool ureduce(const NetUReduce*); void net_case_cmp(const NetCaseCmp*); void udp(const NetUDP*); @@ -146,6 +148,7 @@ struct dll_target : public target_t, public expr_scan_t { ivl_scope_t lookup_scope_(const NetScope*scope); ivl_attribute_s* fill_in_attributes(const Attrib*net); + void switch_attributes(struct ivl_switch_s *obj, const NetNode*net); void logic_attributes(struct ivl_net_logic_s *obj, const NetNode*net); private: @@ -445,6 +448,19 @@ struct ivl_net_logic_s { ivl_expr_t delay[3]; }; +struct ivl_switch_s { + ivl_switch_type_t type; + + perm_string name; + ivl_scope_t scope; + + struct ivl_attribute_s*attr; + unsigned nattr; + + ivl_nexus_t pins[3]; + perm_string file; + unsigned lineno; +}; /* * UDP definition. @@ -481,12 +497,14 @@ struct ivl_nexus_ptr_s { ivl_net_logic_t log; /* type 1 */ ivl_net_const_t con; /* type 2 */ ivl_lpm_t lpm; /* type 3 */ + ivl_switch_t swi; /* type 4 */ } l; }; # define __NEXUS_PTR_SIG 0 # define __NEXUS_PTR_LOG 1 # define __NEXUS_PTR_CON 2 # define __NEXUS_PTR_LPM 3 +# define __NEXUS_PTR_SWI 4 /* * NOTE: ONLY allocate ivl_nexus_s objects with the included "new" operator. @@ -567,6 +585,8 @@ struct ivl_scope_s { unsigned ports; ivl_signal_t*port; + std::vectorswitches; + signed int time_precision :8; signed int time_units :8; @@ -730,4 +750,10 @@ static inline void FILE_NAME(ivl_scope_t scope, const NetScope*info) scope->def_lineno = info->get_def_lineno(); } +static inline void FILE_NAME(ivl_switch_t net, const LineInfo*info) +{ + net->file = info->get_file(); + net->lineno = info->get_lineno(); +} + #endif diff --git a/target.cc b/target.cc index 379a91754..e474c7cf7 100644 --- a/target.cc +++ b/target.cc @@ -61,6 +61,13 @@ void target_t::logic(const NetLogic*) "Unhandled logic gate" << endl; } +bool target_t::tran(const NetTran*) +{ + cerr << "target (" << typeid(*this).name() << "): " + << "TRAN devices not supported." << endl; + return false; +} + bool target_t::bufz(const NetBUFZ*) { cerr << "target (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index c68ffc2f0..d002a9797 100644 --- a/target.h +++ b/target.h @@ -86,6 +86,7 @@ struct target_t { /* Output a gate (called for each gate) */ virtual void logic(const NetLogic*); + virtual bool tran(const NetTran*); virtual bool ureduce(const NetUReduce*); /* unary reduction operator */ virtual bool bufz(const NetBUFZ*); virtual void udp(const NetUDP*); diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index fd726431d..679226758 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -50,7 +50,7 @@ dep: $(CC) $(CPPFLAGS) $(CFLAGS) -MD -c $< -o $*.o mv $*.d dep -O = stub.o expression.o statement.o +O = stub.o expression.o statement.o switches.o ifeq (@WIN32@,yes) TGTLDFLAGS=-L.. -livl diff --git a/tgt-stub/priv.h b/tgt-stub/priv.h index 35ff52750..30f2eaf7d 100644 --- a/tgt-stub/priv.h +++ b/tgt-stub/priv.h @@ -35,6 +35,15 @@ extern FILE*out; */ extern int stub_errors; +/* + * This function finds the vector width of a signal. It relies on the + * assumption that all the signal inputs to the nexus have the same + * width. The ivl_target API should assert that condition. + */ +extern unsigned width_of_nexus(ivl_nexus_t nex); + +extern ivl_variable_type_t type_of_nexus(ivl_nexus_t nex); + /* * Show the details of the expression. */ @@ -45,6 +54,8 @@ extern void show_expression(ivl_expr_t net, unsigned ind); */ extern void show_statement(ivl_statement_t net, unsigned ind); +extern void show_switch(ivl_switch_t net); + /* */ extern const char*data_type_string(ivl_variable_type_t vtype); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 7b455d171..5d390800f 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1478,6 +1478,9 @@ static int show_scope(ivl_scope_t net, void*x) for (idx = 0 ; idx < ivl_scope_lpms(net) ; idx += 1) show_lpm(ivl_scope_lpm(net, idx)); + for (idx = 0 ; idx < ivl_scope_switches(net) ; idx += 1) + show_switch(ivl_scope_switch(net, idx)); + switch (ivl_scope_type(net)) { case IVL_SCT_FUNCTION: case IVL_SCT_TASK: diff --git a/tgt-stub/switches.c b/tgt-stub/switches.c new file mode 100644 index 000000000..79dac554a --- /dev/null +++ b/tgt-stub/switches.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2008 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + + +# include "config.h" +# include "priv.h" +# include +# include +# include + +void show_switch(ivl_switch_t net) +{ + const char*name = ivl_switch_basename(net); + int has_enable = 0; + + switch (ivl_switch_type(net)) { + case IVL_SW_TRAN: + fprintf(out, " tran %s", name); + break; + case IVL_SW_RTRAN: + fprintf(out, " rtran %s", name); + break; + case IVL_SW_TRANIF0: + fprintf(out, " tranif0 %s", name); + has_enable = 1; + break; + case IVL_SW_RTRANIF0: + fprintf(out, " rtranif0 %s", name); + has_enable = 1; + break; + case IVL_SW_TRANIF1: + fprintf(out, " tranif1 %s", name); + has_enable = 1; + break; + case IVL_SW_RTRANIF1: + fprintf(out, " rtranif1 %s", name); + has_enable = 1; + break; + } + + fprintf(out, "\n"); + + 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; + fprintf(out, " A: %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; + fprintf(out, " B: %s \n", nex_name, data_type_string(nex_type_b)); + + /* The A/B pins of the switch must be present, and must match. */ + if (nex_type_a == IVL_VT_NO_TYPE) { + fprintf(out, " A: ERROR: Type missing for pin A\n"); + stub_errors += 1; + } + if (nex_type_b == IVL_VT_NO_TYPE) { + fprintf(out, " B: ERROR: Type missing for pin B\n"); + stub_errors += 1; + } + if (nex_type_a != nex_type_b) { + fprintf(out, " A/B: ERROR: Type mismatch between pins A and B\n"); + stub_errors += 1; + } + + if (has_enable) { + nex = ivl_switch_enable(net); + nex_name = nex? ivl_nexus_name(nex) : ""; + fprintf(out, " E: %s\n", nex_name); + if (width_of_nexus(nex) != 1) { + fprintf(out, " E: ERROR: Nexus width is %u\n", + width_of_nexus(nex)); + } + } +}