From 5aa810dde7e1999fb57e6088c462b31bb51fea8f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 21 Oct 2008 22:15:49 -0700 Subject: [PATCH 01/19] Infrastructure for elaborating analog statements. Put together the infrastructure for elaborating analog statements, including create the NetAnalogTop objects that hold analog statements and are in turn held by the design. While doing this, clean up the various unique initial/always enumerations to use the ivl_process_type_t type. --- AStatement.h | 20 ++++++++++++--- Makefile.in | 5 ++-- Statement.h | 9 +++---- async.cc | 33 ++----------------------- design_dump.cc | 4 +-- elab_scope.cc | 10 ++++++++ elab_sig_analog.cc | 30 +++++++++++++++++++++++ elaborate.cc | 20 +++++++-------- elaborate_analog.cc | 60 +++++++++++++++++++++++++++++++++++++++++++++ net_design.cc | 7 +++++- netlist.cc | 12 ++++++++- netlist.h | 40 ++++++++++++++++++++++++++---- parse.y | 6 ++--- pform.cc | 4 +-- pform.h | 4 +-- pform_analog.cc | 2 +- pform_dump.cc | 28 ++++++++++++--------- syn-rules.y | 2 +- sync.cc | 22 ++--------------- synth.cc | 4 +-- t-dll-proc.cc | 12 ++------- 21 files changed, 219 insertions(+), 115 deletions(-) create mode 100644 elab_sig_analog.cc create mode 100644 elaborate_analog.cc diff --git a/AStatement.h b/AStatement.h index 0b1b60396..b386b3398 100644 --- a/AStatement.h +++ b/AStatement.h @@ -20,11 +20,15 @@ */ # include +# include "ivl_target.h" # include "StringHeap.h" # include "LineInfo.h" # include "PExpr.h" class PExpr; +class NetAnalog; +class NetScope; +class Design; class AStatement : public LineInfo { @@ -33,6 +37,11 @@ class AStatement : public LineInfo { virtual ~AStatement() =0; virtual void dump(ostream&out, unsigned ind) const; + virtual NetAnalog* elaborate(Design*des, NetScope*scope) const; + virtual void elaborate_scope(Design*des, NetScope*scope) const; + virtual void elaborate_sig(Design*des, NetScope*scope) const; + + map attributes; private: // not implemented AStatement(const AStatement&); @@ -65,20 +74,23 @@ class AContrib : public AStatement { class AProcess : public LineInfo { public: - enum Type { PR_INITIAL, PR_ALWAYS }; - - AProcess(Type t, AStatement*st) + AProcess(ivl_process_type_t t, AStatement*st) : type_(t), statement_(st) { } ~AProcess(); + bool elaborate(Design*des, NetScope*scope) const; + + ivl_process_type_t type() const { return type_; } + AStatement*statement() { return statement_; } + map attributes; // Dump the analog process void dump(ostream&out, unsigned ind) const; private: - Type type_; + ivl_process_type_t type_; AStatement*statement_; private: // not implemented diff --git a/Makefile.in b/Makefile.in index b5fc3d3d2..47c1ad1f4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -116,9 +116,10 @@ distclean: clean TT = t-dll.o t-dll-api.o t-dll-expr.o t-dll-proc.o FF = cprop.o nodangle.o synth.o synth2.o syn-rules.o -O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o elab_expr.o \ +O = main.o async.o design_dump.o discipline.o dup_expr.o \ +elaborate.o elab_expr.o elaborate_analog.o \ elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \ -elab_sig.o emit.o eval.o eval_attrib.o \ +elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ 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_func.o \ diff --git a/Statement.h b/Statement.h index 8890f938e..e99833131 100644 --- a/Statement.h +++ b/Statement.h @@ -20,6 +20,7 @@ */ # include +# include "ivl_target.h" # include "svector.h" # include "StringHeap.h" # include "PDelays.h" @@ -46,16 +47,14 @@ class NetScope; class PProcess : public LineInfo { public: - enum Type { PR_INITIAL, PR_ALWAYS }; - - PProcess(Type t, Statement*st) + PProcess(ivl_process_type_t t, Statement*st) : type_(t), statement_(st) { } virtual ~PProcess(); bool elaborate(Design*des, NetScope*scope) const; - Type type() const { return type_; } + ivl_process_type_t type() const { return type_; } Statement*statement() { return statement_; } map attributes; @@ -63,7 +62,7 @@ class PProcess : public LineInfo { virtual void dump(ostream&out, unsigned ind) const; private: - Type type_; + ivl_process_type_t type_; Statement*statement_; }; diff --git a/async.cc b/async.cc index 3d283b9c6..0db7d7bec 100644 --- a/async.cc +++ b/async.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: async.cc,v 1.7 2004/01/18 23:26:54 steve Exp $" -#endif # include "config.h" @@ -87,34 +84,8 @@ bool NetProc::is_asynchronous() bool NetProcTop::is_asynchronous() { - if (type_ == NetProcTop::KINITIAL) + if (type_ == IVL_PR_INITIAL) return false; return statement_->is_asynchronous(); } - -/* - * $Log: async.cc,v $ - * Revision 1.7 2004/01/18 23:26:54 steve - * The is_combinational function really need not recurse. - * - * Revision 1.6 2003/12/20 00:33:39 steve - * More thorough check that NetEvWait is asynchronous. - * - * Revision 1.5 2003/09/04 20:28:05 steve - * Support time0 resolution of combinational threads. - * - * Revision 1.4 2002/08/18 22:07:16 steve - * Detect temporaries in sequential block synthesis. - * - * Revision 1.3 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.2 2002/07/04 00:24:16 steve - * initial statements are not asynchronous. - * - * Revision 1.1 2002/06/30 02:21:31 steve - * Add structure for asynchronous logic synthesis. - * - */ - diff --git a/design_dump.cc b/design_dump.cc index 3aabb3fdd..1ffcd10d7 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -702,11 +702,11 @@ void NetUDP::dump_node(ostream&o, unsigned ind) const void NetProcTop::dump(ostream&o, unsigned ind) const { switch (type_) { - case NetProcTop::KINITIAL: + case IVL_PR_INITIAL: o << "initial /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; break; - case NetProcTop::KALWAYS: + case IVL_PR_ALWAYS: o << "always /* " << get_fileline() << " in " << scope_path(scope_) << " */" << endl; break; diff --git a/elab_scope.cc b/elab_scope.cc index d4040375c..0e2820261 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -40,6 +40,7 @@ # include "PTask.h" # include "PWire.h" # include "Statement.h" +# include "AStatement.h" # include "netlist.h" # include "util.h" # include @@ -1242,3 +1243,12 @@ void PWhile::elaborate_scope(Design*des, NetScope*scope) const if (statement_) statement_ -> elaborate_scope(des, scope); } + +/* + * The base statement does not have sub-statements and does not + * introduce any scope, so this is a no-op. + */ +void AStatement::elaborate_scope(Design*, NetScope*) const +{ +} + diff --git a/elab_sig_analog.cc b/elab_sig_analog.cc new file mode 100644 index 000000000..d7da16fcf --- /dev/null +++ b/elab_sig_analog.cc @@ -0,0 +1,30 @@ +/* + * 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 "AStatement.h" + +# include +# include + +void AStatement::elaborate_sig(Design*des, NetScope*scope) const +{ +} + diff --git a/elaborate.cc b/elaborate.cc index 503b04b54..1adb217d7 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3502,15 +3502,7 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const return false; } - NetProcTop*top=0; - switch (type()) { - case PProcess::PR_INITIAL: - top = new NetProcTop(scope, NetProcTop::KINITIAL, cur); - break; - case PProcess::PR_ALWAYS: - top = new NetProcTop(scope, NetProcTop::KALWAYS, cur); - break; - } + NetProcTop*top=new NetProcTop(scope, type(), cur); ivl_assert(*this, top); // Evaluate the attributes for this process, if there @@ -3535,7 +3527,7 @@ bool PProcess::elaborate(Design*des, NetScope*scope) const gets into its wait statement before non-combinational code is executed. */ do { - if (top->type() != NetProcTop::KALWAYS) + if (top->type() != IVL_PR_ALWAYS) break; NetEvWait*st = dynamic_cast(top->statement()); @@ -3958,6 +3950,12 @@ bool PScope::elaborate_behaviors_(Design*des, NetScope*scope) const result_flag &= (*st)->elaborate(des, scope); } + for (list::const_iterator st = analog_behaviors.begin() + ; st != analog_behaviors.end() ; st ++ ) { + + result_flag &= (*st)->elaborate(des, scope); + } + return result_flag; } @@ -4045,7 +4043,7 @@ bool Design::check_always_delay() const * a runtime infinite loop will happen. If we possible have some * delay then print a warning that an infinite loop is possible. */ - if (pr->type() == NetProcTop::KALWAYS) { + if (pr->type() == IVL_PR_ALWAYS) { DelayType dly_type = pr->statement()->delay_type(); if (dly_type == NO_DELAY || dly_type == ZERO_DELAY) { diff --git a/elaborate_analog.cc b/elaborate_analog.cc new file mode 100644 index 000000000..0688aa2b2 --- /dev/null +++ b/elaborate_analog.cc @@ -0,0 +1,60 @@ +/* + * 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 "AStatement.h" +# include "util.h" + +# include + +NetAnalog* AStatement::elaborate(Design*des, NetScope*scope) const +{ + cerr << get_fileline() << ": sorry: I don't yet know how to elaborate" + << " his kind of analog statement." << endl; + cerr << get_fileline() << ": : typeid = " << typeid(*this).name() << endl; + return 0; +} + +bool AProcess::elaborate(Design*des, NetScope*scope) const +{ + NetAnalog*statement = statement_->elaborate(des, scope); + if (statement == 0) + return false; + + NetAnalogTop*top = new NetAnalogTop(scope, type_, statement); + + // Evaluate the attributes for this process, if there + // are any. These attributes are to be attached to the + // NetProcTop object. + struct attrib_list_t*attrib_list = 0; + unsigned attrib_list_n = 0; + attrib_list = evaluate_attributes(attributes, attrib_list_n, des, scope); + + for (unsigned adx = 0 ; adx < attrib_list_n ; adx += 1) + top->attribute(attrib_list[adx].key, + attrib_list[adx].val); + + delete[]attrib_list; + + top->set_line(*this); + des->add_process(top); + + return true; +} diff --git a/net_design.cc b/net_design.cc index a8434128e..1ee8a4e1f 100644 --- a/net_design.cc +++ b/net_design.cc @@ -36,7 +36,7 @@ # include "ivl_assert.h" Design:: Design() -: errors(0), nodes_(0), procs_(0), lcounter_(0) + : errors(0), nodes_(0), procs_(0), aprocs_(0), lcounter_(0) { procs_idx_ = 0; des_precision_ = 0; @@ -764,6 +764,11 @@ void Design::add_process(NetProcTop*pro) procs_ = pro; } +void Design::add_process(NetAnalogTop*pro) +{ + pro->next_ = aprocs_; + aprocs_ = pro; +} void Design::delete_process(NetProcTop*top) { assert(top); diff --git a/netlist.cc b/netlist.cc index 9cd711a8c..f23fbbe23 100644 --- a/netlist.cc +++ b/netlist.cc @@ -850,7 +850,7 @@ NetProc::~NetProc() { } -NetProcTop::NetProcTop(NetScope*s, Type t, NetProc*st) +NetProcTop::NetProcTop(NetScope*s, ivl_process_type_t t, NetProc*st) : type_(t), statement_(st), scope_(s) { } @@ -875,6 +875,16 @@ NetScope* NetProcTop::scope() return scope_; } +NetAnalogTop::NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetAnalog*st) +: type_(t), statement_(st), scope_(scope) +{ + next_ = 0; +} + +NetAnalogTop::~NetAnalogTop() +{ +} + const NetScope* NetProcTop::scope() const { return scope_; diff --git a/netlist.h b/netlist.h index 9eaf5cce8..63f9f032a 100644 --- a/netlist.h +++ b/netlist.h @@ -3044,12 +3044,10 @@ class NetWhile : public NetProc { class NetProcTop : public LineInfo, public Attrib { public: - enum Type { KINITIAL, KALWAYS }; - - NetProcTop(NetScope*s, Type t, class NetProc*st); + NetProcTop(NetScope*s, ivl_process_type_t t, class NetProc*st); ~NetProcTop(); - Type type() const { return type_; } + ivl_process_type_t type() const { return type_; } NetProc*statement(); const NetProc*statement() const; @@ -3074,7 +3072,7 @@ class NetProcTop : public LineInfo, public Attrib { bool emit(struct target_t*tgt) const; private: - const Type type_; + const ivl_process_type_t type_; NetProc*const statement_; NetScope*scope_; @@ -3082,6 +3080,35 @@ class NetProcTop : public LineInfo, public Attrib { NetProcTop*next_; }; +class NetAnalog : public LineInfo, public Attrib { +}; + +class NetAnalogTop : public LineInfo, public Attrib { + + public: + NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetAnalog*st); + ~NetAnalogTop(); + + ivl_process_type_t type() const { return type_; } + + NetAnalog*statement(); + const NetAnalog*statement() const; + + NetScope*scope(); + const NetScope*scope() const; + + void dump(ostream&, unsigned ind) const; + bool emit(struct target_t*tgt) const; + + private: + const ivl_process_type_t type_; + NetAnalog* statement_; + + NetScope*scope_; + friend class Design; + NetAnalogTop*next_; +}; + /* * This class represents a binary operator, with the left and right * operands and a single character for the operator. The operator @@ -3822,6 +3849,7 @@ class Design { // PROCESSES void add_process(NetProcTop*); + void add_process(NetAnalogTop*); void delete_process(NetProcTop*); bool check_always_delay() const; @@ -3853,6 +3881,8 @@ class Design { NetProcTop*procs_; NetProcTop*procs_idx_; + NetAnalogTop*aprocs_; + map flags_; int des_precision_; diff --git a/parse.y b/parse.y index 99475d19c..d6c05e830 100644 --- a/parse.y +++ b/parse.y @@ -2093,16 +2093,16 @@ module_item /* Always and initial items are behavioral processes. */ | attribute_list_opt K_always statement - { PProcess*tmp = pform_make_behavior(PProcess::PR_ALWAYS, $3, $1); + { PProcess*tmp = pform_make_behavior(IVL_PR_ALWAYS, $3, $1); FILE_NAME(tmp, @2); } | attribute_list_opt K_initial statement - { PProcess*tmp = pform_make_behavior(PProcess::PR_INITIAL, $3, $1); + { PProcess*tmp = pform_make_behavior(IVL_PR_INITIAL, $3, $1); FILE_NAME(tmp, @2); } | attribute_list_opt K_analog analog_statement - { pform_make_analog_behavior(@2, AProcess::PR_ALWAYS, $3); } + { pform_make_analog_behavior(@2, IVL_PR_ALWAYS, $3); } /* The task declaration rule matches the task declaration header, then pushes the function scope. This causes the diff --git a/pform.cc b/pform.cc index 7c0427631..0cd16c451 100644 --- a/pform.cc +++ b/pform.cc @@ -1304,7 +1304,7 @@ void pform_make_reginit(const struct vlltype&li, FILE_NAME(lval, li); PAssign*ass = new PAssign(lval, expr, true); FILE_NAME(ass, li); - PProcess*top = new PProcess(PProcess::PR_INITIAL, ass); + PProcess*top = new PProcess(IVL_PR_INITIAL, ass); FILE_NAME(top, li); pform_put_behavior_in_scope(top); @@ -1947,7 +1947,7 @@ svector* pform_make_udp_input_ports(list*names) return out; } -PProcess* pform_make_behavior(PProcess::Type type, Statement*st, +PProcess* pform_make_behavior(ivl_process_type_t type, Statement*st, svector*attr) { PProcess*pp = new PProcess(type, st); diff --git a/pform.h b/pform.h index 5422e74a2..16ef2f9f9 100644 --- a/pform.h +++ b/pform.h @@ -311,7 +311,7 @@ extern void pform_module_specify_path(PSpecPath*obj); * pform_make_behavior creates processes that are declared with always * or initial items. */ -extern PProcess* pform_make_behavior(PProcess::Type, Statement*, +extern PProcess* pform_make_behavior(ivl_process_type_t, Statement*, svector*attr); extern svector* pform_make_udp_input_ports(list*); @@ -396,7 +396,7 @@ extern void pform_dump(ostream&out, const discipline_t*); /* ** pform_analog.cc */ extern void pform_make_analog_behavior(const struct vlltype&loc, - AProcess::Type type, AStatement*st); + ivl_process_type_t type, AStatement*st); extern AStatement*pform_contribution_statement(const struct vlltype&loc, PExpr*lval, PExpr*rval); diff --git a/pform_analog.cc b/pform_analog.cc index 55408452b..fe5489b44 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -31,7 +31,7 @@ AStatement* pform_contribution_statement(const struct vlltype&loc, return tmp; } -void pform_make_analog_behavior(const struct vlltype&loc, AProcess::Type pt, +void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t pt, AStatement*statement) { AProcess*proc = new AProcess(pt, statement); diff --git a/pform_dump.cc b/pform_dump.cc index a41b835d3..4283620e0 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -135,6 +135,18 @@ ostream& operator<< (ostream&o, const pform_name_t&that) return o; } +std::ostream& operator << (std::ostream&out, ivl_process_type_t pt) +{ + switch (pt) { + case IVL_PR_INITIAL: + out << "initial"; + break; + case IVL_PR_ALWAYS: + out << "always"; + break; + } + return out; +} std::ostream& operator << (std::ostream&out, ddomain_t dom) { @@ -900,16 +912,8 @@ void PWhile::dump(ostream&out, unsigned ind) const void PProcess::dump(ostream&out, unsigned ind) const { - switch (type_) { - case PProcess::PR_INITIAL: - out << setw(ind) << "" << "initial"; - break; - case PProcess::PR_ALWAYS: - out << setw(ind) << "" << "always"; - break; - } - - out << " /* " << get_fileline() << " */" << endl; + out << setw(ind) << "" << type_ + << " /* " << get_fileline() << " */" << endl; dump_attributes_map(out, attributes, ind+2); @@ -919,10 +923,10 @@ void PProcess::dump(ostream&out, unsigned ind) const void AProcess::dump(ostream&out, unsigned ind) const { switch (type_) { - case AProcess::PR_INITIAL: + case IVL_PR_INITIAL: out << setw(ind) << "" << "analog initial"; break; - case AProcess::PR_ALWAYS: + case IVL_PR_ALWAYS: out << setw(ind) << "" << "analog"; break; } diff --git a/syn-rules.y b/syn-rules.y index 78c4b4588..1a3f66ee3 100644 --- a/syn-rules.y +++ b/syn-rules.y @@ -335,7 +335,7 @@ static void syn_start_process(NetProcTop*t) last_ = first_; ptr_ = first_; - first_->token = (t->type() == NetProcTop::KALWAYS)? S_ALWAYS : S_INITIAL; + first_->token = (t->type() == IVL_PR_ALWAYS)? S_ALWAYS : S_INITIAL; first_->top = t; first_->next_ = 0; diff --git a/sync.cc b/sync.cc index 50454a787..b720dc6d5 100644 --- a/sync.cc +++ b/sync.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-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 @@ -16,9 +16,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ -#ifdef HAVE_CVS_IDENT -#ident "$Id: sync.cc,v 1.3 2002/09/24 00:58:35 steve Exp $" -#endif # include "config.h" @@ -59,23 +56,8 @@ bool NetEvWait::is_synchronous() bool NetProcTop::is_synchronous() { - if (type_ == NetProcTop::KINITIAL) + if (type_ == IVL_PR_INITIAL) return false; return statement_->is_synchronous(); } - -/* - * $Log: sync.cc,v $ - * Revision 1.3 2002/09/24 00:58:35 steve - * More detailed check of process edge events. - * - * Revision 1.2 2002/09/16 21:55:06 steve - * Reject multiple probes on synchronous logic. - * - * Revision 1.1 2002/09/16 00:30:33 steve - * Add to synth2 support for synthesis of - * synchronous logic. This includes DFF enables - * modeled by if/then/else. - * - */ diff --git a/synth.cc b/synth.cc index ac2aaeb87..6f2012290 100644 --- a/synth.cc +++ b/synth.cc @@ -131,10 +131,10 @@ void synth_f::process(class Design*des, class NetProcTop*top) { top_ = top; switch (top->type()) { - case NetProcTop::KALWAYS: + case IVL_PR_ALWAYS: proc_always_(des); break; - case NetProcTop::KINITIAL: + case IVL_PR_INITIAL: proc_initial_(des); break; } diff --git a/t-dll-proc.cc b/t-dll-proc.cc index f2031fb0b..13ac6240f 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -39,16 +39,8 @@ bool dll_target::process(const NetProcTop*net) ivl_process_t obj = (struct ivl_process_s*) calloc(1, sizeof(struct ivl_process_s)); - switch (net->type()) { - case NetProcTop::KINITIAL: - obj->type_ = IVL_PR_INITIAL; - break; - case NetProcTop::KALWAYS: - obj->type_ = IVL_PR_ALWAYS; - break; - default: - assert(0); - } + obj->type_ = net->type(); + FILE_NAME(obj, net); /* Save the scope of the process. */ From 68fbb94b3ace9b7c39e6155d347ba2f2bda834e4 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 22 Oct 2008 21:56:00 -0700 Subject: [PATCH 02/19] Basic elaboration of analog contribution statements. Get at least basic elaboration of analog processes and contribution statements. Bring the statements and analog statements together and net future elaboration work sort out which statements are valid in a given context. This makes sense because there really is a lot of syntactic overlap, and analog behavioral code is processed somewhat sequentially. --- AStatement.cc | 4 ---- AStatement.h | 28 ++++++---------------------- Makefile.in | 2 +- design_dump.cc | 28 ++++++++++++++++++++++++++++ elab_scope.cc | 9 --------- elab_sig_analog.cc | 4 ---- elaborate_analog.cc | 16 ++++++++++------ emit.cc | 9 +++++++++ net_analog.cc | 37 +++++++++++++++++++++++++++++++++++++ netlist.cc | 2 +- netlist.h | 29 ++++++++++++++++++++++------- parse.y | 3 +-- pform.h | 6 +++--- pform_analog.cc | 4 ++-- pform_dump.cc | 10 ---------- 15 files changed, 120 insertions(+), 71 deletions(-) create mode 100644 net_analog.cc diff --git a/AStatement.cc b/AStatement.cc index a3617d6bf..3cd9b0c4a 100644 --- a/AStatement.cc +++ b/AStatement.cc @@ -21,10 +21,6 @@ # include "AStatement.h" -AStatement::~AStatement() -{ -} - AContrib::AContrib(PExpr*lv, PExpr*rv) : lval_(lv), rval_(rv) { diff --git a/AStatement.h b/AStatement.h index b386b3398..a02e6d099 100644 --- a/AStatement.h +++ b/AStatement.h @@ -23,6 +23,7 @@ # include "ivl_target.h" # include "StringHeap.h" # include "LineInfo.h" +# include "Statement.h" # include "PExpr.h" class PExpr; @@ -30,36 +31,19 @@ class NetAnalog; class NetScope; class Design; -class AStatement : public LineInfo { - - public: - AStatement() { } - virtual ~AStatement() =0; - - virtual void dump(ostream&out, unsigned ind) const; - virtual NetAnalog* elaborate(Design*des, NetScope*scope) const; - virtual void elaborate_scope(Design*des, NetScope*scope) const; - virtual void elaborate_sig(Design*des, NetScope*scope) const; - - map attributes; - - private: // not implemented - AStatement(const AStatement&); - AStatement& operator= (const AStatement&); -}; - /* * A contribution statement is like an assignment: there is an l-value * expression and an r-value expression. The l-value is a branch probe * expression. */ -class AContrib : public AStatement { +class AContrib : public Statement { public: AContrib(PExpr*lval, PExpr*rval); ~AContrib(); virtual void dump(ostream&out, unsigned ind) const; + virtual NetProc* elaborate(Design*des, NetScope*scope) const; private: PExpr*lval_; @@ -74,7 +58,7 @@ class AContrib : public AStatement { class AProcess : public LineInfo { public: - AProcess(ivl_process_type_t t, AStatement*st) + AProcess(ivl_process_type_t t, Statement*st) : type_(t), statement_(st) { } ~AProcess(); @@ -82,7 +66,7 @@ class AProcess : public LineInfo { bool elaborate(Design*des, NetScope*scope) const; ivl_process_type_t type() const { return type_; } - AStatement*statement() { return statement_; } + Statement*statement() { return statement_; } map attributes; @@ -91,7 +75,7 @@ class AProcess : public LineInfo { private: ivl_process_type_t type_; - AStatement*statement_; + Statement*statement_; private: // not implemented AProcess(const AProcess&); diff --git a/Makefile.in b/Makefile.in index 47c1ad1f4..5e1a59a3d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -121,7 +121,7 @@ elaborate.o elab_expr.o elaborate_analog.o \ elab_lval.o elab_net.o elab_pexpr.o elab_scope.o \ elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ 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 \ +load_module.o netlist.o netmisc.o net_analog.o net_assign.o \ net_design.o net_event.o net_expr.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_tran.o net_udp.o pad_to_width.o \ diff --git a/design_dump.cc b/design_dump.cc index 1ffcd10d7..cf1b5790e 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -720,6 +720,23 @@ void NetProcTop::dump(ostream&o, unsigned ind) const statement_->dump(o, ind+2); } +void NetAnalogTop::dump(ostream&o, unsigned ind) const +{ + switch (type_) { + case IVL_PR_INITIAL: + o << "analog initial /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + + case IVL_PR_ALWAYS: + o << "analog /* " << get_fileline() << " in " + << scope_path(scope_) << " */" << endl; + break; + } + + statement_->dump(o, ind+2); +} + void NetAlloc::dump(ostream&o, unsigned ind) const { o << setw(ind) << "// allocate storage : " << scope_path(scope_) << endl; @@ -868,6 +885,15 @@ void NetCondit::dump(ostream&o, unsigned ind) const } } +void NetContribution::dump(ostream&o, unsigned ind) const +{ + o << setw(ind) << ""; + lval_->dump(o); + o << " <+ "; + rval_->dump(o); + o << ";" << endl; +} + void NetDeassign::dump(ostream&o, unsigned ind) const { o << setw(ind) << "" << "deassign "; @@ -1494,4 +1520,6 @@ void Design::dump(ostream&o) const for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_) idx->dump(o, 0); + for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_) + idx->dump(o, 0); } diff --git a/elab_scope.cc b/elab_scope.cc index 0e2820261..1adf85402 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1243,12 +1243,3 @@ void PWhile::elaborate_scope(Design*des, NetScope*scope) const if (statement_) statement_ -> elaborate_scope(des, scope); } - -/* - * The base statement does not have sub-statements and does not - * introduce any scope, so this is a no-op. - */ -void AStatement::elaborate_scope(Design*, NetScope*) const -{ -} - diff --git a/elab_sig_analog.cc b/elab_sig_analog.cc index d7da16fcf..82b8b9e68 100644 --- a/elab_sig_analog.cc +++ b/elab_sig_analog.cc @@ -24,7 +24,3 @@ # include # include -void AStatement::elaborate_sig(Design*des, NetScope*scope) const -{ -} - diff --git a/elaborate_analog.cc b/elaborate_analog.cc index 0688aa2b2..54a4a7d76 100644 --- a/elaborate_analog.cc +++ b/elaborate_analog.cc @@ -20,21 +20,25 @@ # include "config.h" # include "AStatement.h" +# include "netlist.h" +# include "netmisc.h" # include "util.h" # include -NetAnalog* AStatement::elaborate(Design*des, NetScope*scope) const +NetProc* AContrib::elaborate(Design*des, NetScope*scope) const { - cerr << get_fileline() << ": sorry: I don't yet know how to elaborate" - << " his kind of analog statement." << endl; - cerr << get_fileline() << ": : typeid = " << typeid(*this).name() << endl; - return 0; + NetExpr*lval = elab_and_eval(des, scope, lval_, -1); + NetExpr*rval = elab_and_eval(des, scope, rval_, -1); + + NetContribution*st = new NetContribution(lval, rval); + st->set_line(*this); + return st; } bool AProcess::elaborate(Design*des, NetScope*scope) const { - NetAnalog*statement = statement_->elaborate(des, scope); + NetProc*statement = statement_->elaborate(des, scope); if (statement == 0) return false; diff --git a/emit.cc b/emit.cc index 6d1be63a8..0daef461f 100644 --- a/emit.cc +++ b/emit.cc @@ -190,6 +190,13 @@ bool NetProcTop::emit(struct target_t*tgt) const return tgt->process(this); } +bool NetAnalogTop::emit(struct target_t*tgt) const +{ + cerr << get_fileline() << ": sorry: " + << "I don't know how to emit for analog processes." << endl; + return false; +} + bool NetProc::emit_proc(struct target_t*tgt) const { cerr << "EMIT: Proc type? " << typeid(*this).name() << endl; @@ -459,6 +466,8 @@ int Design::emit(struct target_t*tgt) const bool proc_rc = true; for (const NetProcTop*idx = procs_ ; idx ; idx = idx->next_) proc_rc &= idx->emit(tgt); + for (const NetAnalogTop*idx = aprocs_ ; idx ; idx = idx->next_) + proc_rc &= idx->emit(tgt); rc = tgt->end_design(this); diff --git a/net_analog.cc b/net_analog.cc new file mode 100644 index 000000000..25fde3411 --- /dev/null +++ b/net_analog.cc @@ -0,0 +1,37 @@ +/* + * 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" + +NetContribution::NetContribution(NetExpr*l, NetExpr*r) +: lval_(l), rval_(r) +{ +} + +NetContribution::~NetContribution() +{ +} diff --git a/netlist.cc b/netlist.cc index f23fbbe23..2e114ae21 100644 --- a/netlist.cc +++ b/netlist.cc @@ -875,7 +875,7 @@ NetScope* NetProcTop::scope() return scope_; } -NetAnalogTop::NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetAnalog*st) +NetAnalogTop::NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetProc*st) : type_(t), statement_(st), scope_(scope) { next_ = 0; diff --git a/netlist.h b/netlist.h index 63f9f032a..482d6c369 100644 --- a/netlist.h +++ b/netlist.h @@ -2434,6 +2434,24 @@ class NetCondit : public NetProc { NetProc*else_; }; +/* + * This represents the analog contribution statement. The l-val is a + * branch expression, and the r-value is an arbitrary expression that + * may include branches and real values. + */ +class NetContribution : public NetProc { + + public: + explicit NetContribution(NetExpr*lval, NetExpr*rval); + ~NetContribution(); + + virtual void dump(ostream&, unsigned ind) const; + + private: + NetExpr*lval_; + NetExpr*rval_; +}; + /* * The procedural deassign statement (the opposite of assign) releases * any assign expressions attached to the bits of the reg. The @@ -3080,19 +3098,16 @@ class NetProcTop : public LineInfo, public Attrib { NetProcTop*next_; }; -class NetAnalog : public LineInfo, public Attrib { -}; - class NetAnalogTop : public LineInfo, public Attrib { public: - NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetAnalog*st); + NetAnalogTop(NetScope*scope, ivl_process_type_t t, NetProc*st); ~NetAnalogTop(); ivl_process_type_t type() const { return type_; } - NetAnalog*statement(); - const NetAnalog*statement() const; + NetProc*statement(); + const NetProc*statement() const; NetScope*scope(); const NetScope*scope() const; @@ -3102,7 +3117,7 @@ class NetAnalogTop : public LineInfo, public Attrib { private: const ivl_process_type_t type_; - NetAnalog* statement_; + NetProc* statement_; NetScope*scope_; friend class Design; diff --git a/parse.y b/parse.y index d6c05e830..eb116cd7e 100644 --- a/parse.y +++ b/parse.y @@ -180,7 +180,6 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) PEventStatement*event_statement; Statement*statement; svector*statement_list; - AStatement*astatement; PTaskFuncArg function_type; @@ -304,7 +303,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %type statement statement_or_null %type statement_list -%type analog_statement +%type analog_statement %type spec_polarity %type specify_path_identifiers diff --git a/pform.h b/pform.h index 16ef2f9f9..14fc2f875 100644 --- a/pform.h +++ b/pform.h @@ -396,10 +396,10 @@ extern void pform_dump(ostream&out, const discipline_t*); /* ** pform_analog.cc */ extern void pform_make_analog_behavior(const struct vlltype&loc, - ivl_process_type_t type, AStatement*st); + ivl_process_type_t type, Statement*st); -extern AStatement*pform_contribution_statement(const struct vlltype&loc, - PExpr*lval, PExpr*rval); +extern AContrib*pform_contribution_statement(const struct vlltype&loc, + PExpr*lval, PExpr*rval); extern PExpr* pform_make_branch_probe_expression(const struct vlltype&loc, char*name, char*n1, char*n2); diff --git a/pform_analog.cc b/pform_analog.cc index fe5489b44..81571dfdd 100644 --- a/pform_analog.cc +++ b/pform_analog.cc @@ -23,7 +23,7 @@ # include "parse_misc.h" # include "AStatement.h" -AStatement* pform_contribution_statement(const struct vlltype&loc, +AContrib* pform_contribution_statement(const struct vlltype&loc, PExpr*lval, PExpr*rval) { AContrib*tmp = new AContrib(lval, rval); @@ -32,7 +32,7 @@ AStatement* pform_contribution_statement(const struct vlltype&loc, } void pform_make_analog_behavior(const struct vlltype&loc, ivl_process_type_t pt, - AStatement*statement) + Statement*statement) { AProcess*proc = new AProcess(pt, statement); FILE_NAME(proc, loc); diff --git a/pform_dump.cc b/pform_dump.cc index 4283620e0..4dca440d2 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -564,16 +564,6 @@ void Statement::dump(ostream&out, unsigned ind) const dump_attributes_map(out, attributes, ind+2); } -void AStatement::dump(ostream&out, unsigned ind) const -{ - /* I give up. I don't know what type this statement is, - so just print the C++ typeid and let the user figure - it out. */ - out << setw(ind) << ""; - out << "/* " << get_fileline() << ": " << typeid(*this).name() - << " */ ;" << endl; -} - void AContrib::dump(ostream&out, unsigned ind) const { out << setw(ind) << ""; From 1ec09327e9c64fde1018f925d513e2ca14ba1538 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 30 Oct 2008 21:19:56 -0700 Subject: [PATCH 03/19] Elaborate divide expressions to the proper width. If the operands of a divide expression are fixed width, pad them out to the width of the expression so that the calculations come out right. --- elab_expr.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/elab_expr.cc b/elab_expr.cc index 413e5317a..0513c1a43 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -404,6 +404,16 @@ NetExpr* PEBinary::elaborate_expr_base_div_(Design*des, } } + /* The original elaboration of the left and right expressions + already tried to elaborate to the expr_wid. If the + expressions are not that width by now, then they need to be + padded. The divide expression operands must be the width + of the output. */ + if (expr_wid > 0) { + lp = pad_to_width(lp, expr_wid); + rp = pad_to_width(rp, expr_wid); + } + NetEBDiv*tmp = new NetEBDiv(op_, lp, rp); tmp->set_line(*this); From 2c7fe8aa2a60cac0d6b8b0fb2596c58882ecc594 Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 28 Oct 2008 18:52:32 -0700 Subject: [PATCH 04/19] Fixes for real VPI interface, etc. This patch fixes some problems found when trying to dump words from a real wire array. There are still a few more things that look suspicious and need testing. --- vvp/array.cc | 13 +++++++++++++ vvp/vpi_priv.cc | 8 ++++++++ vvp/vpi_priv.h | 8 ++++++-- vvp/vpi_real.cc | 28 +++++++++++++--------------- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/vvp/array.cc b/vvp/array.cc index 4994a3cd6..defaddffb 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -842,6 +842,19 @@ void array_attach_word(vvp_array_t array, unsigned long addr, vpiHandle word) sig->is_netarray = 1; sig->within.parent = &array->base; sig->id.index = vpip_make_dec_const(addr + array->first_addr.value); + return; + } + + if (struct __vpiRealVar*sig = (struct __vpiRealVar*)word) { + vvp_net_t*net = sig->net; + assert(net); + vvp_fun_signal_base*fun = dynamic_cast(net->fun); + assert(fun); + fun->attach_as_word(array, addr); + sig->is_netarray = 1; + sig->within.parent = &array->base; + sig->id.index = vpip_make_dec_const(addr + array->first_addr.value); + return; } } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index f0338e909..27af301cf 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -58,6 +58,14 @@ struct __vpiScope* vpip_scope(__vpiSignal*sig) return sig->within.scope; } +struct __vpiScope* vpip_scope(__vpiRealVar*sig) +{ + if (sig->is_netarray) + return (struct __vpiScope*) vpi_handle(vpiScope, sig->within.parent); + else + return sig->within.scope; +} + const char *vpip_string(const char*str) { static vpip_string_chunk first_chunk = {0, {0}}; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index c88197bca..6b053ad72 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -354,16 +354,20 @@ extern void vpip_real_value_change(struct __vpiCallback*cbh, */ struct __vpiRealVar { struct __vpiHandle base; - vpiHandle parent; - struct __vpiScope* scope; + union { // The scope or parent array that contains me. + vpiHandle parent; + struct __vpiScope* scope; + } within; /* The name of this variable, or the index for array words. */ union { const char*name; vpiHandle index; } id; + unsigned is_netarray : 1; // This is word of a net array vvp_net_t*net; }; +extern struct __vpiScope* vpip_scope(__vpiRealVar*sig); extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net); /* diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index 6965ed145..78b607519 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -36,7 +36,7 @@ static int real_var_get(int code, vpiHandle ref) switch (code) { case vpiArray: - return rfp->parent != 0; + return rfp->is_netarray != 0; case vpiSize: return 1; @@ -62,8 +62,8 @@ static char* real_var_get_str(int code, vpiHandle ref) } char *nm, *ixs; - if (rfp->parent) { - nm = strdup(vpi_get_str(vpiName, rfp->parent)); + if (rfp->is_netarray) { + nm = strdup(vpi_get_str(vpiName, rfp->within.parent)); s_vpi_value vp; vp.format = vpiDecStrVal; vpi_get_value(rfp->id.index, &vp); @@ -73,7 +73,7 @@ static char* real_var_get_str(int code, vpiHandle ref) ixs = NULL; } - char *rbuf = generic_get_str(code, &rfp->scope->base, nm, ixs); + char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs); free(nm); return rbuf; } @@ -87,10 +87,13 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref) switch (code) { case vpiParent: - return rfp->parent; + return rfp->is_netarray ? rfp->within.parent : 0; case vpiIndex: - return rfp->parent ? rfp->id.index : 0; + return rfp->is_netarray ? rfp->id.index : 0; + + case vpiScope: + return &(vpip_scope(rfp)->base); } return 0; @@ -103,8 +106,8 @@ static vpiHandle real_var_iterate(int code, vpiHandle ref) struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; if (code == vpiIndex) { - return rfp->parent ? (rfp->id.index->vpi_type->iterate_) - (code, rfp->id.index) : 0; + return rfp->is_netarray ? (rfp->id.index->vpi_type->iterate_) + (code, rfp->id.index) : 0; } return 0; @@ -179,22 +182,17 @@ void vpip_real_value_change(struct __vpiCallback*cbh, fun->add_vpi_callback(cbh); } -/* - * Since reals do not currently support arrays none of the array code - * has been tested! Though it should work since it is a copy of the - * signal code. - */ vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net) { struct __vpiRealVar*obj = (struct __vpiRealVar*) malloc(sizeof(struct __vpiRealVar)); obj->base.vpi_type = &vpip_real_var_rt; - obj->parent = 0; obj->id.name = name ? vpip_name_string(name) : 0; + obj->is_netarray = 0; obj->net = net; - obj->scope = vpip_peek_current_scope(); + obj->within.scope = vpip_peek_current_scope(); return &obj->base; } From 7ac35e478b202bd4082de1f51640638435e7a28d Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Oct 2008 09:23:23 -0700 Subject: [PATCH 05/19] The scope of real values needs to be calculated. Finding the scope of a real value is no longer simple, so it must be calculated. --- vvp/vpi_real.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index 78b607519..f80e472b6 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -45,7 +45,7 @@ static int real_var_get(int code, vpiHandle ref) return 0; // Not implemented for now! case vpiAutomatic: - return (int) rfp->scope->is_automatic; + return (int) vpip_scope(rfp)->is_automatic; } return 0; From 9b640f3114ca12aff21b8499b73a9c50e1685a52 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Wed, 29 Oct 2008 08:11:01 -0700 Subject: [PATCH 06/19] Shadow reduction part 4 Continue cleaning up shadowed variables, flagged by turning on -Wshadow. No intended change in functionality. This patch set covers the tgt-vhdl directory, and was tested by Nick. --- tgt-vhdl/cast.cc | 8 ++++---- tgt-vhdl/display.cc | 6 +++--- tgt-vhdl/scope.cc | 10 +++++----- tgt-vhdl/stmt.cc | 16 ++++++++-------- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index e3006e9e0..d01016c6a 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -198,11 +198,11 @@ vhdl_expr *vhdl_expr::resize(int newwidth) else return this; // Doesn't make sense to resize non-vector type - vhdl_fcall *resize = new vhdl_fcall("Resize", rtype); - resize->add_expr(this); - resize->add_expr(new vhdl_const_int(newwidth)); + vhdl_fcall *resizef = new vhdl_fcall("Resize", rtype); + resizef->add_expr(this); + resizef->add_expr(new vhdl_const_int(newwidth)); - return resize; + return resizef; } vhdl_expr *vhdl_const_int::to_vector(vhdl_type_name_t name, int w) diff --git a/tgt-vhdl/display.cc b/tgt-vhdl/display.cc index 05bbe944a..5073ab634 100644 --- a/tgt-vhdl/display.cc +++ b/tgt-vhdl/display.cc @@ -157,10 +157,10 @@ int draw_stask_display(vhdl_procedural *proc, stmt_container *container, // function in VHDL assert(i < count); - ivl_expr_t net = ivl_stmt_parm(stmt, i++); - assert(net); + ivl_expr_t netp = ivl_stmt_parm(stmt, i++); + assert(netp); - vhdl_expr *base = translate_expr(net); + vhdl_expr *base = translate_expr(netp); if (NULL == base) return 1; diff --git a/tgt-vhdl/scope.cc b/tgt-vhdl/scope.cc index 116382eeb..2d4272049 100644 --- a/tgt-vhdl/scope.cc +++ b/tgt-vhdl/scope.cc @@ -698,11 +698,11 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) for (int i = 0; i < nsigs; i++) { ivl_signal_t sig = ivl_scope_sig(scope, i); - for (unsigned i = ivl_signal_array_base(sig); - i < ivl_signal_array_count(sig); - i++) { + for (unsigned j = ivl_signal_array_base(sig); + j < ivl_signal_array_count(sig); + j++) { // Make sure the nexus code is generated - ivl_nexus_t nex = ivl_signal_nex(sig, i); + ivl_nexus_t nex = ivl_signal_nex(sig, j); seen_nexus(nex); nexus_private_t *priv = @@ -712,7 +712,7 @@ static int draw_constant_drivers(ivl_scope_t scope, void *_parent) vhdl_scope *arch_scope = ent->get_arch()->get_scope(); if (priv->const_driver) { - assert(i == 0); // TODO: Make work for more words + assert(j == 0); // TODO: Make work for more words vhdl_var_ref *ref = nexus_to_var_ref(arch_scope, nex); diff --git a/tgt-vhdl/stmt.cc b/tgt-vhdl/stmt.cc index f5644825e..0e86ebf6c 100644 --- a/tgt-vhdl/stmt.cc +++ b/tgt-vhdl/stmt.cc @@ -424,8 +424,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_event_t event = ivl_stmt_events(stmt, i); int nany = ivl_event_nany(event); - for (int i = 0; i < nany; i++) { - ivl_nexus_t nexus = ivl_event_any(event, i); + for (int j = 0; j < nany; j++) { + ivl_nexus_t nexus = ivl_event_any(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); wait->add_sensitivity(ref->get_name()); @@ -441,8 +441,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, ivl_event_t event = ivl_stmt_events(stmt, i); int nany = ivl_event_nany(event); - for (int i = 0; i < nany; i++) { - ivl_nexus_t nexus = ivl_event_any(event, i); + for (int j = 0; j < nany; j++) { + ivl_nexus_t nexus = ivl_event_any(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); ref->set_name(ref->get_name() + "'Event"); @@ -450,8 +450,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } int nneg = ivl_event_nneg(event); - for (int i = 0; i < nneg; i++) { - ivl_nexus_t nexus = ivl_event_neg(event, i); + for (int j = 0; j < nneg; j++) { + ivl_nexus_t nexus = ivl_event_neg(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); vhdl_fcall *detect = new vhdl_fcall("falling_edge", vhdl_type::boolean()); @@ -461,8 +461,8 @@ static int draw_wait(vhdl_procedural *_proc, stmt_container *container, } int npos = ivl_event_npos(event); - for (int i = 0; i < npos; i++) { - ivl_nexus_t nexus = ivl_event_pos(event, i); + for (int j = 0; j < npos; j++) { + ivl_nexus_t nexus = ivl_event_pos(event, j); vhdl_var_ref *ref = nexus_to_var_ref(proc->get_scope(), nexus); vhdl_fcall *detect = new vhdl_fcall("rising_edge", vhdl_type::boolean()); From 403a1e9415b125a5d6cd0cf043f8b2c538cb8724 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Thu, 30 Oct 2008 22:11:05 -0700 Subject: [PATCH 07/19] Add a dup_expr method to NetEUBits. The NetEUBits needs to create a NetEUBits when the dup_expr method is called, so it needs its own dup_expr method. --- dup_expr.cc | 8 ++++++++ netlist.h | 1 + 2 files changed, 9 insertions(+) diff --git a/dup_expr.cc b/dup_expr.cc index 91b6bc867..45ad48d5d 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -138,6 +138,14 @@ NetEUFunc* NetEUFunc::dup_expr() const return tmp; } +NetEUBits* NetEUBits::dup_expr() const +{ + NetEUBits*tmp = new NetEUBits(op_, expr_->dup_expr()); + assert(tmp); + tmp->set_line(*this); + return tmp; +} + NetEUnary* NetEUnary::dup_expr() const { NetEUnary*tmp = new NetEUnary(op_, expr_->dup_expr()); diff --git a/netlist.h b/netlist.h index a73c68b98..0c1f52917 100644 --- a/netlist.h +++ b/netlist.h @@ -3655,6 +3655,7 @@ class NetEUBits : public NetEUnary { virtual NetNet* synthesize(Design*, NetScope*scope); + virtual NetEUBits* dup_expr() const; virtual NetExpr* eval_tree(int prune_to_width = -1); virtual ivl_variable_type_t expr_type() const; }; From 520d9b9dd0b0abc292813136e1896f3d0599be50 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Fri, 31 Oct 2008 09:35:17 -0700 Subject: [PATCH 08/19] Touch up new developer quick start Spelling and other minor touch-up for the new and much-appreciated developer-quick-start.txt --- developer-quick-start.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/developer-quick-start.txt b/developer-quick-start.txt index 48ffa1f9b..33506b62c 100644 --- a/developer-quick-start.txt +++ b/developer-quick-start.txt @@ -10,7 +10,7 @@ participating in the Icarus Verilog development process. That information will not be repeated here. What this documentation *will* cover is the gross structure of the -Icarus Verilog core compiler source. This will help orient you to the +Icarus Verilog compiler source. This will help orient you to the source code itself, so that you can find the global parts where you can look for even better detail. @@ -40,7 +40,7 @@ on the core itself. - The loadable code generators (tgt-*/) This core compiler, after it is finished with parsing and semantic -analysis, uses loadable code generators to emit code for suppoted +analysis, uses loadable code generators to emit code for supported targets. The tgt-*/ directories contains the source for the target code generators that are bundled with Icarus Verilog. The tgt-vvp/ directory in particular contains the code generator for the vvp @@ -65,20 +65,20 @@ and the source is in this subdirectory. The Icarus Verilog support for the deprecated PLI-1 is in this subdirectory. The vvp runtime does not directly support the -PLI-1. Insead, the libveriuser library emulates it using the builtin +PLI-1. Instead, the libveriuser library emulates it using the builtin PLI-2 support. - The Cadence PLI module compatibility module (cadpli/) It is possible in some specialized situations to load and execute -PLI-1 code writen for Verilog-XL. This directory contains the source +PLI-1 code written for Verilog-XL. This directory contains the source for the module that provides the Cadence PLI interface. * The Core Compiler The "ivl" binary is the core compiler that does the heavy lifting of -compiling the Veriog source (including libraries) and generating the +compiling the Verilog source (including libraries) and generating the output. This is the most complex component of the Icarus Verilog compilation system. @@ -86,8 +86,8 @@ The process in the abstract starts with the Verilog lexical analysis and parsing to generate an internal "pform". The pform is then translated by elaboration into the "netlist" form. The netlist is processed by some functors (which include some optimizations and -optional synthesys) then is translated into the ivl_target internal -form. And finallly, the ivl_target form is passed via the ivl_target.h +optional synthesis) then is translated into the ivl_target internal +form. And finally, the ivl_target form is passed via the ivl_target.h API to the code generators. - Lexical Analysis @@ -105,9 +105,9 @@ large set of potential keywords. - Parsing The parser input file "parse.y" is passed to the "bison" program to -generate the parser. The parser uses the functions in parse*., -parse*.cc, pform*.h and pform*.cc to generate the pform from the -stream of input tokens. The pfrom is what compiler writers call a +generate the parser. The parser uses the functions in parse*.h, +parse*.cc, pform.h, and pform*.cc to generate the pform from the +stream of input tokens. The pform is what compiler writers call a "decorated parse tree". The pform itself is described by the classes in the header files From 6cac1d2cab693687f071d34809ce1edfb7c9b368 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 1 Nov 2008 20:44:03 -0700 Subject: [PATCH 09/19] Add support for real/realtime arrays. Support arrays of realtime variable arrays and net arrays. This involved a simple fix to the ivl core parser, proper support in the code generator, and rework the runtime support in vvp. --- parse.y | 8 +++- tgt-vvp/eval_real.c | 22 ++++----- tgt-vvp/vvp_process.c | 20 ++++++-- vvp/array.cc | 108 +++++++++++++++++++++++++++++++----------- vvp/array.h | 9 ++-- vvp/codes.h | 2 + vvp/compile.cc | 3 +- vvp/opcodes.txt | 20 ++++++-- vvp/vpi_priv.h | 1 + vvp/vpi_real.cc | 11 ++++- vvp/vthread.cc | 32 +++++++++++++ vvp/vvp_net.cc | 26 ++++++++++ vvp/vvp_net.h | 20 ++++++++ vvp/words.cc | 2 + 14 files changed, 229 insertions(+), 55 deletions(-) diff --git a/parse.y b/parse.y index a860fdcce..ee84a9c8e 100644 --- a/parse.y +++ b/parse.y @@ -2978,7 +2978,13 @@ real_variable { perm_string name = lex_strings.make($1); pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); if ($2 != 0) { - yyerror(@2, "sorry: real variables do not currently support arrays."); + index_component_t index; + if ($2->size() > 1) { + yyerror(@2, "sorry: only 1 dimensional arrays " + "are currently supported."); + } + index = $2->front(); + pform_set_reg_idx(name, index.msb, index.lsb); delete $2; } $$ = $1; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index de9ce577e..f2b577ba1 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -354,23 +354,17 @@ static int draw_signal_real_real(ivl_expr_t exp) { ivl_signal_t sig = ivl_expr_signal(exp); int res = allocate_word(); - unsigned long word = 0; - if (ivl_signal_dimensions(sig) > 0) { - ivl_expr_t ix = ivl_expr_oper1(exp); - if (!number_is_immediate(ix, IMM_WID, 0)) { - /* XXXX Need to generate a %load/ar instruction. */ - assert(0); - return res; - } - - /* The index is constant, so we can return to direct - readout with the specific word selected. */ - word = get_number_immediate(ix); + if (ivl_signal_dimensions(sig) == 0) { + fprintf(vvp_out, " %%load/wr %d, v%p_0;\n", res, sig); + return res; } - fprintf(vvp_out, " %%load/wr %d, v%p_%lu;\n", res, sig, word); - + ivl_expr_t word_ex = ivl_expr_oper1(exp); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + fprintf(vvp_out, " %%load/ar %d, v%p, %d;\n", res, sig, word_ix); + clr_word(word_ix); return res; } diff --git a/tgt-vvp/vvp_process.c b/tgt-vvp/vvp_process.c index 1d643454f..eacf35547 100644 --- a/tgt-vvp/vvp_process.c +++ b/tgt-vvp/vvp_process.c @@ -497,16 +497,30 @@ static int show_stmt_assign_sig_real(ivl_statement_t net) ivl_signal_t var; res = draw_eval_real(ivl_stmt_rval(net)); - clr_word(res); assert(ivl_stmt_lvals(net) == 1); lval = ivl_stmt_lval(net, 0); var = ivl_lval_sig(lval); assert(var != 0); - assert(ivl_signal_dimensions(var) == 0); + if (ivl_signal_dimensions(var) == 0) { + clr_word(res); + fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); + return 0; + } - fprintf(vvp_out, " %%set/wr v%p_0, %d;\n", var, res); + // For now, only support 1-dimensional arrays. + assert(ivl_signal_dimensions(var) == 1); + + // Calculate the word index into an index register + ivl_expr_t word_ex = ivl_lval_idx(lval); + int word_ix = allocate_word(); + draw_eval_expr_into_integer(word_ex, word_ix); + // Generate an assignment to write to the array. + fprintf(vvp_out, " %%set/ar v%p, %d, %d;\n", var, word_ix, res); + + clr_word(res); + clr_word(word_ix); return 0; } diff --git a/vvp/array.cc b/vvp/array.cc index defaddffb..0cd51b5ff 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -53,7 +53,28 @@ vvp_array_t array_find(const char*label) /* * The vpiArray object holds an array of vpi objects that themselves -* represent the words of the array. The vpi_array_t is a pointer to this. +* represent the words of the array. The vpi_array_t is a pointer to +* a struct __vpiArray. +* +* The details of the implementation depends on what this is an array +* of. The easiest case is if this is an array of nets. +* +* - Array of Nets: +* If this represents an array of nets, then the nets member points to +* an array of vpiHandle objects. Each vpiHandle is a word. This is +* done because typically each word of a net array is simultaneously +* driven and accessed by other means, so there is no advantage to +* compacting the array in any other way. +* +* - Array of vector4 words. +* In this case, the nets pointer is nil, and the vals4 member points +* to a vvl_vector4array_t object that is a compact representation of +* an array of vvp_vector4_t vectors. +* +* - Array of real variables +* The valsr member points to a vvp_realarray_t objects that has an +* array of double variables. This is very much line the way the +* vector4 array works. */ struct __vpiArray { __vpiArray() { } @@ -70,7 +91,8 @@ struct __vpiArray { // If this is a net array, nets lists the handles. vpiHandle*nets; // If this is a var array, then these are used instead of nets. - vvp_vector4array_t *vals; + vvp_vector4array_t *vals4; + vvp_realarray_t *valsr; struct __vpiArrayWord*vals_words; class vvp_fun_arrayport*ports_; @@ -127,7 +149,7 @@ struct __vpiArrayVthrA { /* Get the array word size. This has only been checked for reg arrays. */ unsigned get_array_word_size(vvp_array_t array) { - assert(array->vals); + assert(array->vals4); return array->vals_width; } @@ -424,7 +446,7 @@ static int vpi_array_var_word_get(int code, vpiHandle ref) switch (code) { case vpiSize: - return (int) parent->vals->width(); + return (int) parent->vals4->width(); case vpiLeftRange: return parent->msb.value; @@ -461,9 +483,9 @@ static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value value) assert(obj); unsigned index = decode_array_word_pointer(obj, parent); - unsigned width = parent->vals->width(); + unsigned width = parent->vals4->width(); - vpip_vec4_get_value(parent->vals->get_word(index), width, + vpip_vec4_get_value(parent->vals4->get_word(index), width, parent->signed_flag, value); } @@ -539,7 +561,7 @@ static vpiHandle array_iterator_scan(vpiHandle ref, int) if (obj->array->nets) return obj->array->nets[obj->next]; - assert(obj->array->vals); + assert(obj->array->vals4); if (obj->array->vals_words == 0) array_make_vals_words(obj->array); @@ -702,10 +724,10 @@ void array_set_word(vvp_array_t arr, if (address >= arr->array_count) return; - if (arr->vals) { + if (arr->vals4) { assert(arr->nets == 0); if (part_off != 0 || val.size() != arr->vals_width) { - vvp_vector4_t tmp = arr->vals->get_word(address); + vvp_vector4_t tmp = arr->vals4->get_word(address); if ((part_off + val.size()) > tmp.size()) { cerr << "part_off=" << part_off << " val.size()=" << val.size() @@ -714,9 +736,9 @@ void array_set_word(vvp_array_t arr, assert(0); } tmp.set_vec(part_off, val); - arr->vals->set_word(address, tmp); + arr->vals4->set_word(address, tmp); } else { - arr->vals->set_word(address, val); + arr->vals4->set_word(address, val); } array_word_change(arr, address); return; @@ -734,15 +756,22 @@ void array_set_word(vvp_array_t arr, array_word_change(arr, address); } +void array_set_word(vvp_array_t arr, unsigned address, double val) +{ + assert(arr->valsr!= 0); + assert(arr->nets == 0); + + arr->valsr->set_word(address, val); +} + vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) { - if (arr->vals) { + if (arr->vals4) { assert(arr->nets == 0); - - return arr->vals->get_word(address); + return arr->vals4->get_word(address); } - assert(arr->vals == 0); + assert(arr->vals4 == 0); assert(arr->nets != 0); if (address >= arr->array_count) { @@ -767,6 +796,26 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) return val; } +double array_get_word_r(vvp_array_t arr, unsigned address) +{ + if (arr->valsr) { + assert(arr->vals4 == 0); + assert(arr->nets == 0); + return arr->valsr->get_word(address); + } + + assert(arr->nets); + vpiHandle word = arr->nets[address]; + struct __vpiRealVar*vsig = vpip_realvar_from_handle(word); + assert(vsig); + vvp_fun_signal_real*sig = dynamic_cast (vsig->net->fun); + assert(sig); + + double val = sig->real_value(); + return val; + +} + static vpiHandle vpip_make_array(char*label, const char*name, int first_addr, int last_addr, bool signed_flag) @@ -792,7 +841,8 @@ static vpiHandle vpip_make_array(char*label, const char*name, // Start off now knowing if we are nets or variables. obj->nets = 0; - obj->vals = 0; + obj->vals4 = 0; + obj->valsr = 0; obj->vals_width = 0; vpip_make_dec_const(&obj->msb, 0); vpip_make_dec_const(&obj->lsb, 0); @@ -869,11 +919,11 @@ void compile_var_array(char*label, char*name, int last, int first, /* Make the words. */ arr->vals_width = labs(msb-lsb) + 1; if (vpip_peek_current_scope()->is_automatic) { - arr->vals = new vvp_vector4array_aa(arr->vals_width, - arr->array_count); + arr->vals4 = new vvp_vector4array_aa(arr->vals_width, + arr->array_count); } else { - arr->vals = new vvp_vector4array_sa(arr->vals_width, - arr->array_count); + arr->vals4 = new vvp_vector4array_sa(arr->vals_width, + arr->array_count); } vpip_make_dec_const(&arr->msb, msb); vpip_make_dec_const(&arr->lsb, lsb); @@ -891,14 +941,16 @@ void compile_real_array(char*label, char*name, int last, int first, vpiHandle obj = vpip_make_array(label, name, first, last, true); struct __vpiArray*arr = ARRAY_HANDLE(obj); - vvp_array_t array = array_find(label); /* Make the words. */ - for (unsigned idx = 0 ; idx < arr->array_count ; idx += 1) { - char buf[64]; - snprintf(buf, sizeof buf, "%s_%u", label, idx); - compile_varw_real(strdup(buf), array, idx, msb, lsb); - } + arr->valsr = new vvp_realarray_t(arr->array_count); + arr->vals_width = 1; + + /* Do these even make sense for real arrays? These are the + part select of a vector, but the real value is not + vectorable. */ + vpip_make_dec_const(&arr->msb, msb); + vpip_make_dec_const(&arr->lsb, lsb); count_real_arrays += 1; count_real_array_words += arr->array_count; @@ -1146,7 +1198,7 @@ void array_word_change(vvp_array_t array, unsigned long addr) if (cur->cb_data.cb_rtn != 0) { if (cur->cb_data.value) - vpip_vec4_get_value(array->vals->get_word(addr), + vpip_vec4_get_value(array->vals4->get_word(addr), array->vals_width, array->signed_flag, cur->cb_data.value); @@ -1282,7 +1334,7 @@ void compile_array_alias(char*label, char*name, char*src) // Share the words with the source array. obj->nets = mem->nets; - obj->vals = mem->vals; + obj->vals4 = mem->vals4; obj->ports_ = 0; diff --git a/vvp/array.h b/vvp/array.h index 7bac81088..167fc9387 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -39,12 +39,13 @@ extern void array_attach_word(vvp_array_t array, unsigned long addr, extern void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word); -extern void array_set_word(vvp_array_t arr, - unsigned idx, - unsigned off, - vvp_vector4_t val); +extern void array_set_word(vvp_array_t arr, unsigned idx, + unsigned off, vvp_vector4_t val); +extern void array_set_word(vvp_array_t arr, unsigned idx, + double val); extern vvp_vector4_t array_get_word(vvp_array_t array, unsigned address); +extern double array_get_word_r(vvp_array_t array, unsigned address); /* VPI hooks */ diff --git a/vvp/codes.h b/vvp/codes.h index 769b3a915..0e634a95b 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -107,6 +107,7 @@ extern bool of_JMP0(vthread_t thr, vvp_code_t code); extern bool of_JMP0XZ(vthread_t thr, vvp_code_t code); extern bool of_JMP1(vthread_t thr, vvp_code_t code); extern bool of_JOIN(vthread_t thr, vvp_code_t code); +extern bool of_LOAD_AR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AV(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVP0(vthread_t thr, vvp_code_t code); extern bool of_LOAD_AVP0_S(vthread_t thr, vvp_code_t code); @@ -138,6 +139,7 @@ extern bool of_POW_WR(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_NET(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_REG(vthread_t thr, vvp_code_t code); extern bool of_RELEASE_WR(vthread_t thr, vvp_code_t code); +extern bool of_SET_AR(vthread_t thr, vvp_code_t code); extern bool of_SET_AV(vthread_t thr, vvp_code_t code); extern bool of_SET_VEC(vthread_t thr, vvp_code_t code); extern bool of_SET_WORDR(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index 023b23e2e..75a84311e 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -150,6 +150,7 @@ const static struct opcode_table_s opcode_table[] = { { "%jmp/0xz",of_JMP0XZ, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%jmp/1", of_JMP1, 2, {OA_CODE_PTR, OA_BIT1, OA_NONE} }, { "%join", of_JOIN, 0, {OA_NONE, OA_NONE, OA_NONE} }, + { "%load/ar",of_LOAD_AR,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/av",of_LOAD_AV,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avp0",of_LOAD_AVP0,3, {OA_BIT1, OA_ARR_PTR, OA_BIT2} }, { "%load/avp0/s",of_LOAD_AVP0_S,3,{OA_BIT1, OA_ARR_PTR, OA_BIT2} }, @@ -181,11 +182,11 @@ const static struct opcode_table_s opcode_table[] = { { "%release/net",of_RELEASE_NET,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/reg",of_RELEASE_REG,3,{OA_FUNC_PTR,OA_BIT1,OA_BIT2} }, { "%release/wr",of_RELEASE_WR,2,{OA_FUNC_PTR,OA_BIT1,OA_NONE} }, + { "%set/ar", of_SET_AR, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} }, { "%set/av", of_SET_AV, 3, {OA_ARR_PTR, OA_BIT1, OA_BIT2} }, { "%set/v", of_SET_VEC,3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%set/wr", of_SET_WORDR,2,{OA_FUNC_PTR, OA_BIT1, OA_NONE} }, { "%set/x0", of_SET_X0, 3, {OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, -// { "%set/x0/x",of_SET_X0_X,3,{OA_FUNC_PTR, OA_BIT1, OA_BIT2} }, { "%shiftl/i0", of_SHIFTL_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} }, { "%shiftr/i0", of_SHIFTR_I0, 2, {OA_BIT1,OA_NUMBER, OA_NONE} }, { "%shiftr/s/i0", of_SHIFTR_S_I0,2,{OA_BIT1,OA_NUMBER, OA_NONE} }, diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 1cf47d03c..c9419c405 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -512,9 +512,14 @@ The is, line the %load/v, the result width. But unlike the (%load/vp0/s) to the desired width. * %load/wr , +* %load/ar , , -This instruction reads a real value from the vpi-like object to a word -register. +The %load/wr instruction reads a real value from the vpi-like object +to a word register . + +The %load/ar instruction reads a real value from an array. The +is the index register that contains the canonical word address into +the array. * %load/x1p , , @@ -708,8 +713,17 @@ The address (in canonical form) is precalculated and loaded into index register 3. This is the address of the word within the array. * %set/wr , +* %set/ar , , -This instruction writes a real word to the specified VPI-like object. +The %set/wr instruction writes a real word to the specified VPI-like +object. + +The %set/ar instruction writes a real work to the specified array +word. The addresses the array, and the is the +name of the index register to address into the word. The index +register must contain an integer value that is the canonical address +of the array word. The is the index register that contains the +real value word to write. * %set/x0 , , diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 6b053ad72..a9ffd0369 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -369,6 +369,7 @@ struct __vpiRealVar { extern struct __vpiScope* vpip_scope(__vpiRealVar*sig); extern vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net); +extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj); /* * When a loaded VPI module announces a system task/function, one diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index f80e472b6..a0c83d466 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -28,11 +28,20 @@ #endif # include +struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj) +{ + assert(obj); + if (obj->vpi_type->type_code == vpiRealVar) + return (struct __vpiRealVar*)obj; + else + return 0; +} + static int real_var_get(int code, vpiHandle ref) { assert(ref->vpi_type->type_code == vpiRealVar); - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = vpip_realvar_from_handle(ref); switch (code) { case vpiArray: diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 65a5a4250..b8e6871f3 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -2752,6 +2752,20 @@ bool of_JOIN(vthread_t thr, vvp_code_t cp) return false; } +/* + * %load/ar , , ; +*/ +bool of_LOAD_AR(vthread_t thr, vvp_code_t cp) +{ + unsigned bit = cp->bit_idx[0]; + unsigned idx = cp->bit_idx[1]; + unsigned adr = thr->words[idx].w_int; + + double word = array_get_word_r(cp->array, adr); + thr->words[bit].w_real = word; + return true; +} + /* * %load/av , , ; * @@ -3936,6 +3950,24 @@ bool of_RELEASE_WR(vthread_t thr, vvp_code_t cp) return true; } +/* + * %set/av