diff --git a/design_dump.cc b/design_dump.cc index 1d408ffd8..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()) { @@ -613,11 +638,7 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const void NetTran::dump_node(ostream&o, unsigned ind) const { - const char*r = resistive_? "r" : ""; - const char*ifx = enable_==0? "" : enable_>0? "if1" : "if0"; - - o << setw(ind) << "" << r << "tran" << ifx << " " << name() << endl; - + o << setw(ind) << "" << type_ << " " << name() << endl; dump_node_pins(o, ind+4); dump_obj_attr(o, ind+4); } diff --git a/elaborate.cc b/elaborate.cc index d4ca9b9df..d7180f4b5 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -666,7 +666,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, false, 0); + cur[idx] = new NetTran(scope, inm, IVL_SW_TRAN); } break; case RTRAN: @@ -676,7 +676,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, true, 0); + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRAN); return; } break; @@ -687,7 +687,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, false, -1); + cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF0); } break; case RTRANIF0: @@ -697,7 +697,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, true, -1); + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF0); } break; case TRANIF1: @@ -707,7 +707,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, false, 1); + cur[idx] = new NetTran(scope, inm, IVL_SW_TRANIF1); } break; case RTRANIF1: @@ -717,7 +717,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const des->errors += 1; return; } else { - cur[idx] = new NetTran(scope, inm, true, 1); + cur[idx] = new NetTran(scope, inm, IVL_SW_RTRANIF1); } break; default: 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 index 60be74ad2..88067769b 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -28,12 +28,25 @@ # include "netmisc.h" # include "ivl_assert.h" -NetTran::NetTran(NetScope*scope, perm_string n, bool resistive, int enable) -: NetNode(scope, n, enable? 3 : 2) +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 (enable) { + if (pin_count() == 3) { pin(2).set_dir(Link::INPUT); pin(2).set_name(perm_string::literal("E"), 0); } diff --git a/netlist.h b/netlist.h index da6bb196a..191d91e08 100644 --- a/netlist.h +++ b/netlist.h @@ -1362,15 +1362,16 @@ class NetSysFunc : public NetNode { class NetTran : public NetNode { public: - NetTran(NetScope*scope, perm_string n, bool resistive, int enable); + 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: - bool resistive_; - bool enable_; + ivl_switch_type_t type_; }; /* ========= 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 4288f7477..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) { @@ -1010,9 +1035,38 @@ void dll_target::logic(const NetLogic*net) bool dll_target::tran(const NetTran*net) { - cerr << net->get_fileline() << ": sorry: " - << "trans devices not supported." << endl; - return false; + 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) diff --git a/t-dll.h b/t-dll.h index ae0ce2986..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 @@ -147,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: @@ -446,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. @@ -482,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. @@ -568,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; @@ -731,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/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index b93a8452b..f8a4ebe82 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -51,7 +51,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)); + } + } +}