From ec773fe8cf0188019af8714710b8720684fa4c1a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 21:42:52 -0700 Subject: [PATCH 1/5] Elaborate tran devices The tran devices include tran, rtran, tranif0/1 and rtranif0/1. These are all elaborated as options on a NetTran device. It is still not clear the best way to present tran devices via the ivl_target.h API. --- Makefile.in | 2 +- design_dump.cc | 11 +++++++ elaborate.cc | 78 ++++++++++++++++++++++++++++++++++++++++++++++---- emit.cc | 5 ++++ net_tran.cc | 44 ++++++++++++++++++++++++++++ netlist.h | 14 +++++++++ t-dll.cc | 7 +++++ t-dll.h | 1 + target.cc | 7 +++++ target.h | 1 + 10 files changed, 163 insertions(+), 7 deletions(-) create mode 100644 net_tran.cc diff --git a/Makefile.in b/Makefile.in index 6e4c96ab3..04422581b 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..1d408ffd8 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -611,6 +611,17 @@ void NetTaskDef::dump(ostream&o, unsigned ind) const o << setw(ind) << "" << "endtask" << endl; } +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; + + 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..d4ca9b9df 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, false, 0); + } + 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, true, 0); + 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, false, -1); + } + 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, true, -1); + } + 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, false, 1); + } + 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, true, 1); + } + 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/net_tran.cc b/net_tran.cc new file mode 100644 index 000000000..60be74ad2 --- /dev/null +++ b/net_tran.cc @@ -0,0 +1,44 @@ +/* + * 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" + +NetTran::NetTran(NetScope*scope, perm_string n, bool resistive, int enable) +: NetNode(scope, n, enable? 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) { + 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..da6bb196a 100644 --- a/netlist.h +++ b/netlist.h @@ -1359,6 +1359,20 @@ class NetSysFunc : public NetNode { const struct sfunc_return_type*def_; }; +class NetTran : public NetNode { + + public: + NetTran(NetScope*scope, perm_string n, bool resistive, int enable); + ~NetTran(); + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + + private: + bool resistive_; + bool enable_; +}; + /* ========= * 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.cc b/t-dll.cc index c7c383342..4288f7477 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1008,6 +1008,13 @@ void dll_target::logic(const NetLogic*net) scope_add_logic(scope, obj); } +bool dll_target::tran(const NetTran*net) +{ + cerr << net->get_fileline() << ": sorry: " + << "trans devices not supported." << endl; + return false; +} + 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..ae0ce2986 100644 --- a/t-dll.h +++ b/t-dll.h @@ -67,6 +67,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*); 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*); From ec266ff52e0986ab8f742f2a8abecb6abe19bd47 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 19 May 2008 21:55:53 -0700 Subject: [PATCH 2/5] Make sure expressions of value_ranges are initialized. --- elab_scope.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/elab_scope.cc b/elab_scope.cc index 00f564b10..0dee90151 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -93,11 +93,15 @@ void Module::elaborate_parm_item_(perm_string name, const param_expr_t&cur, if (range->low_expr) { tmp->low_expr = elab_and_eval(des, scope, range->low_expr, -1); ivl_assert(*range->low_expr, tmp->low_expr); + } else { + tmp->low_expr = 0; } if (range->high_expr) { tmp->high_expr = elab_and_eval(des, scope, range->high_expr, -1); ivl_assert(*range->high_expr, tmp->high_expr); + } else { + tmp->high_expr = 0; } tmp->next = range_list; From 88313670c046f0a11f29940357c26d1f94f80c3a Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 20 May 2008 20:32:42 -0700 Subject: [PATCH 3/5] Clear up some poor pointer management. The expression for a paramter value was not well managed, given that the eval_expr() function replaces pointers. Clear things up a bit. --- net_design.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/net_design.cc b/net_design.cc index d180f7160..595a90817 100644 --- a/net_design.cc +++ b/net_design.cc @@ -288,10 +288,15 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) eval_expr(expr); + /* The eval_expr may delete any replace the expr pointer, so the + second.expr value cannot be relied on. Might as well replace + it now with the expression that we evaluated. */ + (*cur).second.expr = expr; + switch (expr->expr_type()) { case IVL_VT_REAL: if (! dynamic_cast(expr)) { - cerr << (*cur).second.expr->get_fileline() + cerr << expr->get_fileline() << ": internal error: " << "unable to evaluate real parameter value: " << *expr << endl; @@ -303,7 +308,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) case IVL_VT_LOGIC: case IVL_VT_BOOL: if (! dynamic_cast(expr)) { - cerr << (*cur).second.expr->get_fileline() + cerr << expr->get_fileline() << ": internal error: " << "unable to evaluate parameter " << (*cur).first @@ -314,7 +319,7 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) break; default: - cerr << (*cur).second.expr->get_fileline() + cerr << expr->get_fileline() << ": internal error: " << "unhandled expression type?" << endl; des->errors += 1; @@ -346,10 +351,6 @@ void NetScope::evaluate_parameter_logic_(Design*des, param_ref_t cur) } } - // Done fiddling with the expression, save it back in the parameter. - expr->set_line(*(*cur).second.expr); - (*cur).second.expr = expr; - // If there are no value ranges to test the value against, // then we are done. if ((*cur).second.range == 0) { From e59f28d659c5d10ddc6b52eab70f5f783415936f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 22 May 2008 18:40:29 -0700 Subject: [PATCH 4/5] work interrupted --- design_dump.cc | 31 ++++++++++++++++++++++++++----- elaborate.cc | 12 ++++++------ ivl_target.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ net_tran.cc | 19 ++++++++++++++++--- netlist.h | 5 ++--- t-dll.h | 11 +++++++++++ 6 files changed, 108 insertions(+), 17 deletions(-) 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_target.h b/ivl_target.h index 785fd0dcb..c0c16c2a2 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, @@ -1826,6 +1840,39 @@ 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); #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..c7fabd138 100644 --- a/netlist.h +++ b/netlist.h @@ -1362,15 +1362,14 @@ 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(); 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.h b/t-dll.h index ae0ce2986..3bfc4915e 100644 --- a/t-dll.h +++ b/t-dll.h @@ -446,6 +446,17 @@ 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]; +}; /* * UDP definition. From ca756f3ec38e84da89ceb3614fef1a6f461c83fc Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Fri, 23 May 2008 20:53:10 -0700 Subject: [PATCH 5/5] Bring switch information out to the ivl_target API. This involves defining the API for switches and cleaning up the elaborated form to match the defined ivl_target API. Also add t-dll code to support the ivl_switch_t functions, and add stub code that checks the results. --- design_dump.cc | 31 ++++++++++++--- elaborate.cc | 12 +++--- ivl.def | 11 ++++++ ivl_target.h | 52 +++++++++++++++++++++++++ net_tran.cc | 19 +++++++-- netlist.h | 7 ++-- t-dll-api.cc | 38 ++++++++++++++++++ t-dll.cc | 60 +++++++++++++++++++++++++++-- t-dll.h | 25 ++++++++++++ tgt-stub/Makefile.in | 2 +- tgt-stub/priv.h | 11 ++++++ tgt-stub/stub.c | 3 ++ tgt-stub/switches.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 342 insertions(+), 21 deletions(-) create mode 100644 tgt-stub/switches.c 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)); + } + } +}