diff --git a/Makefile.in b/Makefile.in index cac099f67..7bd62d4f1 100644 --- a/Makefile.in +++ b/Makefile.in @@ -107,12 +107,13 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.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_analog.o net_assign.o net_design.o \ - netenum.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ + netenum.o netstruct.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 parse.o parse_misc.o pform.o pform_analog.o \ - pform_disciplines.o pform_dump.o pform_types.o \ + pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \ + pform_types.o \ symbol_search.o sync.o sys_funcs.o verinum.o verireal.o target.o \ - Attrib.o HName.o Module.o PDelays.o PEvent.o PExpr.o PGate.o \ + Attrib.o HName.o Module.o PClass.o PDelays.o PEvent.o PExpr.o PGate.o \ PGenerate.o PScope.o PSpec.o PTask.o PUdp.o PFunction.o PWire.o \ Statement.o AStatement.o $M $(FF) $(TT) @@ -150,8 +151,8 @@ endif clean: $(foreach dir,$(SUBDIRS),$(MAKE) -C $(dir) $@ && ) true rm -f *.o parse.cc parse.h lexor.cc - rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps parse.output - rm -f syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp + rm -f ivl.exp iverilog-vpi.man iverilog-vpi.pdf iverilog-vpi.ps + rm -f parse.output syn-rules.output dosify.exe ivl@EXEEXT@ check.vvp rm -f lexor_keyword.cc libivl.a libvpi.a iverilog-vpi syn-rules.cc rm -rf dep rm -f version.exe @@ -244,15 +245,17 @@ lexor.o: lexor.cc parse.h parse.o: parse.cc -parse.cc parse.h: $(srcdir)/parse.y - $(YACC) --verbose -t -p VL -d -o parse.cc $(srcdir)/parse.y - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h +# Build this in two steps to avoid parallel build issues (see pr3462585) +parse.cc: $(srcdir)/parse.y + $(YACC) --verbose -t -p VL -d -o $@ $< +parse.h: parse.cc + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ syn-rules.cc: $(srcdir)/syn-rules.y - $(YACC) --verbose -p syn_ -o syn-rules.cc $(srcdir)/syn-rules.y + $(YACC) --verbose -t -p syn_ -o $@ $< lexor.cc: $(srcdir)/lexor.lex - $(LEX) -s -olexor.cc $(srcdir)/lexor.lex + $(LEX) -s -t $< > $@ lexor_keyword.o: lexor_keyword.cc parse.h diff --git a/Module.cc b/Module.cc index 40871d059..66efe26b0 100644 --- a/Module.cc +++ b/Module.cc @@ -28,7 +28,7 @@ list Module::user_defparms; /* n is a permallocated string. */ Module::Module(perm_string n) -: PScope(n) +: PScopeExtra(n) { library_flag = false; is_cell = false; diff --git a/Module.h b/Module.h index 307836edf..a791a6be2 100644 --- a/Module.h +++ b/Module.h @@ -49,7 +49,7 @@ class NetScope; * therefore the handle for grasping the described circuit. */ -class Module : public PScope, public LineInfo { +class Module : public PScopeExtra, public LineInfo { /* The module ports are in general a vector of port_t objects. Each port has a name and an ordered list of @@ -112,10 +112,6 @@ class Module : public PScope, public LineInfo { bool time_from_timescale; bool timescale_warn_done; - /* Task definitions within this module */ - map tasks; - map funcs; - /* The module has a list of generate schemes that appear in the module definition. These are used at elaboration time. */ list generate_schemes; diff --git a/PClass.cc b/PClass.cc new file mode 100644 index 000000000..9a9a62355 --- /dev/null +++ b/PClass.cc @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 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 "PClass.h" + +PClass::PClass(perm_string name, LexicalScope*parent) +: PScopeExtra(name, parent) +{ +} + + +PClass::~PClass() +{ +} diff --git a/PClass.h b/PClass.h new file mode 100644 index 000000000..b4578ad68 --- /dev/null +++ b/PClass.h @@ -0,0 +1,40 @@ +#ifndef __PClass_H +#define __PClass_H +/* + * Copyright (c) 2012 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 "PScope.h" +# include "LineInfo.h" +# include "StringHeap.h" + +/* + * SystemVerilog supports class declarations with their own lexical + * scope, etc. The parser arranges for these to be created and + * collected. + */ + +class PClass : public PScopeExtra, public LineInfo { + + public: + explicit PClass (perm_string name, LexicalScope*parent); + ~PClass(); + +}; + +#endif diff --git a/PExpr.cc b/PExpr.cc index b301cb3cb..7cbc649a4 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams + * Copyright (c) 1998-2012 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -346,7 +346,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC); net->set_file(get_file()); net->set_lineno(get_lineno()); - net->set_range(0, 0, SR_NET, true); + net->set_range_scalar(SR_NET); scope->wires[name] = net; if (warn_implicit) { cerr << get_fileline() << ": warning: implicit " diff --git a/PExpr.h b/PExpr.h index 8aa74beee..03c9e3284 100644 --- a/PExpr.h +++ b/PExpr.h @@ -343,18 +343,33 @@ class PEIdent : public PExpr { bool calculate_up_do_width_(Design*, NetScope*, unsigned long&wid) const; + // Evaluate the prefix indices. All but the final index in a + // chain of indices must be a single value and must evaluate + // to constants at compile time. For example: + // [x] - OK + // [1][2][x] - OK + // [1][x:y] - OK + // [2:0][x] - BAD + // [y][x] - BAD + // Leave the last index for special handling. + bool calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, + std::list&prefix_indices) const; + private: NetAssign_*elaborate_lval_net_word_(Design*, NetScope*, NetNet*) const; bool elaborate_lval_net_bit_(Design*, NetScope*, NetAssign_*) const; bool elaborate_lval_net_part_(Design*, NetScope*, NetAssign_*) const; bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, index_component_t::ctype_t) const; + bool elaborate_lval_net_packed_member_(Design*, NetScope*, + NetAssign_*, + const perm_string&) const; private: NetExpr*elaborate_expr_param_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, unsigned expr_wid, @@ -362,21 +377,21 @@ class PEIdent : public PExpr { NetExpr*elaborate_expr_param_part_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, unsigned expr_wid) const; NetExpr*elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const; NetExpr*elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*found, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const; @@ -494,6 +509,10 @@ class PEUnary : public PExpr { unsigned flags) const; virtual verinum* eval_const(Design*des, NetScope*sc) const; + public: + inline char get_op() const { return op_; } + inline PExpr*get_expr() const { return expr_; } + private: NetExpr* elaborate_expr_bits_(NetExpr*operand, unsigned expr_wid) const; diff --git a/PScope.cc b/PScope.cc index f23a506ee..0e5dd4abe 100644 --- a/PScope.cc +++ b/PScope.cc @@ -41,3 +41,18 @@ PWire* LexicalScope::wires_find(perm_string name) else return (*cur).second; } + +PScopeExtra::PScopeExtra(perm_string n, LexicalScope*parent) +: PScope(n, parent) +{ +} + +PScopeExtra::PScopeExtra(perm_string n) +: PScope(n) +{ +} + +PScopeExtra::~PScopeExtra() +{ +} + diff --git a/PScope.h b/PScope.h index a6c11466c..e14cb6b4e 100644 --- a/PScope.h +++ b/PScope.h @@ -27,8 +27,10 @@ class PEvent; class PExpr; +class PFunction; class AProcess; class PProcess; +class PTask; class PWire; class Design; @@ -83,6 +85,9 @@ class LexicalScope { mapparameters; maplocalparams; + // Defined types in the scope. + maptypedefs; + // Named events in the scope. mapevents; @@ -105,6 +110,8 @@ class LexicalScope { LexicalScope* parent_scope() const { return parent_; } protected: + void dump_typedefs_(ostream&out, unsigned indent) const; + void dump_parameters_(ostream&out, unsigned indent) const; void dump_localparams_(ostream&out, unsigned indent) const; @@ -145,4 +152,21 @@ class PScope : public LexicalScope { perm_string name_; }; +/* + * Some scopes can carry definitions. These include Modules and PClass + * scopes. These derive from PScopeExtra so that they hold the maps of + * extra definitions. + */ +class PScopeExtra : public PScope { + + public: + PScopeExtra(perm_string, LexicalScope*parent); + PScopeExtra(perm_string); + ~PScopeExtra(); + + /* Task definitions within this module */ + map tasks; + map funcs; +}; + #endif diff --git a/PTask.h b/PTask.h index b06375dfc..aeb30419d 100644 --- a/PTask.h +++ b/PTask.h @@ -1,7 +1,7 @@ #ifndef __PTask_H #define __PTask_H /* - * Copyright (c) 1999-2008,2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2008,2010,2012 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 @@ -41,12 +41,14 @@ enum PTaskFuncEnum { PTF_REALTIME, PTF_TIME, PTF_ATOM2, - PTF_ATOM2_S + PTF_ATOM2_S, + PTF_STRING, + PTF_VOID }; struct PTaskFuncArg { PTaskFuncEnum type; - vector*range; + std::list*range; }; /* diff --git a/PWire.cc b/PWire.cc index 6187528ca..4539bba17 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,9 +28,9 @@ PWire::PWire(perm_string n, ivl_variable_type_t dt) : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), - port_msb_(0), port_lsb_(0), port_set_(false), - net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), - error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), discipline_(0) + port_set_(false), net_set_(false), is_scalar_(false), + error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), + discipline_(0) { if (t == NetNet::INTEGER) { type_ = NetNet::REG; @@ -148,8 +148,9 @@ bool PWire::get_scalar() const return is_scalar_; } -void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) +void PWire::set_range_scalar(PWSRType type) { + is_scalar_ = true; switch (type) { case SR_PORT: if (port_set_) { @@ -157,10 +158,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared a port." << endl; error_cnt_ += 1; } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - is_scalar_ = is_scalar; } return; @@ -170,10 +168,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared." << endl; error_cnt_ += 1; } else { - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; } return; @@ -190,13 +185,58 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) error_cnt_ += 1; } } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; + } + return; + } +} + +void PWire::set_range(const list&rlist, PWSRType type) +{ + switch (type) { + case SR_PORT: + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } else { + port_ = rlist; + port_set_ = true; + is_scalar_ = false; + } + return; + + case SR_NET: + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } else { + net_ = rlist; + net_set_ = true; + is_scalar_ = false; + } + return; + + case SR_BOTH: + if (port_set_ || net_set_) { + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } + } else { + port_ = rlist; + port_set_ = true; + net_ = rlist; + net_set_ = true; + is_scalar_ = false; } return; } @@ -217,9 +257,17 @@ void PWire::set_memory_idx(PExpr*ldx, PExpr*rdx) void PWire::set_enumeration(enum_type_t*enum_type) { assert(enum_type_ == 0); + assert(struct_type_ == 0); enum_type_ = enum_type; } +void PWire::set_struct_type(struct_type_t*type) +{ + assert(enum_type_ == 0); + assert(struct_type_ == 0); + struct_type_ = type; +} + void PWire::set_discipline(ivl_discipline_t d) { assert(discipline_ == 0); diff --git a/PWire.h b/PWire.h index 680593edb..23c496ba5 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef __PWire_H #define __PWire_H /* - * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009,2012 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 @@ -21,8 +21,8 @@ # include "netlist.h" # include "LineInfo.h" +# include # include -# include "svector.h" # include "StringHeap.h" #ifdef HAVE_IOSFWD @@ -75,11 +75,13 @@ class PWire : public LineInfo { bool set_data_type(ivl_variable_type_t dt); ivl_variable_type_t get_data_type() const; - void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar); + void set_range_scalar(PWSRType type); + void set_range(const std::list&ranges, PWSRType type); void set_memory_idx(PExpr*ldx, PExpr*rdx); void set_enumeration(enum_type_t*enum_type); + void set_struct_type(struct_type_t*type); void set_discipline(ivl_discipline_t); ivl_discipline_t get_discipline(void) const; @@ -100,12 +102,14 @@ class PWire : public LineInfo { bool isint_; // original type of integer // These members hold expressions for the bit width of the - // wire. If they do not exist, the wire is 1 bit wide. - PExpr*port_msb_; - PExpr*port_lsb_; + // wire. If they do not exist, the wire is 1 bit wide. If they + // do exist, they represent the packed dimensions of the + // bit. The first item in the list is the first range, and so + // on. For example "reg [3:0][7:0] ..." will contains the + // range_t object for [3:0] first and [7:0] last. + std::listport_; bool port_set_; - PExpr*net_msb_; - PExpr*net_lsb_; + std::listnet_; bool net_set_; bool is_scalar_; unsigned error_cnt_; @@ -116,6 +120,7 @@ class PWire : public LineInfo { PExpr*ridx_; enum_type_t*enum_type_; + struct_type_t*struct_type_; ivl_discipline_t discipline_; diff --git a/Statement.cc b/Statement.cc index e726099bb..a99e8b37e 100644 --- a/Statement.cc +++ b/Statement.cc @@ -276,9 +276,8 @@ PForever::~PForever() } PForStatement::PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st) -: name1_(n1), expr1_(e1), cond_(cond), name2_(n2), expr2_(e2), - statement_(st) + Statement*step, Statement*st) +: name1_(n1), expr1_(e1), cond_(cond), step_(step), statement_(st) { } diff --git a/Statement.h b/Statement.h index cef5833c1..049aa118e 100644 --- a/Statement.h +++ b/Statement.h @@ -196,18 +196,6 @@ class PCallTask : public Statement { const pform_name_t& path() const; - unsigned nparms() const { return parms_.size(); } - - PExpr*&parm(unsigned idx) - { assert(idx < parms_.size()); - return parms_[idx]; - } - - PExpr* parm(unsigned idx) const - { assert(idx < parms_.size()); - return parms_[idx]; - } - virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -403,7 +391,7 @@ class PForStatement : public Statement { public: PForStatement(PExpr*n1, PExpr*e1, PExpr*cond, - PExpr*n2, PExpr*e2, Statement*st); + Statement*step, Statement*body); ~PForStatement(); virtual NetProc* elaborate(Design*des, NetScope*scope) const; @@ -417,8 +405,7 @@ class PForStatement : public Statement { PExpr*cond_; - PExpr* name2_; - PExpr* expr2_; + Statement*step_; Statement*statement_; }; diff --git a/cadpli/Makefile.in b/cadpli/Makefile.in index 2aa370ea7..24f52ebab 100644 --- a/cadpli/Makefile.in +++ b/cadpli/Makefile.in @@ -47,8 +47,6 @@ CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ LDFLAGS = @LDFLAGS@ -SHARED = @shared@ - O = cadpli.o all: dep cadpli.vpl $(ALL32) @@ -80,7 +78,7 @@ ifeq (@MINGW32@,yes) endif cadpli.vpl: $O ../vvp/libvpi.a ../libveriuser/libveriuser.o - $(CC) @shared@ -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O ../libveriuser/libveriuser.o $(SYSTEM_VPI_LDFLAGS) install: all installdirs $(vpidir)/cadpli.vpl diff --git a/cppcheck.sup b/cppcheck.sup index 31acd1554..0c003b15d 100644 --- a/cppcheck.sup +++ b/cppcheck.sup @@ -1,3 +1,3 @@ // These are correct and are used to find the base (zero) pin. -thisSubtraction:netlist.h:4168 -thisSubtraction:netlist.h:4177 +thisSubtraction:netlist.h:4169 +thisSubtraction:netlist.h:4178 diff --git a/design_dump.cc b/design_dump.cc index 3ebeaae5f..e3d14f3b0 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -187,6 +187,15 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } +ostream&operator<<(ostream&out, const list&rlist) +{ + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + out << "[" << cur->msb << ":" << cur->lsb << "]"; + } + return out; +} + /* Dump a net. This can be a wire or register. */ void NetNet::dump_net(ostream&o, unsigned ind) const { @@ -212,11 +221,16 @@ void NetNet::dump_net(ostream&o, unsigned ind) const case NetNet::PINOUT: o << " inout"; break; + case NetNet::PREF: + o <<" ref"; + break; } if (ivl_discipline_t dis = get_discipline()) o << " discipline=" << dis->name(); + o << " packed dims: " << packed_dims_; + o << " (eref=" << peek_eref() << ", lref=" << peek_lref() << ")"; if (scope()) o << " scope=" << scope_path(scope()); @@ -1045,8 +1059,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const if (result_sig_) { o << setw(ind+2) << "" << "Return signal: "; if (result_sig_->get_signed()) o << "+"; - o << result_sig_->name() << "[" << result_sig_->msb() << ":" - << result_sig_->lsb() << "]" << endl; + o << result_sig_->name() << result_sig_->packed_dims() << endl; } o << setw(ind+2) << "" << "Arguments: "; if (port_count() == 0) o << ""; @@ -1068,8 +1081,7 @@ void NetFuncDef::dump(ostream&o, unsigned ind) const break; } if (port(idx)->get_signed()) o << "+"; - o << port(idx)->name() << "[" << port(idx)->msb() << ":" - << port(idx)->lsb() << "]" << endl; + o << port(idx)->name() << port(idx)->packed_dims() << endl; } if (statement_) statement_->dump(o, ind+2); @@ -1509,7 +1521,7 @@ void NetESignal::dump(ostream&o) const o << "+"; o << name(); if (word_) o << "[word=" << *word_ << "]"; - o << "[" << msi()<<":"<packed_dims(); } void NetETernary::dump(ostream&o) const diff --git a/driver/Makefile.in b/driver/Makefile.in index 7a1930bb9..c6f3e4922 100644 --- a/driver/Makefile.in +++ b/driver/Makefile.in @@ -79,11 +79,13 @@ dep: iverilog@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o iverilog@EXEEXT@ @EXTRALIBS@ -cflexor.c: cflexor.lex - $(LEX) -s -ocflexor.c $(srcdir)/cflexor.lex +cflexor.c: $(srcdir)/cflexor.lex + $(LEX) -s -t $< > $@ -cfparse.h cfparse.c: cfparse.y - $(YACC) --verbose -t -d -o cfparse.c --name-prefix=cf $(srcdir)/cfparse.y +# Build this in two steps to avoid parallel build issues (see pr3462585) +cfparse.c: $(srcdir)/cfparse.y + $(YACC) --verbose -t -p cf -d -o $@ $< +cfparse.h: cfparse.c %.o: %.c $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o diff --git a/elab_expr.cc b/elab_expr.cc index ad24ecff3..992fc5d0e 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -29,6 +29,7 @@ # include "netenum.h" # include "discipline.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -1418,6 +1419,50 @@ static NetExpr* check_for_enum_methods(const LineInfo*li, return sys_expr; } +/* + * If the method matches a structure member then return the member otherwise + * return 0. Also return the offset of the member. + */ +static const netstruct_t::member_t*get_struct_member(const LineInfo*li, + Design*des, NetScope*, + NetNet*net, + perm_string method_name, + unsigned long&off) +{ + netstruct_t*type = net->struct_type(); + ivl_assert(*li, type); + + if (! type->packed()) { + cerr << li->get_fileline() + << ": sorry: unpacked structures not supported here. " + << "Method=" << method_name << endl; + des->errors += 1; + return 0; + } + + return type->packed_member(method_name, off); +} + +static NetExpr* check_for_struct_members(const LineInfo*li, + Design*des, NetScope*, + NetNet*net, perm_string method_name) +{ + unsigned long off; + const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net, + method_name, off); + if (mem == 0) return 0; + + if (debug_elaborate) { + cerr << li->get_fileline() << ": debug: Found struct member " <name + << " At offset " << off << endl; + } + + NetESignal*sig = new NetESignal(net); + NetEConst*base = make_const_val(off); + NetESelect*sel = new NetESelect(sig, base, mem->width()); + return sel; +} + NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, unsigned expr_wid, unsigned flags) const { @@ -1456,8 +1501,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -1472,6 +1516,7 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope, expr_wid, tmp, parms_.size()); } + } } @@ -1823,6 +1868,17 @@ NetExpr* PEFNumber::elaborate_expr(Design*, NetScope*, unsigned, unsigned) const return tmp; } +bool PEIdent::calculate_packed_indices_(Design*des, NetScope*scope, NetNet*net, + list&prefix_indices) const +{ + list index; + index = path_.back().index; + for (size_t idx = 0 ; idx < net->array_dimensions() ; idx += 1) + index.pop_front(); + + return evaluate_index_prefix(des, scope, prefix_indices, index); +} + /* * Given that the msb_ and lsb_ are part select expressions, this * function calculates their values. Note that this method does *not* @@ -1968,7 +2024,8 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) const NetExpr*ex1, *ex2; - symbol_search(0, des, scope, path_, net, par, eve, ex1, ex2); + NetScope*found_in = symbol_search(0, des, scope, path_, net, par, eve, + ex1, ex2); // If there is a part/bit select expression, then process it // here. This constrains the results no matter what kind the @@ -2104,6 +2161,37 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) return expr_width_; } + // If this is SystemVerilog then maybe this is a structure element. + if (gn_system_verilog() && found_in==0 && path_.size() >= 2) { + pform_name_t use_path = path_; + perm_string method_name = peek_tail_name(use_path); + use_path.pop_back(); + + found_in = symbol_search(this, des, scope, use_path, + net, par, eve, ex1, ex2); + + // Check to see if we have a net and if so is it a structure? + if (net != 0) { + // If this net is a struct, the method name may be + // a struct member. + if (net->struct_type() != 0) { + ivl_assert(*this, use_path.back().index.empty()); + + const netstruct_t::member_t*mem; + unsigned long unused; + mem = get_struct_member(this, des, scope, net, + method_name, unused); + if (mem) { + expr_type_ = mem->data_type(); + expr_width_ = mem->width(); + min_width_ = expr_width_; + signed_flag_ = mem->get_signed(); + return expr_width_; + } + } + } + } + // Not a net, and not a parameter? Give up on the type, but // set the width to 0. expr_type_ = IVL_VT_NO_TYPE; @@ -2289,8 +2377,9 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // enumeration? If so then check to see if this is an // enumeration method call. if (net != 0) { - netenum_t*netenum = net->enumeration(); - if (netenum) { + // If this net is actually an enum, the method may + // be an enumeration method. + if (netenum_t*netenum = net->enumeration()) { // We may need the net expression for the // enumeration variable so get it. NetESignal*expr = new NetESignal(net); @@ -2303,6 +2392,16 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, use_path, method_name, expr, expr_wid, NULL, 0); } + + // If this net is a struct, the method name may be + // a struct member. + if (net->struct_type() != 0) { + ivl_assert(*this, use_path.back().index.empty()); + + return check_for_struct_members(this, des, scope, + net, method_name); + } + } } @@ -2540,7 +2639,7 @@ static void warn_param_ob(long par_msv, long par_lsv, bool defined, NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const @@ -2613,6 +2712,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, base = normalize_variable_base(base, par_msv, par_lsv, wid, true); NetExpr*tmp = par->dup_expr(); + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_UP); tmp->set_line(*this); return tmp; @@ -2620,7 +2725,7 @@ NetExpr* PEIdent::elaborate_expr_param_idx_up_(Design*des, NetScope*scope, NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, const NetExpr*par, - NetScope*, + NetScope*found_in, const NetExpr*par_msb, const NetExpr*par_lsb, bool need_const) const @@ -2694,6 +2799,12 @@ NetExpr* PEIdent::elaborate_expr_param_idx_do_(Design*des, NetScope*scope, base = normalize_variable_base(base, par_msv, par_lsv, wid, false); NetExpr*tmp = par->dup_expr(); + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); tmp = new NetESelect(tmp, base, wid, IVL_SEL_IDX_DOWN); tmp->set_line(*this); return tmp; @@ -2748,8 +2859,14 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, // rewritten in the above format, as I get to it. NetExpr*tmp = par->dup_expr(); - if (!tmp) - return 0; + if (!tmp) return 0; + + /* The numeric parameter value needs to have the file and line + * information for the actual parameter not the expression. */ + if (! dynamic_cast(tmp)) { + NetScope::param_ref_t pref = found_in->find_parameter(peek_tail_name(path_)); + tmp->set_line((*pref).second); + } if (use_sel == index_component_t::SEL_BIT) { ivl_assert(*this, !name_tail.index.empty()); @@ -2846,6 +2963,7 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, NetEConst*re2 = new NetEConst(verinum(rb, 1)); + re2->set_line(*this); delete tmp; delete mtmp; tmp = re2; @@ -2911,7 +3029,6 @@ NetExpr* PEIdent::elaborate_expr_param_(Design*des, } } - tmp->set_line(*this); return tmp; } @@ -3041,6 +3158,10 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, NetESignal*net, NetScope*, unsigned expr_wid) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + long msv, lsv; bool parts_defined_flag; bool flag = calculate_parts_(des, scope, msv, lsv, parts_defined_flag); @@ -3073,9 +3194,8 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, tmp->set_line(*this); return tmp; } - - long sb_lsb = net->sig()->sb_to_idx(lsv); - long sb_msb = net->sig()->sb_to_idx(msv); + long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv); + long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv); if (sb_msb < sb_lsb) { cerr << get_fileline() << ": error: part select " << net->name(); @@ -3147,6 +3267,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; @@ -3160,27 +3284,32 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, NetExpr*ex; if (base_c->value().is_defined()) { long lsv = base_c->value().as_long(); + long offset = 0; + // Get the signal range. + const list&packed = net->sig()->packed_dims(); + ivl_assert(*this, packed.size() == prefix_indices.size()+1); + + // We want the last range, which is where we work. + const NetNet::range_t&rng = packed.back(); + if (rng.msb < rng.lsb) { + offset = -wid + 1; + } + + long rel_base = net->sig()->sb_to_idx(prefix_indices, lsv); // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sig()->sb_to_idx(lsv) == 0 && - wid == net->vector_width()) { + if (rel_base == 0 && wid == net->vector_width()) { delete base; net->cast_signed(false); return net; } - long offset = 0; - if (net->msi() < net->lsi()) { - offset = -wid + 1; - } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + - offset)); + ex = new NetEConst(verinum(rel_base + offset)); if (warn_ob_select) { - long rel_base = net->sig()->sb_to_idx(lsv) + offset; if (rel_base < 0) { cerr << get_fileline() << ": warning: " << net->name(); @@ -3216,7 +3345,12 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, return ss; } - base = normalize_variable_base(base, net->msi(), net->lsi(), wid, true); + + ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size()); + + // Convert the non-constant part select index expression into + // an expression that returns a canonical base. + base = normalize_variable_part_base(prefix_indices, base, net->sig(), wid, true); NetESelect*ss = new NetESelect(net, base, wid, IVL_SEL_IDX_UP); ss->set_line(*this); @@ -3236,6 +3370,10 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + NetExpr*base = calculate_up_do_base_(des, scope, need_const); unsigned long wid = 0; @@ -3252,7 +3390,7 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, // If the part select covers exactly the entire // vector, then do not bother with it. Return the // signal itself. - if (net->sig()->sb_to_idx(lsv) == (signed) (wid-1) && + if (net->sig()->sb_to_idx(prefix_indices,lsv) == (signed) (wid-1) && wid == net->vector_width()) { delete base; net->cast_signed(false); @@ -3265,10 +3403,9 @@ NetExpr* PEIdent::elaborate_expr_net_idx_do_(Design*des, NetScope*scope, } // Otherwise, make a part select that covers the right // range. - ex = new NetEConst(verinum(net->sig()->sb_to_idx(lsv) + - offset)); + ex = new NetEConst(verinum(net->sig()->sb_to_idx(prefix_indices,lsv) + offset)); if (warn_ob_select) { - long rel_base = net->sig()->sb_to_idx(lsv) + offset; + long rel_base = net->sig()->sb_to_idx(prefix_indices,lsv) + offset; if (rel_base < 0) { cerr << get_fileline() << ": warning: " << net->name(); @@ -3321,6 +3458,10 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetESignal*net, NetScope*, bool need_const) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, net->sig(), prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back(); ivl_assert(*this, !name_tail.index.empty()); @@ -3328,12 +3469,12 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, ivl_assert(*this, index_tail.msb != 0); ivl_assert(*this, index_tail.lsb == 0); - NetExpr*ex = elab_and_eval(des, scope, index_tail.msb, -1, need_const); + NetExpr*mux = elab_and_eval(des, scope, index_tail.msb, -1, need_const); // If the bit select is constant, then treat it similar // to the part select, so that I save the effort of // making a mux part in the netlist. - if (NetEConst*msc = dynamic_cast (ex)) { + if (NetEConst*msc = dynamic_cast (mux)) { // Special case: The bit select expression is constant // x/z. The result of the expression is 1'bx. @@ -3354,12 +3495,35 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetEConst*tmp = make_const_x(1); tmp->set_line(*this); - delete ex; + delete mux; return tmp; } long msv = msc->value().as_long(); - long idx = net->sig()->sb_to_idx(msv); + + const list& sig_packed = net->sig()->packed_dims(); + if (prefix_indices.size()+2 <= sig_packed.size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // ... x[2] ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + unsigned long lwid; + long idx; + rc = net->sig()->sb_to_slice(prefix_indices, msv, idx, lwid); + + // Make an expression out of the index + NetEConst*idx_c = new NetEConst(verinum(idx)); + idx_c->set_line(*net); + + NetESelect*res = new NetESelect(net, idx_c, lwid); + res->set_line(*net); + return res; + } + + long idx = net->sig()->sb_to_idx(prefix_indices,msv); if (idx >= (long)net->vector_width() || idx < 0) { /* The bit select is out of range of the @@ -3375,8 +3539,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, else cerr << "vector "; cerr << net->name(); if (net->word_index()) cerr << "[]"; - cerr << "[" << net->sig()->msb() << ":" - << net->sig()->lsb() << "]." << endl; + cerr << net->sig()->packed_dims() << "." << endl; cerr << get_fileline() << ": : " << "Replacing select with a constant 1'bx." << endl; @@ -3385,7 +3548,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, NetEConst*tmp = make_const_x(1); tmp->set_line(*this); - delete ex; + delete mux; return tmp; } @@ -3405,15 +3568,35 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } + const list& sig_packed = net->sig()->packed_dims(); + if (prefix_indices.size()+2 <= sig_packed.size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // x[2] = ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + unsigned long lwid; + mux = normalize_variable_slice_base(prefix_indices, mux, + net->sig(), lwid); + mux->set_line(*net); + + // Make a PART select with the canonical index + NetESelect*res = new NetESelect(net, mux, lwid); + res->set_line(*net); + + return res; + } + // Non-constant bit select? punt and make a subsignal // device to mux the bit in the net. This is a fairly // complicated task because we need to generate // expressions to convert calculated bit select // values to canonical values that are used internally. - ex = normalize_variable_base(ex, net->sig()->msb(), net->sig()->lsb(), - 1, true); + mux = normalize_variable_bit_base(prefix_indices, mux, net->sig()); - NetESelect*ss = new NetESelect(net, ex, 1); + NetESelect*ss = new NetESelect(net, mux, 1); ss->set_line(*this); return ss; } @@ -3446,6 +3629,10 @@ NetExpr* PEIdent::elaborate_expr_net(Design*des, NetScope*scope, return 0; } + list prefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, path_.back().index); + if (!rc) return 0; + // If this is a part select of a signal, then make a new // temporary signal that is connected to just the // selected bits. The lsb_ and msb_ expressions are from diff --git a/elab_lval.cc b/elab_lval.cc index 1997f89f3..2cfb98016 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -22,6 +22,7 @@ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "compiler.h" # include # include @@ -152,8 +153,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, NetNet* reg = 0; const NetExpr*par = 0; NetEvent* eve = 0; + perm_string method_name; symbol_search(this, des, scope, path_, reg, par, eve); + + /* If the signal is not found, check to see if this is a + member of a struct. Take the name of the form "a.b.member", + remove the member and store it into method_name, and retry + the search with "a.b". */ + if (reg == 0 && path_.size() >= 2) { + pform_name_t use_path = path_; + method_name = peek_tail_name(use_path); + use_path.pop_back(); + symbol_search(this, des, scope, use_path, reg, par, eve); + + if (reg && reg->struct_type() == 0) { + method_name = perm_string(); + reg = 0; + } + } + if (reg == 0) { cerr << get_fileline() << ": error: Could not find variable ``" << path_ << "'' in ``" << scope_path(scope) << @@ -164,16 +183,26 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } ivl_assert(*this, reg); - + // We are processing the tail of a string of names. For + // example, the verilog may be "a.b.c", so we are processing + // "c" at this point. const name_component_t&name_tail = path_.back(); + // Use the last index to determine what kind of select + // (bit/part/etc) we are processing. For example, the verilog + // may be "a.b.c[1][2][]". All but the last index must + // be simple expressions, only the may be a part + // select etc., so look at it to determine how we will be + // proceeding. index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; if (!name_tail.index.empty()) use_sel = name_tail.index.back().sel; - // This is the special case that the l-value is an entire - // memory. This is, in fact, an error. - if (reg->array_dimensions() > 0 && name_tail.index.empty()) { + // Special case: The l-value is an entire memory, or array + // slice. This is, in fact, an error in l-values. Detect the + // situation by noting if the index count is less than the + // array dimensions (unpacked). + if (reg->array_dimensions() > name_tail.index.size()) { cerr << get_fileline() << ": error: Cannot assign to array " << path_ << ". Did you forget a word index?" << endl; des->errors += 1; @@ -181,7 +210,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } /* Get the signal referenced by the identifier, and make sure - it is a register. Wires are not allows in this context, + it is a register. Wires are not allowed in this context, unless this is the l-value of a force. */ if ((reg->type() != NetNet::REG) && !is_force) { cerr << get_fileline() << ": error: " << path_ << @@ -193,6 +222,12 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return 0; } + if (reg->struct_type() && !method_name.nil()) { + NetAssign_*lv = new NetAssign_(reg); + elaborate_lval_net_packed_member_(des, scope, lv, method_name); + return lv; + } + if (reg->array_dimensions() > 0) return elaborate_lval_net_word_(des, scope, reg); @@ -322,7 +357,13 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, NetScope*scope, NetAssign_*lv) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + if (!rc) return false; + const name_component_t&name_tail = path_.back(); + ivl_assert(*this, !name_tail.index.empty()); + const index_component_t&index_tail = name_tail.index.back(); ivl_assert(*this, index_tail.msb != 0); ivl_assert(*this, index_tail.lsb == 0); @@ -340,20 +381,43 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, mux = 0; } - if (mux) { - // Non-constant bit mux. Correct the mux for the range - // of the vector, then set the l-value part select expression. - mux = normalize_variable_base(mux, reg->msb(), reg->lsb(), 1, true); + if (prefix_indices.size()+2 <= reg->packed_dims().size()) { + // Special case: this is a slice of a multi-dimensional + // packed array. For example: + // reg [3:0][7:0] x; + // x[2] = ... + // This shows up as the prefix_indices being too short + // for the packed dimensions of the vector. What we do + // here is convert to a "slice" of the vector. + if (mux == 0) { + long loff; + unsigned long lwid; + bool rcl = reg->sb_to_slice(prefix_indices, lsb, loff, lwid); + ivl_assert(*this, rcl); + + lv->set_part(new NetEConst(verinum(loff)), lwid); + } else { + unsigned long lwid; + mux = normalize_variable_slice_base(prefix_indices, mux, + reg, lwid); + lv->set_part(mux, lwid); + } + + } else if (mux) { + // Non-constant bit mux. Correct the mux for the range + // of the vector, then set the l-value part select + // expression. + mux = normalize_variable_bit_base(prefix_indices, mux, reg); lv->set_part(mux, 1); - } else if (lsb == reg->msb() && lsb == reg->lsb()) { + } else if (reg->vector_width() == 1 && reg->sb_is_valid(prefix_indices,lsb)) { // Constant bit mux that happens to select the only bit // of the l-value. Don't bother with any select at all. } else { // Constant bit select that does something useful. - long loff = reg->sb_to_idx(lsb); + long loff = reg->sb_to_idx(prefix_indices,lsb); if (loff < 0 || loff >= (long)reg->vector_width()) { cerr << get_fileline() << ": error: bit select " @@ -373,6 +437,10 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, NetScope*scope, NetAssign_*lv) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + ivl_assert(*this, rc); + // The range expressions of a part select must be // constant. The calculate_parts_ function calculates the // values into msb and lsb. @@ -385,41 +453,50 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, ivl_assert(*this, parts_defined_flag); NetNet*reg = lv->sig(); - assert(reg); + ivl_assert(*this, reg); - if (msb == reg->msb() && lsb == reg->lsb()) { + const list&packed = reg->packed_dims(); - /* Part select covers the entire vector. Simplest case. */ - - } else { - - /* Get the canonical offsets into the vector. */ - long loff = reg->sb_to_idx(lsb); - long moff = reg->sb_to_idx(msb); - long wid = moff - loff + 1; - - if (moff < loff) { - cerr << get_fileline() << ": error: part select " - << reg->name() << "[" << msb<<":"<errors += 1; - return false; - } - - /* If the part select extends beyond the extremes of the - variable, then report an error. Note that loff is - converted to normalized form so is relative the - variable pins. */ - - if (loff < 0 || moff >= (signed)reg->vector_width()) { - cerr << get_fileline() << ": warning: Part select " - << reg->name() << "[" << msb<<":"<set_part(new NetEConst(verinum(loff)), wid); + // Part selects cannot select slices. So there must be enough + // prefix_indices to get all the way to the final dimension. + if (prefix_indices.size()+1 < packed.size()) { + cerr << get_fileline() << ": error: Cannot select a range " + << "of slices from a packed array." << endl; + des->errors += 1; + return false; } + long loff = reg->sb_to_idx(prefix_indices,lsb); + long moff = reg->sb_to_idx(prefix_indices,msb); + long wid = moff - loff + 1; + + if (moff < loff) { + cerr << get_fileline() << ": error: part select " + << reg->name() << "[" << msb<<":"<errors += 1; + return false; + } + + // Special case: The range winds up selecting the entire + // vector. Treat this as no part select at all. + if (loff == 0 && moff == (long)(reg->vector_width()-1)) { + return true; + } + + /* If the part select extends beyond the extremes of the + variable, then report an error. Note that loff is + converted to normalized form so is relative the + variable pins. */ + + if (loff < 0 || moff >= (long)reg->vector_width()) { + cerr << get_fileline() << ": warning: Part select " + << reg->name() << "[" << msb<<":"<set_part(new NetEConst(verinum(loff)), wid); + return true; } @@ -428,6 +505,10 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, NetAssign_*lv, index_component_t::ctype_t use_sel) const { + listprefix_indices; + bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back();; ivl_assert(*this, !name_tail.index.empty()); @@ -462,14 +543,20 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, if (base_c->value().is_defined()) { long lsv = base_c->value().as_long(); long offset = 0; - if (((reg->msb() < reg->lsb()) && + // Get the signal range. + const list&packed = reg->packed_dims(); + ivl_assert(*this, packed.size() == prefix_indices.size()+1); + + // We want the last range, which is where we work. + const NetNet::range_t&rng = packed.back(); + if (((rng.msb < rng.lsb) && use_sel == index_component_t::SEL_IDX_UP) || - ((reg->msb() > reg->lsb()) && + ((rng.msb > rng.lsb) && use_sel == index_component_t::SEL_IDX_DO)) { offset = -wid + 1; } delete base; - long rel_base = reg->sb_to_idx(lsv) + offset; + long rel_base = reg->sb_to_idx(prefix_indices,lsv) + offset; /* If we cover the entire lvalue just skip the select. */ if (rel_base == 0 && wid == reg->vector_width()) return true; base = new NetEConst(verinum(rel_base)); @@ -511,15 +598,16 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, } } } else { + ivl_assert(*this, prefix_indices.size()+1 == reg->packed_dims().size()); /* Correct the mux for the range of the vector. */ if (use_sel == index_component_t::SEL_IDX_UP) { - base = normalize_variable_base(base, reg->msb(), reg->lsb(), - wid, true); + base = normalize_variable_part_base(prefix_indices, base, + reg, wid, true); sel_type = IVL_SEL_IDX_UP; } else { // This is assumed to be a SEL_IDX_DO. - base = normalize_variable_base(base, reg->msb(), reg->lsb(), - wid, false); + base = normalize_variable_part_base(prefix_indices, base, + reg, wid, false); sel_type = IVL_SEL_IDX_DOWN; } } @@ -533,6 +621,38 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } +bool PEIdent::elaborate_lval_net_packed_member_(Design*des, + NetScope*, + NetAssign_*lv, + const perm_string&member_name) const +{ + NetNet*reg = lv->sig(); + ivl_assert(*this, reg); + + netstruct_t*struct_type = reg->struct_type(); + ivl_assert(*this, struct_type); + + if (! struct_type->packed()) { + cerr << get_fileline() << ": sorry: Only packed structures " + << "are supported in l-value." << endl; + des->errors += 1; + return false; + } + + unsigned long off; + const netstruct_t::member_t* member = struct_type->packed_member(member_name, off); + + if (member == 0) { + cerr << get_fileline() << ": error: Member " << member_name + << " is not a member of variable " << reg->name() << endl; + des->errors += 1; + return false; + } + + lv->set_part(new NetEConst(verinum(off)), member->width()); + return true; +} + NetAssign_* PENumber::elaborate_lval(Design*des, NetScope*, bool) const { cerr << get_fileline() << ": error: Constant values not allowed " diff --git a/elab_net.cc b/elab_net.cc index 2a7d75400..a39ccfe74 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -22,6 +22,7 @@ # include "PExpr.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "compiler.h" # include @@ -199,6 +200,10 @@ bool PEConcat::is_collapsible_net(Design*des, NetScope*scope) const bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, long&midx, long&lidx) const { + list prefix_indices; + bool rc = calculate_packed_indices_(des, scope, sig, prefix_indices); + ivl_assert(*this, rc); + const name_component_t&name_tail = path_.back(); // Only treat as part/bit selects any index that is beyond the // word selects for an array. This is not an array, then @@ -257,13 +262,13 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } long midx_val = tmp->value().as_long(); - midx = sig->sb_to_idx(midx_val); + midx = sig->sb_to_idx(prefix_indices, midx_val); delete tmp_ex; if (index_tail.sel == index_component_t::SEL_IDX_UP) - lidx = sig->sb_to_idx(midx_val+wid-1); + lidx = sig->sb_to_idx(prefix_indices, midx_val+wid-1); else - lidx = sig->sb_to_idx(midx_val-wid+1); + lidx = sig->sb_to_idx(prefix_indices, midx_val-wid+1); if (midx < lidx) { long tmpx = midx; @@ -312,8 +317,8 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, /* bool flag = */ calculate_parts_(des, scope, msb, lsb, part_defined_flag); ivl_assert(*this, part_defined_flag); - long lidx_tmp = sig->sb_to_idx(lsb); - long midx_tmp = sig->sb_to_idx(msb); + long lidx_tmp = sig->sb_to_idx(prefix_indices, lsb); + long midx_tmp = sig->sb_to_idx(prefix_indices, msb); /* Detect reversed indices of a part select. */ if (lidx_tmp > midx_tmp) { cerr << get_fileline() << ": error: Part select " @@ -369,7 +374,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig, } assert(mval); - midx = sig->sb_to_idx(mval->as_long()); + midx = sig->sb_to_idx(prefix_indices, mval->as_long()); if (midx >= (long)sig->vector_width()) { cerr << get_fileline() << ": error: Index " << sig->name() << "[" << mval->as_long() << "] is out of range." @@ -405,6 +410,7 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, NetNet* sig = 0; const NetExpr*par = 0; NetEvent* eve = 0; + perm_string method_name; symbol_search(this, des, scope, path_, sig, par, eve); @@ -416,6 +422,23 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, return 0; } + /* If the signal is not found, check to see if this is a + member of a struct. Take the name of the form "a.b.member", + remove the member and store it into method_name, and retry + the search with "a.b". */ + if (sig == 0 && path_.size() >= 2) { + pform_name_t use_path = path_; + method_name = peek_tail_name(use_path); + use_path.pop_back(); + symbol_search(this, des, scope, use_path, sig, par, eve); + + // Whoops, not a struct signal, so give up on this avenue. + if (sig && sig->struct_type() == 0) { + method_name = perm_string(); + sig = 0; + } + } + if (sig == 0) { cerr << get_fileline() << ": error: Net " << path_ << " is not defined in this context." << endl; @@ -434,13 +457,6 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, sig->type(NetNet::UNRESOLVED_WIRE); } - if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->pin(0).is_linked()) { - cerr << get_fileline() << ": error: Unresolved net/uwire " - << sig->name() << " cannot have multiple drivers." << endl; - des->errors += 1; - return 0; - } - /* Don't allow registers as assign l-values. */ if (sig->type() == NetNet::REG) { cerr << get_fileline() << ": error: reg " << sig->name() @@ -460,7 +476,26 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, const name_component_t&name_tail = path_.back(); - if (sig->array_dimensions() > 0) { + netstruct_t*struct_type = 0; + if ((struct_type = sig->struct_type()) && !method_name.nil()) { + + // Detect the variable is a structure and there was a + // method name detected. + if (debug_elaborate) + cerr << get_fileline() << ": debug: " + << "Signal " << sig->name() << " is a structure, " + << "try to match member " << method_name << endl; + + unsigned long member_off = 0; + const struct netstruct_t::member_t*member = struct_type->packed_member(method_name, member_off); + ivl_assert(*this, member); + + // Rewrite a member select of a packed structure as a + // part select of the base variable. + lidx = member_off; + midx = lidx + member->width() - 1; + + } else if (sig->array_dimensions() > 0) { if (name_tail.index.empty()) { cerr << get_fileline() << ": error: array " << sig->name() @@ -553,6 +588,14 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope, unsigned subnet_wid = midx-lidx+1; + /* Check if the l-value bits are double-driven. */ + if (sig->type() == NetNet::UNRESOLVED_WIRE && sig->test_part_lref(midx,lidx)) { + cerr << get_fileline() << ": error: Unresolved net/uwire " + << sig->name() << " cannot have multiple drivers." << endl; + des->errors += 1; + return 0; + } + if (sig->pin_count() > 1) { if (widx < 0 || widx >= (long) sig->pin_count()) { cerr << get_fileline() << ": warning: ignoring out of " @@ -659,6 +702,7 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const case NetNet::PINPUT: case NetNet::POUTPUT: case NetNet::PINOUT: + case NetNet::PREF: break; /* If the name matches, but the signal is not a port, @@ -726,6 +770,9 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const sig = tmp; break; + case NetNet::PREF: + // For the purposes of module ports, treat ref ports + // just like inout ports. case NetNet::PINOUT: ps = new NetTran(scope, scope->local_symbol(), sig->vector_width(), swid, lidx); diff --git a/elab_scope.cc b/elab_scope.cc index a93c9a08c..02d46659f 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -133,9 +133,10 @@ static void elaborate_scope_enumeration(Design*des, NetScope*scope, enum_type_t*enum_type) { bool rc_flag; - assert(enum_type->range->size() == 2); - NetExpr*msb_ex = elab_and_eval(des, scope, enum_type->range->front(), -1); - NetExpr*lsb_ex = elab_and_eval(des, scope, enum_type->range->back(), -1); + assert(enum_type->range->size() == 1); + pform_range_t&range = enum_type->range->front(); + NetExpr*msb_ex = elab_and_eval(des, scope, range.first, -1); + NetExpr*lsb_ex = elab_and_eval(des, scope, range.second, -1); long msb = 0; rc_flag = eval_as_long(msb, msb_ex); diff --git a/elab_sig.cc b/elab_sig.cc index 77cab98fe..ca7a1ac73 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -32,6 +32,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "util.h" # include "ivl_assert.h" @@ -84,6 +85,14 @@ bool PScope::elaborate_sig_wires_(Design*des, NetScope*scope) const PWire*cur = (*wt).second; NetNet*sig = cur->elaborate_sig(des, scope); + if (sig && (sig->scope() == scope) + && (sig->port_type() == NetNet::PREF)) { + + cerr << cur->get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + } + /* If the signal is an input and is also declared as a reg, then report an error. */ @@ -467,14 +476,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_REG: case PTF_REG_S: if (return_type_.range) { - ivl_assert(*this, return_type_.range->size() == 2); + ivl_assert(*this, return_type_.range->size() == 1); + pform_range_t&return_range = return_type_.range->front(); NetExpr*me = elab_and_eval(des, scope, - return_type_.range->at(0), -1, + return_range.first, -1, true); assert(me); NetExpr*le = elab_and_eval(des, scope, - return_type_.range->at(1), -1, + return_range.second, -1, true); assert(le); @@ -493,7 +503,9 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const des->errors += 1; } - ret_sig = new NetNet(scope, fname, NetNet::REG, mnum, lnum); + list packed; + packed.push_back(NetNet::range_t(mnum, lnum)); + ret_sig = new NetNet(scope, fname, NetNet::REG, packed); ret_sig->set_scalar(false); } else { @@ -539,17 +551,18 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const case PTF_ATOM2: case PTF_ATOM2_S: - ivl_assert(*this, return_type_.range != 0); long use_wid; { + ivl_assert(*this, return_type_.range->size() == 1); + pform_range_t&return_range = return_type_.range->front(); NetExpr*me = elab_and_eval(des, scope, - (*return_type_.range)[0], -1, + return_range.first, -1, true); - assert(me); + ivl_assert(*this, me); NetExpr*le = elab_and_eval(des, scope, - (*return_type_.range)[1], -1, + return_range.second, -1, true); - assert(le); + ivl_assert(*this, le); long mnum = 0, lnum = 0; if ( ! get_const_argument(me, mnum) ) { @@ -577,6 +590,15 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const ret_sig->data_type(IVL_VT_BOOL); break; + case PTF_STRING: + cerr << get_fileline() << ": sorry: String functions are not supported yet" << endl; + break; + + case PTF_VOID: + // Void functions have no return value, so there is no + // signal to create here. + break; + default: if (ports_) { cerr << get_fileline() << ": internal error: I don't know " @@ -780,6 +802,114 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } +static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, + struct_type_t*struct_type) +{ + netstruct_t*res = new netstruct_t; + + res->packed(struct_type->packed_flag); + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*curp = *cur; + long use_msb = 0; + long use_lsb = 0; + if (curp->range.get() && ! curp->range->empty()) { + ivl_assert(*curp, curp->range->size() == 1); + pform_range_t&rangep = curp->range->front(); + PExpr*msb_pex = rangep.first; + PExpr*lsb_pex = rangep.second; + + NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); + ivl_assert(*curp, tmp); + bool rc = eval_as_long(use_msb, tmp); + ivl_assert(*curp, rc); + + tmp = elab_and_eval(des, scope, lsb_pex, -2, true); + ivl_assert(*curp, tmp); + rc = eval_as_long(use_lsb, tmp); + ivl_assert(*curp, rc); + } + + for (list::iterator name = curp->names->begin() + ; name != curp->names->end() ; ++ name) { + decl_assignment_t*namep = *name; + + netstruct_t::member_t memb; + memb.name = namep->name; + memb.type = curp->type; + memb.msb = use_msb; + memb.lsb = use_lsb; + res->append_member(memb); + } + } + + return res; +} + +static bool evaluate_ranges(Design*des, NetScope*scope, + list&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + NetNet::range_t lrng; + + NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); + if (! eval_as_long(lrng.msb, texpr)) { + cerr << cur->first->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->first->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->first << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->second, -1, true); + if (! eval_as_long(lrng.lsb, texpr)) { + cerr << cur->second->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->second->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->second << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(lrng); + } + + return bad_msb | bad_lsb; +} + +bool test_ranges_eeq(const list&lef, const list&rig) +{ + if (lef.size() != rig.size()) + return false; + + list::const_iterator lcur = lef.begin(); + list::const_iterator rcur = rig.begin(); + while (lcur != lef.end()) { + if (lcur->msb != rcur->msb) + return false; + if (lcur->lsb != rcur->lsb) + return false; + + ++ lcur; + ++ rcur; + } + + return true; +} + /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -801,7 +931,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } unsigned wid = 1; - long lsb = 0, msb = 0; + listpacked_dimensions; des->errors += error_cnt_; @@ -841,135 +971,74 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } if (port_set_ || net_set_) { - long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; - bool bad_lsb = false, bad_msb = false; + bool bad_range = false; + list plist, nlist; /* If they exist get the port definition MSB and LSB */ - if (port_set_ && port_msb_ != 0) { - NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true); - - if (! eval_as_long(pmsb, texpr)) { - cerr << port_msb_->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << port_msb_->get_fileline() << " : " - "This MSB expression violates the rule: " - << *port_msb_ << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, port_lsb_, -1, true); - - if (! eval_as_long(plsb, texpr)) { - cerr << port_lsb_->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << port_lsb_->get_fileline() << " : " - "This LSB expression violates the rule: " - << *port_lsb_ << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - nmsb = pmsb; - nlsb = plsb; + if (port_set_ && !port_.empty()) { + bad_range |= evaluate_ranges(des, scope, plist, port_); + nlist = plist; /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; } - if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); - if (port_msb_ == 0) assert(port_lsb_ == 0); - if (port_lsb_ == 0) assert(port_msb_ == 0); + assert(port_set_ || port_.empty()); /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { - NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true); - - if (! eval_as_long(nmsb, texpr)) { - cerr << net_msb_->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << net_msb_->get_fileline() << " : " - "This MSB expression violates the rule: " - << *net_msb_ << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, net_lsb_, -1, true); - - if (! eval_as_long(nlsb, texpr)) { - cerr << net_lsb_->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << net_lsb_->get_fileline() << " : " - "This LSB expression violates the rule: " - << *net_lsb_ << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; + if (net_set_ && !net_.empty() && !bad_range) { + nlist.clear(); + bad_range |= evaluate_ranges(des, scope, nlist, net_); } - if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0); - if (net_msb_ == 0) assert(net_lsb_ == 0); - if (net_lsb_ == 0) assert(net_msb_ == 0); + assert(net_set_ || net_.empty()); + + /* If we find errors here, then give up on this signal. */ + if (bad_range) + return 0; /* We have a port size error */ - if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { + if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) { /* Scalar port with a vector net/etc. definition */ - if (port_msb_ == 0) { + if (port_.empty()) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; } else { cerr << get_fileline() << ": error: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; des->errors += 1; return 0; } } /* Vectored port with a scalar net/etc. definition */ - if (net_msb_ == 0) { - cerr << port_msb_->get_fileline() + if (net_.empty()) { + cerr << port_.front().first->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a scalar net declaration at " + << name_ << "'' " << plist + << " has a scalar net declaration at " << get_fileline() << "." << endl; des->errors += 1; return 0; } /* Both vectored, but they have different ranges. */ - if (port_msb_ != 0 && net_msb_ != 0) { - cerr << port_msb_->get_fileline() + if (!port_.empty() && !net_.empty()) { + cerr << port_.front().first->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a net declaration [" << nmsb << ":" - << nlsb << "] at " << net_msb_->get_fileline() + << name_ << "'' " << plist + << " has a net declaration " << nlist + << " at " << net_.front().first->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; } } - /* Attempt to recover from errors. */ - if (bad_lsb) nlsb = 0; - if (bad_msb) nmsb = nlsb; - - lsb = nlsb; - msb = nmsb; - if (nmsb > nlsb) - wid = nmsb - nlsb + 1; - else - wid = nlsb - nmsb + 1; - + packed_dimensions = nlist; + wid = NetNet::vector_width(packed_dimensions); } @@ -1021,13 +1090,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const array_dimensions = 1; } - if (data_type_ == IVL_VT_REAL && (msb != 0 || lsb != 0)) { + if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) { cerr << get_fileline() << ": error: real "; if (wtype == NetNet::REG) cerr << "variable"; else cerr << "net"; cerr << " '" << name_ - << "' cannot be declared as a vector, found a range [" - << msb << ":" << lsb << "]." << endl; + << "' cannot be declared as a vector, found a range " + << packed_dimensions << "." << endl; des->errors += 1; return 0; } @@ -1068,26 +1137,47 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } } - if (debug_elaborate) { - cerr << get_fileline() << ": debug: Create signal " << wtype; - if (!get_scalar()) { - cerr << " ["<packed()) + cerr << " " << use_type->packed_width() << " bit packed struct "; + else + cerr << " struct <> "; + cerr << name_; + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " " << name_; - if (array_dimensions > 0) { - cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + + sig = new NetNet(scope, name_, wtype, use_type); + + } else { + if (debug_elaborate) { + cerr << get_fileline() << ": debug: Create signal " << wtype; + if (!get_scalar()) { + cerr << " " << packed_dimensions; + } + cerr << " " << name_; + if (array_dimensions > 0) { + cerr << " [" << array_s0 << ":" << array_e0 << "]" << endl; + } + cerr << " in scope " << scope_path(scope) << endl; } - cerr << " in scope " << scope_path(scope) << endl; + + sig = array_dimensions > 0 + ? new NetNet(scope, name_, wtype, packed_dimensions, array_s0, array_e0) + : new NetNet(scope, name_, wtype, packed_dimensions); } - - NetNet*sig = array_dimensions > 0 - ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) - : new NetNet(scope, name_, wtype, msb, lsb); - // If this is an enumeration, then set the enumeration set for // the new signal. This turns it into an enumeration. if (enum_type_) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, ! enum_type_->names->empty()); list::const_iterator sample_name = enum_type_->names->begin(); netenum_t*use_enum = scope->enumeration_for_name(sample_name->name); diff --git a/elaborate.cc b/elaborate.cc index ed85ab6b2..cd3ef2d73 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -524,7 +524,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tran device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRAN); + gate = new NetTran(scope, inst_name, IVL_SW_TRAN, + instance_width); } break; @@ -534,7 +535,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtran device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRAN); + gate = new NetTran(scope, inst_name, IVL_SW_RTRAN, + instance_width); } break; @@ -544,7 +546,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tranif0 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0); + gate = new NetTran(scope, inst_name, IVL_SW_TRANIF0, + instance_width); } break; @@ -554,7 +557,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtranif0 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0); + gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF0, + instance_width); } break; @@ -564,7 +568,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "tranif1 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1); + gate = new NetTran(scope, inst_name, IVL_SW_TRANIF1, + instance_width); } break; @@ -574,7 +579,8 @@ NetNode* PGBuiltin::create_gate_for_output_(Design*des, NetScope*scope, << "rtranif1 device." << endl; des->errors += 1; } else { - gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1); + gate = new NetTran(scope, inst_name, IVL_SW_RTRANIF1, + instance_width); } break; @@ -1063,6 +1069,10 @@ NetNet*PGModule::resize_net_to_port_(Design*des, NetScope*scope, ivl_assert(*this, 0); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; + default: ivl_assert(*this, 0); } @@ -1500,6 +1510,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } else { /* Port type must be OUTPUT here. */ + ivl_assert(*this, prts[0]->port_type() == NetNet::POUTPUT); /* Output from module. Elaborate the port expression as the l-value of a continuous @@ -1634,6 +1645,9 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const /* This may not be correct! */ as_signed = prts[0]->get_signed() && sig->get_signed(); break; + case NetNet::PREF: + ivl_assert(*this, 0); + break; default: ivl_assert(*this, 0); } @@ -1780,6 +1794,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } break; + case NetNet::PREF: + cerr << get_fileline() << ": sorry: " + << "Reference ports not supported yet." << endl; + des->errors += 1; + break; + case NetNet::PIMPLICIT: cerr << get_fileline() << ": internal error: " << "Unexpected IMPLICIT port" << endl; @@ -2805,12 +2825,12 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const des->errors += 1; } - unsigned parm_count = nparms(); + unsigned parm_count = parms_.size(); /* Catch the special case that the system task has no parameters. The "()" string will be parsed as a single empty parameter, when we really mean no parameters at all. */ - if ((nparms() == 1) && (parm(0) == 0)) + if ((parm_count== 1) && (parms_[0] == 0)) parm_count = 0; svectoreparms (parm_count); @@ -2818,7 +2838,7 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const perm_string name = peek_tail_name(path_); for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { - PExpr*ex = parm(idx); + PExpr*ex = parms_[idx]; if (ex != 0) { eparms[idx] = elab_sys_task_arg(des, scope, name, idx, ex); } else { @@ -2910,9 +2930,20 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const } assert(def); - if (nparms() != def->port_count()) { + + unsigned parm_count = parms_.size(); + + // Handle special case that the definition has no arguments + // but the parser found a simgle nul argument. This is an + // argument of the parser allowing for the possibility of + // default values for argumets: The parser cannot tell the + // difference between "func()" and "func()". + if (def->port_count() == 0 && parm_count == 1 && parms_[0] == 0) + parm_count = 0; + + if (parm_count != def->port_count()) { cerr << get_fileline() << ": error: Port count mismatch in call to ``" - << path_ << "''. Got " << nparms() + << path_ << "''. Got " << parm_count << " ports, expecting " << def->port_count() << " ports." << endl; des->errors += 1; return 0; @@ -2922,7 +2953,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const /* Handle non-automatic tasks with no parameters specially. There is no need to make a sequential block to hold the generated code. */ - if ((nparms() == 0) && !task->is_auto()) { + if ((parm_count == 0) && !task->is_auto()) { cur = new NetUTask(task); cur->set_line(*this); return cur; @@ -2954,7 +2985,23 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression the r-value. We know by definition that the port is a reg type, so this elaboration is pretty obvious. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { + + if (parms_[idx] == 0 && !gn_system_verilog()) { + cerr << get_fileline() << ": error: " + << "Missing argument " << (idx+1) + << " of call to task." << endl; + des->errors += 1; + continue; + } + + if (parms_[idx] == 0) { + cerr << get_fileline() << ": sorry: " + << "Implicit arguments (arg " << (idx+1) + << ") not supported." << endl; + des->errors += 1; + continue; + } NetNet*port = def->port(idx); assert(port->port_type() != NetNet::NOT_A_PORT); @@ -2965,7 +3012,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const unsigned wid = count_lval_width(lv); ivl_variable_type_t lv_type = lv->expr_type(); - NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_[idx]); + NetExpr*rv = elaborate_rval_expr(des, scope, lv_type, wid, parms_ [idx]); if (NetEEvent*evt = dynamic_cast (rv)) { cerr << evt->get_fileline() << ": error: An event '" << evt->event()->name() << "' can not be a user " @@ -2995,7 +3042,7 @@ NetProc* PCallTask::elaborate_usr(Design*des, NetScope*scope) const expression that can be a target to a procedural assignment, including a memory word. */ - for (unsigned idx = 0 ; idx < nparms() ; idx += 1) { + for (unsigned idx = 0 ; idx < parm_count ; idx += 1) { NetNet*port = def->port(idx); @@ -3774,8 +3821,6 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const const PEIdent*id1 = dynamic_cast(name1_); assert(id1); - const PEIdent*id2 = dynamic_cast(name2_); - assert(id2); NetBlock*top = new NetBlock(NetBlock::SEQU, 0); top->set_line(*this); @@ -3820,32 +3865,15 @@ NetProc* PForStatement::elaborate(Design*des, NetScope*scope) const body->append(tmp); - /* Elaborate the increment assignment statement at the end of - the for loop. This is also a very specific assignment - statement. Put this into the "body" block. */ - sig = des->find_signal(scope, id2->path()); - if (sig == 0) { - cerr << get_fileline() << ": error: Unable to find variable " - << id2->path() << " in for-loop increment expression." << endl; - des->errors += 1; - return body; - } - - assert(sig); - lv = new NetAssign_(sig); - - /* Make the r-value of the increment assignment, and size it - properly. Then use it to build the assignment statement. */ - etmp = elaborate_rval_expr(des, scope, lv->expr_type(), lv->lwidth(), - expr2_); - + /* Now elaborate the for_step statement. I really should do + some error checking here to make sure the step statement + really does step the variable. */ if (debug_elaborate) { - cerr << get_fileline() << ": debug: FOR increment assign: " + cerr << get_fileline() << ": debug: Elaborate for_step statement " << sig->name() << " = " << *etmp << endl; } - NetAssign*step = new NetAssign(lv, etmp); - step->set_line(*this); + NetProc*step = step_->elaborate(des, scope); body->append(step); diff --git a/functor.cc b/functor.cc index 6d5bcebb0..8e128dbe5 100644 --- a/functor.cc +++ b/functor.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,71 +28,71 @@ functor_t::~functor_t() { } -void functor_t::event(class Design*, class NetEvent*) +void functor_t::event(Design*, NetEvent*) { } -void functor_t::signal(class Design*, class NetNet*) +void functor_t::signal(Design*, NetNet*) { } -void functor_t::process(class Design*, class NetProcTop*) +void functor_t::process(Design*, NetProcTop*) { } -void functor_t::lpm_abs(class Design*, class NetAbs*) +void functor_t::lpm_abs(Design*, NetAbs*) { } -void functor_t::lpm_add_sub(class Design*, class NetAddSub*) +void functor_t::lpm_add_sub(Design*, NetAddSub*) { } -void functor_t::lpm_compare(class Design*, class NetCompare*) +void functor_t::lpm_compare(Design*, NetCompare*) { } -void functor_t::lpm_const(class Design*, class NetConst*) +void functor_t::lpm_const(Design*, NetConst*) { } -void functor_t::lpm_divide(class Design*, class NetDivide*) +void functor_t::lpm_divide(Design*, NetDivide*) { } -void functor_t::lpm_literal(class Design*, class NetLiteral*) +void functor_t::lpm_literal(Design*, NetLiteral*) { } -void functor_t::lpm_modulo(class Design*, class NetModulo*) +void functor_t::lpm_modulo(Design*, NetModulo*) { } -void functor_t::lpm_ff(class Design*, class NetFF*) +void functor_t::lpm_ff(Design*, NetFF*) { } -void functor_t::lpm_logic(class Design*, class NetLogic*) +void functor_t::lpm_logic(Design*, NetLogic*) { } -void functor_t::lpm_mult(class Design*, class NetMult*) +void functor_t::lpm_mult(Design*, NetMult*) { } -void functor_t::lpm_mux(class Design*, class NetMux*) +void functor_t::lpm_mux(Design*, NetMux*) { } -void functor_t::lpm_pow(class Design*, class NetPow*) +void functor_t::lpm_pow(Design*, NetPow*) { } -void functor_t::sign_extend(class Design*, class NetSignExtend*) +void functor_t::sign_extend(Design*, NetSignExtend*) { } -void functor_t::lpm_ureduce(class Design*, class NetUReduce*) +void functor_t::lpm_ureduce(Design*, NetUReduce*) { } diff --git a/ivl.def b/ivl.def index 4e57899c5..603c116e8 100644 --- a/ivl.def +++ b/ivl.def @@ -230,6 +230,9 @@ ivl_signal_msb ivl_signal_name ivl_signal_nex ivl_signal_npath +ivl_signal_packed_dimensions +ivl_signal_packed_lsb +ivl_signal_packed_msb ivl_signal_path ivl_signal_port ivl_signal_scope diff --git a/ivl_target.h b/ivl_target.h index 3a1c39b70..fddcf86f5 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -1785,13 +1785,23 @@ extern int ivl_scope_time_units(ivl_scope_t net); * If the signal has been declared with a domain (Verilog-AMS) then * this function will return a non-nil ivl_discipline_t. * - * ivl_signal_msb - * ivl_signal_lsb + * ivl_signal_msb (deprecated) + * ivl_signal_lsb (deprecated) + * ivl_signal_packed_dimensions + * ivl_signal_packed_msb + * ivl_signal_packed_lsb * ivl_signal_width - * These functions return the left and right indices, respectively, - * of the signal. If the signal is a scalar, both return 0. However, - * it doesn't mean that the signal is a scalar if both return 0, one - * can have a vector with 0 as both indices. + * These functions return the msb and lsb packed indices. The + * packed dimensions are declared differently from array + * dimensions, like so: + * reg [4:1][7:0] sig... + * which has two packed dimensions. The [4:1] dimension is the + * first, and so forth. If the signal is a scalar, it has 0 + * dimension. + * + * The ivl_signal_msb/ivl_signal_lsb functions are deprecated + * versions that only work with variables that have less than two + * dimensions. They will return msb==lsb==0 for scalars. * * ivl_signal_port * If the signal is a port to a module, this function returns the @@ -1859,8 +1869,11 @@ extern unsigned ivl_signal_array_count(ivl_signal_t net); extern unsigned ivl_signal_array_addr_swapped(ivl_signal_t net); extern unsigned ivl_signal_dimensions(ivl_signal_t net); extern ivl_discipline_t ivl_signal_discipline(ivl_signal_t net); -extern int ivl_signal_msb(ivl_signal_t net); -extern int ivl_signal_lsb(ivl_signal_t net); +extern unsigned ivl_signal_packed_dimensions(ivl_signal_t net); +extern int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim); +extern int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim); +extern int ivl_signal_msb(ivl_signal_t net) __attribute__((deprecated)); +extern int ivl_signal_lsb(ivl_signal_t net) __attribute__((deprecated)); extern unsigned ivl_signal_width(ivl_signal_t net); extern ivl_signal_port_t ivl_signal_port(ivl_signal_t net); extern int ivl_signal_signed(ivl_signal_t net); @@ -2000,7 +2013,7 @@ extern unsigned ivl_stmt_lineno(ivl_statement_t net); * is the compressed operator used it statements like this: * foo += * The ivl_stmt_opcode() returns null (0) if this is not a compressed - * assignment statment. + * assignment statement. * * - IVL_ST_CASSIGN * This reflects a procedural continuous assignment to an l-value. The diff --git a/ivlpp/Makefile.in b/ivlpp/Makefile.in index 62a799e98..44b800e4b 100644 --- a/ivlpp/Makefile.in +++ b/ivlpp/Makefile.in @@ -69,8 +69,8 @@ Makefile: $(srcdir)/Makefile.in ../config.status ivlpp@EXEEXT@: $O $(CC) $(LDFLAGS) $O -o ivlpp@EXEEXT@ @EXTRALIBS@ -lexor.c: lexor.lex - $(LEX) -olexor.c $(srcdir)/lexor.lex +lexor.c: $(srcdir)/lexor.lex + $(LEX) -t $< > $@ install: all installdirs $(libdir)/ivl$(suffix)/ivlpp@EXEEXT@ diff --git a/lexor.lex b/lexor.lex index a197990fb..01a891437 100644 --- a/lexor.lex +++ b/lexor.lex @@ -4,7 +4,7 @@ %{ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -51,7 +51,7 @@ */ extern YYLTYPE yylloc; -static char* strdupnew(char const *str) +char* strdupnew(char const *str) { return str ? strcpy(new char [strlen(str)+1], str) : 0; } @@ -191,7 +191,7 @@ TU [munpf] ">>>=" { return K_RSS_EQ; } "++" { return K_INCR; } "--" {return K_DECR; } - +"'{" { return K_LP; } /* Watch out for the tricky case of (*). Cannot parse this as "(*" and ")", but since I know that this is really ( * ), replace it @@ -303,11 +303,22 @@ TU [munpf] perm_string tmp = lex_strings.make(yylval.text); map::iterator cur = disciplines.find(tmp); if (cur != disciplines.end()) { + delete[]yylval.text; yylval.discipline = (*cur).second; rc = DISCIPLINE_IDENTIFIER; } } + /* If this identifier names a previously declared type, then + return this as a TYPE_IDENTIFIER instead. */ + if (rc == IDENTIFIER && gn_system_verilog()) { + if (data_type_t*type = pform_test_type_identifier(yylval.text)) { + delete[]yylval.text; + yylval.data_type = type; + rc = TYPE_IDENTIFIER; + } + } + return rc; } @@ -366,8 +377,11 @@ TU [munpf] << "Using SystemVerilog 'N bit vector. Use at least " << "-g2005-sv to remove this warning." << endl; } + generation_t generation_save = generation_flag; + generation_flag = GN_VER2005_SV; yylval.number = make_unsized_binary(yytext); - return BASED_NUMBER; } + generation_flag = generation_save; + return UNBASED_NUMBER; } [0-9][0-9_]* { yylval.number = make_unsized_dec(yytext); diff --git a/libmisc/LineInfo.h b/libmisc/LineInfo.h index f2262b568..357360fad 100644 --- a/libmisc/LineInfo.h +++ b/libmisc/LineInfo.h @@ -1,7 +1,7 @@ #ifndef __LineInfo_H #define __LineInfo_H /* - * Copyright (c) 1999-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2011 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 @@ -40,7 +40,7 @@ class LineInfo { // Get a fully formatted file/lineno string get_fileline() const; - // Set the file/line fro another LineInfo object. + // Set the file/line from another LineInfo object. void set_line(const LineInfo&that); // Access parts of LineInfo data diff --git a/libveriuser/Makefile.in b/libveriuser/Makefile.in index 52154fbbf..557c12fa0 100644 --- a/libveriuser/Makefile.in +++ b/libveriuser/Makefile.in @@ -46,7 +46,6 @@ endif CPPFLAGS = $(INCLUDE_PATH) @CPPFLAGS@ @DEFS@ @PICFLAG@ CFLAGS = @WARNING_FLAGS@ @CFLAGS@ -LDFLAGS = @LDFLAGS@ A = a_close.o a_compare_handles.o a_configure.o a_fetch_argc.o \ a_fetch_argv.o a_fetch_dir.o a_fetch_fullname.o a_fetch_location.o \ diff --git a/net_design.cc b/net_design.cc index 84f4a7a34..3ed2fef8c 100644 --- a/net_design.cc +++ b/net_design.cc @@ -641,8 +641,8 @@ void NetScope::evaluate_parameters(Design*des) cur->second->evaluate_parameters(des); if (debug_scopes) - cerr << ":0" << ": debug: " - << "Evaluate parameters in " << scope_path(this) << endl; + cerr << "debug: " + << "Evaluating parameters in " << scope_path(this) << endl; for (param_ref_t cur = parameters.begin() ; cur != parameters.end() ; ++ cur) { diff --git a/net_link.cc b/net_link.cc index 2ed0588b1..0d99acd90 100644 --- a/net_link.cc +++ b/net_link.cc @@ -278,7 +278,7 @@ bool Nexus::assign_lval() const if (net == 0) continue; - if (net->peek_lref()) + if (net->peek_lref() > 0) return true; } diff --git a/net_tran.cc b/net_tran.cc index 79d9c50f0..e170bb3fc 100644 --- a/net_tran.cc +++ b/net_tran.cc @@ -42,15 +42,15 @@ static bool has_enable(ivl_switch_type_t tt) } } -NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt) -: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt) +NetTran::NetTran(NetScope*scope__, perm_string n, ivl_switch_type_t tt, + unsigned width) +: NetNode(scope__, n, has_enable(tt)? 3 : 2), type_(tt), wid_(width) { pin(0).set_dir(Link::PASSIVE); pin(1).set_dir(Link::PASSIVE); if (pin_count() == 3) { pin(2).set_dir(Link::INPUT); // Enable } - wid_ = 0; part_ = 0; off_ = 0; } diff --git a/netlist.cc b/netlist.cc index d0aad7adf..ef0b6c1a6 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -27,6 +27,7 @@ # include "compiler.h" # include "netlist.h" # include "netmisc.h" +# include "netstruct.h" # include "ivl_assert.h" @@ -450,12 +451,15 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), msb_(npins-1), lsb_(0), dimensions_(0), - s0_(0), e0_(0), eref_count_(0), lref_count_(0) + enumeration_(0), struct_type_(0), discipline_(0), + dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { assert(s); assert(npins>0); + // Synthesize a single range to describe this canonical vector. + packed_dims_.push_back(NetNet::range_t(npins-1, 0)); + Link::DIR dir = Link::PASSIVE; switch (t) { @@ -492,15 +496,15 @@ void NetNet::initialize_dir_(Link::DIR dir) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls) + const list&packed) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), - enumeration_(0), discipline_(0), - msb_(ms), lsb_(ls), + enumeration_(0), struct_type_(0), discipline_(0), dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { + packed_dims_ = packed; assert(s); Link::DIR dir = Link::PASSIVE; @@ -540,15 +544,16 @@ static unsigned calculate_count(long s, long e) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls, long array_s, long array_e) + const list&packed, long array_s, long array_e) : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), - is_scalar_(false), local_flag_(false), enumeration_(0), discipline_(0), - msb_(ms), lsb_(ls), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(0), + discipline_(0), dimensions_(1), s0_(array_s), e0_(array_e), eref_count_(0), lref_count_(0) { + packed_dims_ = packed; ivl_assert(*this, s); if (pin_count() == 0) { cerr << "Array too big [" << array_s << ":" << array_e << "]" << endl; @@ -577,6 +582,52 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, s->add_signal(this); } +static unsigned calculate_count(netstruct_t*type) +{ + long wid = type->packed_width(); + if (wid >= 0) + return wid; + else + return 1; +} + +/* + * When we create a netnet for a packed struct, create a single + * vector with the msb_/lsb_ chosen to name enough bits for the entire + * packed structure. + */ +NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) +: NetObj(s, n, 1), + type_(t), port_type_(NOT_A_PORT), + data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), + is_scalar_(false), local_flag_(false), enumeration_(0), struct_type_(ty), + discipline_(0), + dimensions_(0), s0_(0), e0_(0), + eref_count_(0), lref_count_(0) +{ + packed_dims_.push_back(range_t(calculate_count(ty)-1, 0)); + Link::DIR dir = Link::PASSIVE; + + switch (t) { + case REG: + case IMPLICIT_REG: + dir = Link::OUTPUT; + break; + case SUPPLY0: + dir = Link::OUTPUT; + break; + case SUPPLY1: + dir = Link::OUTPUT; + break; + default: + break; + } + + initialize_dir_(dir); + + s->add_signal(this); +} + NetNet::~NetNet() { if (eref_count_ > 0) { @@ -692,10 +743,16 @@ netenum_t*NetNet::enumeration(void) const void NetNet::set_enumeration(netenum_t*es) { + ivl_assert(*this, struct_type_ == 0); ivl_assert(*this, enumeration_ == 0); enumeration_ = es; } +netstruct_t*NetNet::struct_type(void) const +{ + return struct_type_; +} + ivl_discipline_t NetNet::get_discipline() const { return discipline_; @@ -707,40 +764,121 @@ void NetNet::set_discipline(ivl_discipline_t dis) discipline_ = dis; } -long NetNet::lsb() const +unsigned long NetNet::vector_width(const list&packed) { - return lsb_; + unsigned wid = 1; + for (list::const_iterator cur = packed.begin() + ; cur != packed.end() ; ++cur) { + unsigned use_wid; + if (cur->msb >= cur->lsb) + use_wid = cur->msb - cur->lsb + 1; + else + use_wid = cur->lsb - cur->msb + 1; + wid *= use_wid; + } + + return wid; } -long NetNet::msb() const +bool NetNet::sb_is_valid(const list&indices, long sb) const { - return msb_; -} - -unsigned long NetNet::vector_width() const -{ - if (msb_ > lsb_) - return msb_ - lsb_ + 1; + ivl_assert(*this, indices.size()+1 == packed_dims_.size()); + assert(packed_dims_.size() == 1); + const range_t&rng = packed_dims_.back(); + if (rng.msb >= rng.lsb) + return (sb <= rng.msb) && (sb >= rng.lsb); else - return lsb_ - msb_ + 1; + return (sb <= rng.lsb) && (sb >= rng.msb); } -bool NetNet::sb_is_valid(long sb) const +long NetNet::sb_to_idx(const list&indices, long sb) const { - if (msb_ >= lsb_) - return (sb <= msb_) && (sb >= lsb_); + ivl_assert(*this, indices.size()+1 == packed_dims_.size()); + + list::const_iterator pcur = packed_dims_.end(); + -- pcur; + + long acc_off; + long acc_wid = pcur->width(); + if (pcur->msb >= pcur->lsb) + acc_off = sb - pcur->lsb; else - return (sb <= lsb_) && (sb >= msb_); + acc_off = pcur->lsb - sb; + + // The acc_off is the possition within the innermost + // dimension. If this is a multi-dimension packed array then + // we need to add in the canonical address of the current slice. + if (indices.size() >= 1) { + list::const_iterator icur = indices.end(); + do { + -- icur; + -- pcur; + + long tmp_off; + if (pcur->msb >= pcur->lsb) + tmp_off = *icur - pcur->lsb; + else + tmp_off = pcur->lsb - *icur; + + acc_off += tmp_off * acc_wid; + acc_wid *= pcur->width(); + + } while (icur != indices.begin()); + } + + return acc_off; } -long NetNet::sb_to_idx(long sb) const +bool NetNet::sb_to_slice(const list&indices, long sb, long&loff, unsigned long&lwid) const { - if (msb_ >= lsb_) - return sb - lsb_; + ivl_assert(*this, indices.size() < packed_dims_.size()); + + size_t acc_wid = 1; + list::const_iterator pcur = packed_dims_.end(); + for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) { + -- pcur; + acc_wid *= pcur->width(); + } + + lwid = acc_wid; + + -- pcur; + if (sb < pcur->msb && sb < pcur->lsb) + return false; + if (sb > pcur->msb && sb > pcur->lsb) + return false; + + long acc_off = 0; + if (pcur->msb >= pcur->lsb) + acc_off += (sb - pcur->lsb) * acc_wid; else - return lsb_ - sb; + acc_off += (sb - pcur->msb) * acc_wid; + + if (indices.size() == 0) { + loff = acc_off; + return true; + } + + lwid *= pcur->width(); + + list::const_iterator icur = indices.end(); + do { + -- pcur; + -- icur; + acc_wid *= pcur->width(); + if (pcur->msb >= pcur->lsb) + acc_off += (*icur - pcur->lsb) * acc_wid; + else + acc_off += (*icur - pcur->msb) * acc_wid; + + } while (icur != indices.begin()); + + loff = acc_off; + + return true; } + unsigned NetNet::array_dimensions() const { return dimensions_; @@ -802,6 +940,26 @@ unsigned NetNet::peek_eref() const return eref_count_; } +/* + * Test each of the bits in the range, and set them. If any bits are + * already set then return true. + */ +bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb) +{ + if (lref_mask_.size() == 0) + lref_mask_.resize(vector_width()); + + bool rc = false; + for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { + if (lref_mask_[idx]) + rc = true; + else + lref_mask_[idx] = true; + } + + return rc; +} + void NetNet::incr_lref() { lref_count_ += 1; @@ -2296,14 +2454,23 @@ NetNet* NetESignal::sig() return net_; } +/* + * The lsi() and msi() methods should be removed from the NetESignal + * class, to be replaced with packed dimensions aware methods of + * getting at dimensions. + */ long NetESignal::lsi() const { - return net_->lsb(); + const list&packed = net_->packed_dims(); + ivl_assert(*this, packed.size() == 1); + return packed.back().lsb; } long NetESignal::msi() const { - return net_->msb(); + const list&packed = net_->packed_dims(); + ivl_assert(*this, packed.size() == 1); + return packed.back().msb; } ivl_variable_type_t NetESignal::expr_type() const @@ -2429,7 +2596,7 @@ NetECast::~NetECast() ivl_variable_type_t NetECast::expr_type() const { - ivl_variable_type_t ret; + ivl_variable_type_t ret = IVL_VT_NO_TYPE; switch (op_) { case 'v': ret = IVL_VT_LOGIC; diff --git a/netlist.h b/netlist.h index 8304bb777..a99a41730 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef __netlist_H #define __netlist_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -75,6 +75,7 @@ class NetEvWait; class PExpr; class PFunction; class netenum_t; +class netstruct_t; struct target; struct functor_t; @@ -549,7 +550,7 @@ class NetDelaySrc : public NetObj { * * NetNet objects are located by searching NetScope objects. * - * The pin of a NetNet object are PASSIVE: they do not drive + * The pins of a NetNet object are PASSIVE: they do not drive * anything and they are not a data sink, per se. The pins follow the * values on the nexus. */ @@ -560,8 +561,24 @@ class NetNet : public NetObj { SUPPLY0, SUPPLY1, WAND, TRIAND, TRI0, WOR, TRIOR, REG, UNRESOLVED_WIRE }; - enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; + enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF }; + struct range_t { + inline range_t() : msb(0), lsb(0) { } + inline range_t(long m, long l) : msb(m), lsb(l) { } + inline range_t(const range_t&that) + : msb(that.msb), lsb(that.lsb) { } + inline range_t& operator = (const range_t&that) + { msb = that.msb; lsb = that.lsb; return *this; } + + long msb; + long lsb; + + inline unsigned long width()const + { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; } + }; + + public: // The width in this case is a shorthand for ms=width-1 and // ls=0. Only one pin is created, the width is of the vector // that passed through. @@ -572,9 +589,12 @@ class NetNet : public NetObj { // dimensions. If s0==e0, then this is not an array after // all. explicit NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls); + const std::list&packed); explicit NetNet(NetScope*s, perm_string n, Type t, - long ms, long ls, long s0, long e0); + const std::list&packed, long s0, long e0); + + // This form builds a NetNet from its record definition. + explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); virtual ~NetNet(); @@ -603,27 +623,49 @@ class NetNet : public NetObj { void set_enumeration(netenum_t*enum_set); netenum_t*enumeration(void) const; + netstruct_t*struct_type(void) const; + /* Attach a discipline to the net. */ ivl_discipline_t get_discipline() const; void set_discipline(ivl_discipline_t dis); - /* These methods return the msb and lsb indices for the most - significant and least significant bits. These are signed - longs, and may be different from pin numbers. For example, - reg [1:8] has 8 bits, msb==1 and lsb==8. */ - long msb() const; - long lsb() const; - unsigned long vector_width() const; + /* This method returns a reference to the packed dimensions + for the vector. These are arranged as a list where the + first range in the list (front) is the left-most range in + the verilog declaration. */ + const std::list& packed_dims() const { return packed_dims_; } + + /* The vector_width returns the bit width of the packed array, + vector or scaler that is this NetNet object. The static + method is also a convenient way to convert a range list to + a vector width. */ + static unsigned long vector_width(const std::list&); + unsigned long vector_width() const { return vector_width(packed_dims_); } + + /* Given a prefix of indices, figure out how wide the + resulting slice would be. This is a generalization of the + vector_width(), where the depth would be 0. */ + unsigned long slice_width(size_t depth) const; /* This method converts a signed index (the type that might be - found in the Verilog source) to a pin number. It accounts - for variation in the definition of the reg/wire/whatever. */ - long sb_to_idx(long sb) const; + found in the Verilog source) to canonical. It accounts + for variation in the definition of the + reg/wire/whatever. Note that a canonical index of a + multi-dimensioned packed array is a single dimension. For + example, "reg [4:1][3:0]..." has the canonical dimension + [15:0] and the sb_to_idx() method will convert [2][2] to + the canonical index [6]. */ + long sb_to_idx(const std::list&prefix, long sb) const; + + /* This method converts a partial packed indices list and a + tail index, and generates a canonical slice offset and + width. */ + bool sb_to_slice(const std::list&prefix, long sb, long&off, unsigned long&wid) const; /* This method checks that the signed index is valid for this signal. If it is, the above sb_to_idx can be used to get the pin# from the index. */ - bool sb_is_valid(long sb) const; + bool sb_is_valid(const std::list&prefix, long sb) const; /* This method returns 0 for scalars and vectors, and greater for arrays. The value is the number of array @@ -654,6 +696,7 @@ class NetNet : public NetObj { void incr_lref(); void decr_lref(); unsigned peek_lref() const { return lref_count_; } + bool test_part_lref(unsigned msb, unsigned lsb); unsigned get_refs() const; @@ -676,18 +719,25 @@ class NetNet : public NetObj { bool is_scalar_ : 1; bool local_flag_: 1; netenum_t*enumeration_; + netstruct_t*struct_type_; ivl_discipline_t discipline_; - long msb_, lsb_; + std::list packed_dims_; const unsigned dimensions_; long s0_, e0_; unsigned eref_count_; unsigned lref_count_; + // When the signal is an unresolved wire, we need more detail + // which bits are assigned. This mask is true for each bit + // that is known to be driven. + std::vector lref_mask_; vector delay_paths_; }; +extern std::ostream&operator << (std::ostream&out, const std::list&rlist); + /* * This object type is used to contain a logical scope within a * design. The scope doesn't represent any executable hardware, but is @@ -1613,7 +1663,8 @@ class NetTran : public NetNode, public IslandBranch { public: // Tran devices other than TRAN_VP - NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type); + NetTran(NetScope*scope, perm_string n, ivl_switch_type_t type, + unsigned wid); // Create a TRAN_VP NetTran(NetScope*scope, perm_string n, unsigned wid, unsigned part, unsigned off); @@ -2315,6 +2366,8 @@ class NetAssign_ { ivl_select_type_t select_type() const; void set_word(NetExpr*); + // Set a part select expression for the l-value vector. Note + // that the expression calculates a CANONICAL bit address. void set_part(NetExpr* loff, unsigned wid, ivl_select_type_t = IVL_SEL_OTHER); diff --git a/netmisc.cc b/netmisc.cc index b9abaad93..504b58dcb 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -27,55 +27,6 @@ # include "compiler.h" # include "ivl_assert.h" -// This routines is not currently used! -#if 0 -NetNet* add_to_net(Design*des, NetNet*sig, long val) -{ - if (val == 0) - return sig; - cerr << sig->get_fileline() << ": XXXX: Forgot how to implement add_to_net" << endl; - return 0; - NetScope*scope = sig->scope(); - unsigned long abs_val = (val >= 0)? val : (-val); - unsigned width = sig->pin_count(); - - verinum val_v (abs_val, width); - - NetConst*val_c = new NetConst(scope, scope->local_symbol(), val_v); - - NetNet*val_s = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - val_s->local_flag(true); - - NetNet*res = new NetNet(scope, scope->local_symbol(), - NetNet::IMPLICIT, width); - res->local_flag(true); - - NetAddSub*add = new NetAddSub(scope, scope->local_symbol(), width); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(sig->pin(idx), add->pin_DataA(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(val_c->pin(idx), add->pin_DataB(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(val_s->pin(idx), add->pin_DataB(idx)); - - for (unsigned idx = 0 ; idx < width ; idx += 1) - connect(res->pin(idx), add->pin_Result(idx)); - - if (val < 0) - add->attribute(perm_string::literal("LPM_Direction"), verinum("SUB")); - else - add->attribute(perm_string::literal("LPM_Direction"), verinum("ADD")); - - des->add_node(add); - des->add_node(val_c); - - return res; -} -#endif NetNet* sub_net_from(Design*des, NetScope*scope, long val, NetNet*sig) { @@ -247,6 +198,21 @@ static NetExpr* make_sub_expr(long val, NetExpr*expr) return res; } +static NetExpr* make_mult_expr(NetExpr*expr, unsigned long val) +{ + verinum val_v (val, expr->expr_width()); + val_v.has_sign(true); + + NetEConst*val_c = new NetEConst(val_v); + val_c->set_line(*expr); + + NetEBMult*res = new NetEBMult('*', expr, val_c, expr->expr_width(), + expr->has_sign()); + res->set_line(*expr); + + return res; +} + /* * This routine is used to calculate the number of bits needed to * contain the given number. @@ -273,10 +239,13 @@ static unsigned num_bits(long arg) /* * This routine generates the normalization expression needed for a variable - * bit select or a variable base expression for an indexed part select. + * bit select or a variable base expression for an indexed part + * select. This function doesn't actually look at the variable + * dimensions, it just does the final calculation using msb/lsb of the + * last slice, and the off of the slice in the variable. */ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, - unsigned long wid, bool is_up) + unsigned long wid, bool is_up, long soff) { long offset = lsb; @@ -309,13 +278,13 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, base = tmp; } /* Normalize the expression. */ - base = make_sub_expr(offset, base); + base = make_sub_expr(offset+soff, base); } else { /* Correct the offset if needed. */ if (!is_up) offset += wid - 1; /* If the offset is zero then just return the base (index) * expression. */ - if (offset == 0) return base; + if ((soff-offset) == 0) return base; /* Calculate the space needed for the offset. */ unsigned min_wid = num_bits(-offset); /* We need enough space for the larger of the offset or the @@ -338,12 +307,83 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, base = tmp; } /* Normalize the expression. */ - base = make_add_expr(base, -offset); + base = make_add_expr(base, soff-offset); } return base; } +/* + * This method is how indices should work except that the base should + * be a vector of expressions that matches the size of the dims list, + * so that we can generate an expression based on the entire packed + * vector. For now, we assert that there is only one set of dimensions. + */ +NetExpr *normalize_variable_base(NetExpr *base, + const list&dims, + unsigned long wid, bool is_up) +{ + ivl_assert(*base, dims.size() == 1); + const NetNet::range_t&rng = dims.back(); + return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); +} + +NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, + const NetNet*reg) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size()+1 == packed_dims.size()); + + // Get the canonical offset of the slice within which we are + // addressing. We need that address as a slice offset to + // calculate the proper complete address + const NetNet::range_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.lsb); + + return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); +} + +NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, + const NetNet*reg, + unsigned long wid, bool is_up) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size()+1 == packed_dims.size()); + + // Get the canonical offset of the slice within which we are + // addressing. We need that address as a slice offset to + // calculate the proper complete address + const NetNet::range_t&rng = packed_dims.back(); + long slice_off = reg->sb_to_idx(indices, rng.lsb); + + return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off); +} + +NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, + const NetNet*reg, unsigned long&lwid) +{ + const list&packed_dims = reg->packed_dims(); + ivl_assert(*base, indices.size() < packed_dims.size()); + + list::const_iterator pcur = packed_dims.end(); + for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) { + -- pcur; + } + + long sb; + if (pcur->msb >= pcur->lsb) + sb = pcur->lsb; + else + sb = pcur->msb; + + long loff; + reg->sb_to_slice(indices, sb, loff, lwid); + + base = make_mult_expr(base, lwid); + base = make_add_expr(base, loff); + return base; +} + /* * This routine generates the normalization expression needed for a variable * array word select. @@ -892,3 +932,39 @@ void collapse_partselect_pv_to_concat(Design*des, NetNet*sig) delete ps_obj; } } + +/* + * Evaluate the prefix indices. All but the final index in a + * chain of indices must be a single value and must evaluate + * to constants at compile time. For example: + * [x] - OK + * [1][2][x] - OK + * [1][x:y] - OK + * [2:0][x] - BAD + * [y][x] - BAD + * Leave the last index for special handling. + */ +bool evaluate_index_prefix(Design*des, NetScope*scope, + list&prefix_indices, + const list&indices) +{ + list::const_iterator icur = indices.begin(); + for (size_t idx = 0 ; (idx+1) < indices.size() ; idx += 1, ++icur) { + assert(icur != indices.end()); + assert(icur->sel == index_component_t::SEL_BIT); + NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, true); + + long tmp; + if (texpr == 0 || !eval_as_long(tmp, texpr)) { + cerr << icur->msb->get_fileline() << ": error: " + "Array index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + prefix_indices .push_back(tmp); + delete texpr; + } + + return true; +} diff --git a/netmisc.h b/netmisc.h index 20d72461f..7f34131fa 100644 --- a/netmisc.h +++ b/netmisc.h @@ -99,7 +99,49 @@ extern NetNet*crop_to_width(Design*des, NetNet*n, unsigned w); * the provided vector/array information. */ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, - unsigned long wid, bool is_up); + unsigned long wid, bool is_up, + long slice_off =0); +extern NetExpr*normalize_variable_base(NetExpr *base, + const list&dims, + unsigned long wid, bool is_up); + +/* + * Calculate a canonicalizing expression for a bit select, when the + * base expression is the last index of an otherwise complete bit + * select. For example: + * reg [3:0][7:0] foo; + * ... foo[1][x] ... + * base is (x) and the generated expression will be (x+8). + */ +extern NetExpr*normalize_variable_bit_base(const list&indices, NetExpr *base, + const NetNet*reg); + +/* + * This is similar to normalize_variable_bit_base, but the tail index + * it a base and width, instead of a bit. This is used for handling + * indexed part selects: + * reg [3:0][7:0] foo; + * ... foo[1][x +: 2] + * base is (x), wid input is (2), and is_up is (true). The output + * expression is (x+8). + */ +extern NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, + const NetNet*reg, + unsigned long wid, bool is_up); +/* + * Calculate a canonicalizing expression for a slice select. The + * indices array is less than needed to fully address a bit, so the + * result is a slice of the packed array. The return value is an + * expression that gets to the base of the slice, and (lwid) becomes + * the width of the slice, in bits. For example: + * reg [4:1][7:0] foo + * ...foo[x]... + * base is (x) and the generated expression will be (x*8 - 8), with + * lwid set to (8). + */ +extern NetExpr*normalize_variable_slice_base(const list&indices, NetExpr *base, + const NetNet*reg, unsigned long&lwid); + extern NetExpr*normalize_variable_array_base(NetExpr *base, long offset, unsigned count); @@ -235,4 +277,7 @@ extern uint64_t get_scaled_time_from_real(Design*des, extern void collapse_partselect_pv_to_concat(Design*des, NetNet*sig); +extern bool evaluate_index_prefix(Design*des, NetScope*scope, + list&prefix_indices, + const list&indices); #endif diff --git a/netstruct.cc b/netstruct.cc new file mode 100644 index 000000000..63b673bae --- /dev/null +++ b/netstruct.cc @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011 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 "netstruct.h" +# include + +using namespace std; + +netstruct_t::netstruct_t() +: packed_(false) +{ +} + +netstruct_t::~netstruct_t() +{ +} + +void netstruct_t::packed(bool flag) +{ + packed_ = flag; +} + +void netstruct_t::append_member(const netstruct_t::member_t&val) +{ + members_.push_back(val); +} + +const netstruct_t::member_t* netstruct_t::packed_member(perm_string name, unsigned long&off) const +{ + unsigned long count_off = 0; + for (size_t idx = members_.size() ; idx > 0 ; idx -= 1) { + if (members_[idx-1].name == name) { + off = count_off; + return &members_[idx-1]; + } + count_off += members_[idx-1].width(); + } + + return 0; +} + +long netstruct_t::packed_width(void) const +{ + if (! packed_) + return -1; + + long res = 0; + for (size_t idx = 0 ; idx < members_.size() ; idx += 1) + res += members_[idx].width(); + + return res; +} diff --git a/netstruct.h b/netstruct.h new file mode 100644 index 000000000..b84df6a4a --- /dev/null +++ b/netstruct.h @@ -0,0 +1,73 @@ +#ifndef __netstruct_H +#define __netstruct_H +/* + * Copyright (c) 2011-2012 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 "LineInfo.h" +# include +# include "ivl_target.h" + +class netstruct_t : public LineInfo { + + public: + struct member_t { + perm_string name; + ivl_variable_type_t type; + long msb; + long lsb; + long width() const; + ivl_variable_type_t data_type() const { return type; }; + // We need to keep the individual element sign information. + bool get_signed() const { return false; }; + }; + + public: + netstruct_t(); + ~netstruct_t(); + + void packed(bool flag); + bool packed(void) const; + + void append_member(const member_t&); + + // Given the name of a member, return a pointer to the member + // description, and set the off value to be the offset into + // the packed value where the member begins. + const struct member_t* packed_member(perm_string name, unsigned long&off) const; + + // Return the width (in bits) of the packed record, or -1 if + // the record is not packed. + long packed_width() const; + + private: + bool packed_; + std::vectormembers_; +}; + +inline bool netstruct_t::packed(void) const { return packed_; } + +inline long netstruct_t::member_t::width() const +{ + if (msb >= lsb) + return msb - lsb + 1; + else + return lsb - msb + 1; +} + +#endif diff --git a/parse.y b/parse.y index 3f4c78dbf..cce1cffca 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -38,7 +38,7 @@ extern void lex_end_table(); bool have_timeunit_decl = false; bool have_timeprec_decl = false; -static list* param_active_range = 0; +static list* param_active_range = 0; static bool param_active_signed = false; static ivl_variable_type_t param_active_type = IVL_VT_LOGIC; @@ -48,9 +48,10 @@ static struct { NetNet::PortType port_type; ivl_variable_type_t var_type; bool sign_flag; - list* range; + data_type_t* data_type; + list* range; } port_declaration_context = {NetNet::NONE, NetNet::NOT_A_PORT, - IVL_VT_NO_TYPE, false, 0}; + IVL_VT_NO_TYPE, false, 0, 0}; /* The task and function rules need to briefly hold the pointer to the task/function that is currently in progress. */ @@ -97,8 +98,7 @@ static list >* make_port_list(char*id, PExpr*expr) delete[]id; return tmp; } -static list >* make_port_list(list >*tmp, +static list >* make_port_list(list >*tmp, char*id, PExpr*expr) { tmp->push_back(make_pair(lex_strings.make(id), expr)); @@ -106,39 +106,28 @@ static list >* make_port_list(list* make_range_from_width(uint64_t wid) +list* make_range_from_width(uint64_t wid) { - list*range = new list; + pform_range_t range; + range.first = new PENumber(new verinum(wid-1, integer_width)); + range.second = new PENumber(new verinum((uint64_t)0, integer_width)); - range->push_back(new PENumber(new verinum(wid-1, integer_width))); - range->push_back(new PENumber(new verinum((uint64_t)0, integer_width))); - - return range; + list*rlist = new list; + rlist->push_back(range); + return rlist; } -/* - * Make a range vector from an existing pair of expressions. - */ -static vector* make_range_vector(list*that) +static list* make_range_from_pair(list*rpair) { - assert(that->size() == 2); - vector*tmp = new vector (2); - tmp->at(0) = that->front(); - tmp->at(1) = that->back(); - delete that; - return tmp; -} + pform_range_t range; + assert(rpair && rpair->size() == 2); + range.first = rpair->front(); + range.second = rpair->back(); + delete rpair; -/* - * Make a range vector from a width. Generate the msb and lsb - * expressions to get the canonical range for the given width. - */ -static vector* make_range_vector(uint64_t wid) -{ - vector*tmp = new vector (2); - tmp->at(0) = new PENumber(new verinum(wid-1, integer_width)); - tmp->at(1) = new PENumber(new verinum((uint64_t)0, integer_width)); - return tmp; + list*rlist = new list; + rlist->push_back(range); + return rlist; } static list* list_from_identifier(char*id) @@ -156,12 +145,12 @@ static list* list_from_identifier(list*tmp, char*id) return tmp; } -static list* copy_range(list* orig) +list* copy_range(list* orig) { - list*copy = 0; + list*copy = 0; if (orig) - copy = new list (*orig); + copy = new list (*orig); return copy; } @@ -253,19 +242,76 @@ static long check_enum_seq_value(const YYLTYPE&loc, verinum *arg, bool zero_ok) return value; } -static void current_task_set_statement(vector*s) +static void current_task_set_statement(const YYLTYPE&loc, vector*s) { + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty tasks requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_task->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ if (s->size() == 1) { current_task->set_statement((*s)[0]); return; } + if (!gn_system_verilog()) { + yyerror(loc, "error: Task body with multiple statements requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); tmp->set_statement(*s); current_task->set_statement(tmp); } +static void current_function_set_statement(const YYLTYPE&loc, vector*s) +{ + if (s == 0) { + /* if the statement list is null, then the parser + detected the case that there are no statements in the + task. If this is System Verilog, handle it as an + an empty block. */ + if (!gn_system_verilog()) { + yyerror(loc, "error: Support for empty functions requires SystemVerilog."); + } + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + current_function->set_statement(tmp); + return; + } + + /* The parser assures that there is a non-empty vector. */ + assert(s && !s->empty()); + + /* A vector of 1 is handled as a simple statement. */ + if (s->size() == 1) { + current_function->set_statement((*s)[0]); + return; + } + + if (!gn_system_verilog()) { + yyerror(loc, "error: Function body with multiple statements requires SystemVerilog."); + } + + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + FILE_NAME(tmp, loc); + tmp->set_statement(*s); + current_function->set_statement(tmp); +} + %} %union { @@ -307,6 +353,7 @@ static void current_task_set_statement(vector*s) named_pexpr_t*named_pexpr; list*named_pexprs; struct parmvalue_t*parmvalue; + list*ranges; PExpr*expr; list*exprs; @@ -316,7 +363,7 @@ static void current_task_set_statement(vector*s) NetNet::Type nettype; PGBuiltin::Type gatetype; NetNet::PortType porttype; - ivl_variable_type_t datatype; + ivl_variable_type_t vartype; PWire*wire; svector*wires; @@ -330,6 +377,16 @@ static void current_task_set_statement(vector*s) net_decl_assign_t*net_decl_assign; enum_type_t*enum_type; + decl_assignment_t*decl_assignment; + list*decl_assignments; + + struct_member_t*struct_member; + list*struct_members; + struct_type_t*struct_type; + + data_type_t*data_type; + class_type_t*class_type; + verinum* number; verireal* realtime; @@ -339,12 +396,13 @@ static void current_task_set_statement(vector*s) }; %token IDENTIFIER SYSTEM_IDENTIFIER STRING TIME_LITERAL +%token TYPE_IDENTIFIER %token DISCIPLINE_IDENTIFIER %token PATHPULSE_IDENTIFIER -%token BASED_NUMBER DEC_NUMBER +%token BASED_NUMBER DEC_NUMBER UNBASED_NUMBER %token REALTIME %token K_PLUS_EQ K_MINUS_EQ K_INCR K_DECR -%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LS K_RS K_RSS K_SG +%token K_LE K_GE K_EG K_EQ K_NE K_CEQ K_CNE K_LP K_LS K_RS K_RSS K_SG /* K_CONTRIBUTE is <+, the contribution assign. */ %token K_CONTRIBUTE %token K_PO_POS K_PO_NEG K_POW @@ -436,8 +494,9 @@ static void current_task_set_statement(vector*s) %type from_exclude %type number pos_neg_number -%type unsigned_signed_opt signed_unsigned_opt reg_opt -%type udp_reg_opt edge_operator automatic_opt +%type signing unsigned_signed_opt signed_unsigned_opt +%type K_automatic_opt K_packed_opt K_reg_opt K_static_opt K_virtual_opt +%type udp_reg_opt edge_operator %type drive_strength drive_strength_opt dr_strength0 dr_strength1 %type udp_input_sym udp_output_sym %type udp_input_list udp_sequ_entry udp_comb_entry @@ -449,9 +508,9 @@ static void current_task_set_statement(vector*s) %type udp_initial udp_init_opt %type udp_initial_expr_opt -%type register_variable net_variable real_variable +%type register_variable net_variable endname_opt class_declaration_endname_opt %type register_variable_list net_variable_list -%type real_variable_list list_of_identifiers +%type list_of_identifiers loop_variables %type list_of_port_identifiers %type net_decl_assign net_decl_assigns @@ -461,14 +520,14 @@ static void current_task_set_statement(vector*s) %type list_of_ports module_port_list_opt list_of_port_declarations module_attribute_foreign %type parameter_value_range parameter_value_ranges %type parameter_value_ranges_opt -%type value_range_expression +%type tf_port_item_expr_opt value_range_expression %type enum_name_list enum_name %type enum_data_type %type task_item task_item_list task_item_list_opt -%type task_port_item task_port_decl task_port_decl_list task_port_decl_list_opt -%type function_item function_item_list +%type tf_port_declaration tf_port_item tf_port_list tf_port_list_opt +%type function_item function_item_list function_item_list_opt %type port_name parameter_value_byname %type port_name_list parameter_value_byname_list @@ -483,20 +542,32 @@ static void current_task_set_statement(vector*s) %type gate_instance_list %type hierarchy_identifier -%type expression expr_primary expr_mintypmax -%type lpvalue -%type branch_probe_expression +%type assignment_pattern expression expr_primary expr_mintypmax +%type class_new dynamic_array_new inc_or_dec_expression inside_expression lpvalue +%type branch_probe_expression streaming_concatenation %type delay_value delay_value_simple %type delay1 delay3 delay3_opt delay_value_list %type expression_list_with_nuls expression_list_proper %type cont_assign cont_assign_list -%type range range_opt -%type dimensions_opt dimensions +%type variable_decl_assignment +%type list_of_variable_decl_assignments + +%type data_type data_type_or_implicit +%type class_declaration_extends_opt +%type class_identifier +%type struct_union_member +%type struct_union_member_list +%type struct_data_type + +%type range range_opt variable_dimension +%type dimensions_opt dimensions + %type net_type var_type net_type_opt %type gatetype switchtype -%type port_type -%type primitive_type primitive_type_opt bit_logic +%type port_direction port_direction_opt +%type primitive_type primitive_type_opt bit_logic +%type integer_vector_type %type parameter_value_opt %type function_range_or_type_opt @@ -504,8 +575,8 @@ static void current_task_set_statement(vector*s) %type event_expression %type event_control %type statement statement_or_null compressed_statement -%type statement_list statement_or_null_list -%type statement_list_or_null +%type loop_statement for_step jump_statement +%type statement_or_null_list statement_or_null_list_opt %type analog_statement @@ -515,12 +586,13 @@ static void current_task_set_statement(vector*s) %type specify_simple_path specify_simple_path_decl %type specify_edge_path specify_edge_path_decl -%type atom2_type +%type atom2_type non_integer_type +%type module_start module_end %token K_TAND %right K_PLUS_EQ K_MINUS_EQ K_MUL_EQ K_DIV_EQ K_MOD_EQ K_AND_EQ K_OR_EQ %right K_XOR_EQ K_LS_EQ K_RS_EQ K_RSS_EQ -%right '?' ':' +%right '?' ':' K_inside %left K_LOR %left K_LAND %left '|' @@ -553,6 +625,619 @@ source_file | source_file description ; +assignment_pattern /* IEEE1800-2005: A.6.7.1 */ + : K_LP expression_list_proper '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + | K_LP '}' + { PEVoid*tmp = new PEVoid; + FILE_NAME(tmp, @1); + yyerror(@1, "sorry: Assignment patterns (array literals) not supported."); + $$ = tmp; + } + ; + +class_declaration /* IEEE1800-2005: A.1.2 */ + : K_virtual_opt K_class class_identifier class_declaration_extends_opt ';' + { pform_start_class_declaration(@2, $3); + if ($4) { + yyerror(@4, "sorry: Class extends not supported yet."); + } + } + class_items_opt K_endclass + { // Process a class. + pform_end_class_declaration(); + yyerror(@2, "sorry: Class declarations not supported yet."); + } + class_declaration_endname_opt + { // Wrap up the class. + if ($10 && $3 && $3->name != $10) { + yyerror(@10, "error: Class end name doesn't match class name."); + delete[]$10; + } + } + ; + +class_constraint /* IEEE1800-2005: A.1.8 */ + : constraint_prototype + | constraint_declaration + ; + +class_identifier + : IDENTIFIER + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($1); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$1; + $$ = tmp; + } + | TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast($1); + if (tmp == 0) { + yyerror(@1, "Type name is not a predeclared class name."); + } + $$ = tmp; + } + ; + + /* The endname after a class declaration is a little tricky because + the class name is detected by the lexor as a TYPE_IDENTIFIER if it + does indeed match a name. */ +class_declaration_endname_opt + : ':' TYPE_IDENTIFIER + { class_type_t*tmp = dynamic_cast ($2); + if (tmp == 0) { + yyerror(@2, "error: class declaration endname is not a class name\n"); + $$ = 0; + } else { + $$ = strdupnew(tmp->name.str()); + } + } + | ':' IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + + /* This rule implements [ extends class_type ] in the + class_declaration. It is not a rule of its own in the LRM. + + Note that for this to be correct, the identifier after the + extends keyword must be a class name. Therefore, match + TYPE_IDENTIFIER instead of IDENTIFIER, and this rule will return + a data_type. */ + +class_declaration_extends_opt /* IEEE1800-2005: A.1.2 */ + : K_extends TYPE_IDENTIFIER + { $$ = $2; } + | + { $$ = 0; } + ; + + /* The class_items_opt and class_items rules together implement the + rule snippet { class_item } (zero or more class_item) of the + class_declaration. */ +class_items_opt /* IEEE1800-2005: A.1.2 */ + : class_items + | + ; + +class_items /* IEEE1800-2005: A.1.2 */ + : class_items class_item + | class_item + ; + +class_item /* IEEE1800-2005: A.1.8 */ + + /* IEEE1800 A.1.8: class_constructor_declaration */ + : method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt + statement_or_null_list_opt + K_endfunction endnew_opt + { yyerror(@3, "sorry: Class constructors not supported yet."); + yyerrok; + } + + /* IEEE1800 A.1.8: class_constructor_declaration with a call to + parent constructor. Note that the implicit_class_handle must + be K_super ("this.new" makes little sense) but that would + cause a conflict. */ + | method_qualifier_opt K_function K_new '(' tf_port_list_opt ')' ';' + function_item_list_opt + implicit_class_handle '.' K_new '(' expression_list_with_nuls ')' + statement_or_null_list_opt + K_endfunction endnew_opt + { yyerror(@3, "sorry: Class constructors not supported yet."); + yyerrok; + } + + /* Class properties... */ + + | property_qualifier_opt data_type list_of_variable_decl_assignments ';' + + + /* Class methods... */ + + | method_qualifier_opt task_declaration + + | method_qualifier_opt function_declaration + + + /* Class constraints... */ + + | class_constraint + + /* Here are some error matching rules to help recover from various + syntax errors within a class declaration. */ + + | property_qualifier_opt data_type error ';' + { yyerror(@3, "error: Errors in variable names after data type."); + yyerrok; + } + + | property_qualifier_opt IDENTIFIER error ';' + { yyerror(@3, "error: %s doesn't name a type.", $2); + yyerrok; + } + + | method_qualifier_opt K_function K_new error K_endfunction endnew_opt + { yyerror(@1, "error: I give up on this class constructor declaration."); + yyerrok; + } + + | error ';' + { yyerror(@2, "error: invalid class item."); + yyerrok; + } + + ; + +class_item_qualifier /* IEEE1800-2005 A.1.8 */ + : K_static + | K_protected + | K_local + ; + +class_new /* IEEE1800-2005 A.2.4 */ + : K_new '(' ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + | K_new '(' expression_list_proper ')' + { yyerror(@1, "sorry: class_new not implemented yet."); + $$ = 0; + } + ; + +constraint_block_item /* IEEE1800-2005 A.1.9 */ + : constraint_expression + ; + +constraint_block_item_list + : constraint_block_item_list constraint_block_item + | constraint_block_item + ; + +constraint_block_item_list_opt + : + | constraint_block_item_list + ; + +constraint_declaration /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER '{' constraint_block_item_list_opt '}' + { yyerror(@2, "sorry: Constraint declarations not supported.") } + + /* Error handling rules... */ + + | K_static_opt K_constraint IDENTIFIER '{' error '}' + { yyerror(@4, "error: Errors in the constraint block item list."); } + ; + +constraint_expression /* IEEE1800-2005 A.1.9 */ + : expression ';' + | expression K_dist '{' '}' ';' + | expression K_TRIGGER constraint_set + | K_if '(' expression ')' constraint_set %prec less_than_K_else + | K_if '(' expression ')' constraint_set K_else constraint_set + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' constraint_set + ; + +constraint_expression_list /* */ + : constraint_expression_list constraint_expression + | constraint_expression + ; + +constraint_prototype /* IEEE1800-2005: A.1.9 */ + : K_static_opt K_constraint IDENTIFIER ';' + { yyerror(@2, "sorry: Constraint prototypes not supported.") } + ; + +constraint_set /* IEEE1800-2005 A.1.9 */ + : constraint_expression + | '{' constraint_expression_list '}' + ; + +data_type /* IEEE1800-2005: A.2.2.1 */ + : integer_vector_type unsigned_signed_opt range_opt + { vector_type_t*tmp = new vector_type_t($1, $2, $3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | non_integer_type + { real_type_t*tmp = new real_type_t($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | struct_data_type + { $$ = $1; } + | enum_data_type + { $$ = $1; } + | atom2_type signed_unsigned_opt + { atom2_type_t*tmp = new atom2_type_t($1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | TYPE_IDENTIFIER + { $$ = $1; } + | K_string + { yyerror(@1, "sorry: String data type not supported."); + $$ = 0; + } + ; + + /* The data_type_or_implicit rule is a little more complex then the + rule documented in the IEEE format syntax in order to allow for + signaling the special case that the data_type is completely + absent. The context may need that information to decide to resort + to left context. */ + +data_type_or_implicit /* IEEE1800-2005: A.2.2.1 */ + : data_type + { $$ = $1; } + | signing range_opt + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, $1, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | range + { vector_type_t*tmp = new vector_type_t(IVL_VT_LOGIC, false, $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | + { $$ = 0; } + ; + + /* This implements the [ : INDENTIFIER ] part of the constructure + rule documented in IEEE1800-2005: A.1.8 */ +endnew_opt : ':' K_new | ; + + /* The dynamic_array_new rule is kinda like an expression, but it is + treated differently by rules that use this "expression". Watch out! */ + +dynamic_array_new /* IEEE1800-2005: A.2.4 */ + : K_new '[' expression ']' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + | K_new '[' expression ']' '(' expression ')' + { yyerror(@1, "sorry: Dynamic array new expression not supported."); + $$ = 0; + } + ; + +for_step /* IEEE1800-2005: A.6.8 */ + : lpvalue '=' expression + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | inc_or_dec_expression + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + | compressed_statement + { $$ = $1; } + ; + + + /* The function declaration rule matches the function declaration + header, then pushes the function scope. This causes the + definitions in the func_body to take on the scope of the function + instead of the module. */ +function_declaration /* IEEE1800-2005: A.2.6 */ + : K_function K_automatic_opt function_range_or_type_opt IDENTIFIER ';' + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + function_item_list statement_or_null_list_opt + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + current_function_set_statement($8? @8 : @4, $8); + pform_pop_scope(); + current_function = 0; + } + endname_opt + { // Last step: check any closing name. + if ($11 && (strcmp($4,$11) != 0)) { + yyerror(@11, "error: End name doesn't match function name"); + } + if ($11 && !gn_system_verilog()) { + yyerror(@11, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($11) delete[]$11; + } + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER + { assert(current_function == 0); + current_function = pform_push_function_scope(@1, $4, $2); + } + '(' tf_port_list_opt ')' ';' + block_item_decls_opt + statement_or_null_list_opt + K_endfunction + { current_function->set_ports($7); + current_function->set_return($3); + current_function_set_statement($11? @11 : @4, $11); + pform_pop_scope(); + current_function = 0; + if ($7==0 && !gn_system_verilog()) { + yyerror(@4, "error: Empty parenthesis syntax requires SystemVerilog."); + } + } + endname_opt + { // Last step: check any closing name. + if ($14 && (strcmp($4,$14) != 0)) { + yyerror(@14, "error: End name doesn't match function name"); + } + if ($14 && !gn_system_verilog()) { + yyerror(@14, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($14) delete[]$14; + } + + /* Detect and recover from some errors. */ + + | K_function K_automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction + { /* */ + if (current_function) { + pform_pop_scope(); + current_function = 0; + } + assert(current_function == 0); + yyerror(@1, "error: Syntax error defining function."); + yyerrok; + } + endname_opt + { // Last step: check any closing name. + if ($8 && (strcmp($4,$8) != 0)) { + yyerror(@4, "error: End name doesn't match function name"); + } + if ($8 && !gn_system_verilog()) { + yyerror(@8, "error: Function end names require System Verilog."); + } + delete[]$4; + if ($8) delete[]$8; + } + + ; + +implicit_class_handle /* IEEE1800-2005: A.8.4 */ + : K_this + | K_super + ; + + /* SystemVerilog adds support for the increment/decrement + expressions, which look like a++, --a, etc. These are primaries + but are in their own rules because they can also be + statements. Note that the operator can only take l-value + expressions. */ + +inc_or_dec_expression /* IEEE1800-2005: A.4.3 */ + : K_INCR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('I', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_INCR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('i', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_DECR lpvalue %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('D', $2); + FILE_NAME(tmp, @2); + $$ = tmp; + } + | lpvalue K_DECR %prec UNARY_PREC + { PEUnary*tmp = new PEUnary('d', $1); + FILE_NAME(tmp, @1); + $$ = tmp; + } + ; + +inside_expression /* IEEE1800-2005 A.8.3 */ + : expression K_inside '{' open_range_list '}' + { yyerror(@2, "sorry: \"inside\" expressions not supported yet."); + $$ = 0; + } + ; + +integer_vector_type /* IEEE1800-2005: A.2.2.1 */ + : K_reg { $$ = IVL_VT_LOGIC; } + | K_bit { $$ = IVL_VT_BOOL; } + | K_logic { $$ = IVL_VT_LOGIC; } + | K_bool { $$ = IVL_VT_BOOL; } /* Icarus Verilog xtypes extension */ + ; + +jump_statement /* IEEE1800-2005: A.6.5 */ + : K_break ';' + { yyerror(@1, "sorry: break statements not supported."); + $$ = 0; + } + | K_return ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + | K_return expression ';' + { yyerror(@1, "sorry: return statements not supported."); + $$ = 0; + } + ; + + /* Loop statements are kinds of statements. */ + +loop_statement /* IEEE1800-2005: A.6.8 */ + : K_for '(' lpvalue '=' expression ';' expression ';' for_step ')' + statement_or_null + { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_for '(' data_type IDENTIFIER '=' expression ';' expression ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@3, "sorry: for_variable_declaration not supported"); + } + + | K_forever statement_or_null + { PForever*tmp = new PForever($2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_repeat '(' expression ')' statement_or_null + { PRepeat*tmp = new PRepeat($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_while '(' expression ')' statement_or_null + { PWhile*tmp = new PWhile($3, $5); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + | K_foreach '(' IDENTIFIER '[' loop_variables ']' ')' statement_or_null + { yyerror(@1, "sorry: foreach loops not supported"); + delete[]$3; + delete $5; + delete $8; + $$ = 0; + } + + /* Error forms for loop statements. */ + + | K_for '(' lpvalue '=' expression ';' expression ';' error ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop step assignment."); + } + + | K_for '(' lpvalue '=' expression ';' error ';' for_step ')' + statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in for loop condition expression."); + } + + | K_for '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Incomprehensible for loop."); + } + + | K_while '(' error ')' statement_or_null + { $$ = 0; + yyerror(@1, "error: Error in while loop condition."); + } + + | K_foreach '(' IDENTIFIER '[' error ']' ')' statement_or_null + { $$ = 0; + yyerror(@4, "error: Errors in foreach loop variables list."); + } + ; + + +/* TODO: Replace register_variable_list with list_of_variable_decl_assignments. */ +list_of_variable_decl_assignments /* IEEE1800-2005 A.2.3 */ + : variable_decl_assignment + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + | list_of_variable_decl_assignments ',' variable_decl_assignment + { list*tmp = $1; + tmp->push_back($3); + $$ = tmp; + } + ; + +variable_decl_assignment /* IEEE1800-2005 A.2.3 */ + : IDENTIFIER dimensions_opt + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + if ($2) { + tmp->index = *$2; + delete $2; + } + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' expression + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + tmp->expr .reset($3); + delete[]$1; + $$ = tmp; + } + | IDENTIFIER '=' K_new '(' ')' + { decl_assignment_t*tmp = new decl_assignment_t; + tmp->name = lex_strings.make($1); + yyerror("sorry: Class initialization assignment not supported here."); + delete[]$1; + $$ = tmp; + } + ; + + +loop_variables /* IEEE1800-2005: A.6.8 */ + : loop_variables ',' IDENTIFIER + { list*tmp = $1; + tmp->push_back(lex_strings.make($3)); + delete[]$3; + $$ = tmp; + } + | IDENTIFIER + { list*tmp = new list; + tmp->push_back(lex_strings.make($1)); + delete[]$1; + $$ = tmp; + } + ; + +method_qualifier /* IEEE1800-2005: A.1.8 */ + : K_virtual + | class_item_qualifier + ; + +method_qualifier_opt + : method_qualifier + | + ; + + +non_integer_type /* IEEE1800-2005: A.2.2.1 */ + : K_real { $$ = K_real; } + | K_realtime { $$ = K_real; } + | K_shortreal { $$ = K_shortreal; } + ; + number : BASED_NUMBER { $$ = $1; based_size = 0;} | DEC_NUMBER @@ -560,8 +1245,65 @@ number : BASED_NUMBER | DEC_NUMBER BASED_NUMBER { $$ = pform_verinum_with_size($1,$2, @2.text, @2.first_line); based_size = 0; } + | UNBASED_NUMBER + { $$ = $1; based_size = 0;} + | DEC_NUMBER UNBASED_NUMBER + { yyerror(@1, "error: Unbased SystemVerilog literal cannot have " + "a size."); + $$ = $1; based_size = 0;} ; +open_range_list /* IEEE1800-2005 A.2.11 */ + : open_range_list ',' value_range + | value_range + ; + +port_direction /* IEEE1800-2005 A.1.3 */ + : K_input { $$ = NetNet::PINPUT; } + | K_output { $$ = NetNet::POUTPUT; } + | K_inout { $$ = NetNet::PINOUT; } + | K_ref + { $$ = NetNet::PREF; + if (!gn_system_verilog()) { + yyerror(@1, "error: Reference ports (ref) require SystemVerilog."); + $$ = NetNet::PINPUT; + } + } + ; + + /* port_direction_opt is used in places where the port direction is + optional. The default direction is selected by the context, + which needs to notice the PIMPLICIT direction. */ + +port_direction_opt + : port_direction { $$ = $1; } + | { $$ = NetNet::PIMPLICIT; } + ; + + /* The property_qualifier rule is as literally described in the LRM, + but the use is usually as { property_qualifier }, which is + implemented bt the property_qualifier_opt rule below. */ + +property_qualifier /* IEEE1800-2005 A.1.8 */ + : class_item_qualifier + | random_qualifier + ; + +property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ + : property_qualifier_list + | + ; + +property_qualifier_list /* IEEE1800-2005 A.1.8 */ + : property_qualifier_list property_qualifier + | property_qualifier + ; + +random_qualifier /* IEEE1800-2005 A.1.8 */ + : K_rand + | K_randc + ; + /* real and realtime are exactly the same so save some code * with a common matching rule. */ real_or_realtime @@ -569,6 +1311,423 @@ real_or_realtime | K_realtime ; +signing /* IEEE1800-2005: A.2.2.1 */ + : K_signed { $$ = true; } + | K_unsigned { $$ = false; } + ; + + /* Many places where statements are allowed can actually take a + statement or a null statement marked with a naked semi-colon. */ + +statement_or_null /* IEEE1800-2005: A.6.4 */ + : statement + { $$ = $1; } + | ';' + { $$ = 0; } + ; + +stream_expression + : expression + ; + +stream_expression_list + : stream_expression_list ',' stream_expression + | stream_expression + ; + +stream_operator + : K_LS + | K_RS + ; + +streaming_concatenation /* IEEE1800-2005: A.8.1 */ + : '{' stream_operator '{' stream_expression_list '}' '}' + { /* streaming concatenation is a SystemVerilog thing. */ + if (gn_system_verilog()) { + yyerror(@2, "sorry: Streaming concatenation not supported."); + $$ = 0; + } else { + yyerror(@2, "error: Streaming concatenation requires SystemVerilog"); + $$ = 0; + } + } + ; + + /* The task declaration rule matches the task declaration + header, then pushes the function scope. This causes the + definitions in the task_body to take on the scope of the task + instead of the module. */ + +task_declaration /* IEEE1800-2005: A.2.7 */ + + : K_task K_automatic_opt IDENTIFIER ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + task_item_list_opt + statement_or_null_list_opt + K_endtask + { current_task->set_ports($6); + current_task_set_statement(@3, $7); + pform_pop_scope(); + current_task = 0; + if ($7 && $7->size() > 1 && !gn_system_verilog()) { + yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $7; + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($10 && (strcmp($3,$10) != 0)) { + yyerror(@10, "error: End name doesn't match module/program name"); + } + if ($10 && !gn_system_verilog()) { + yyerror(@10, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($10) delete[]$10; + } + + | K_task K_automatic_opt IDENTIFIER '(' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + tf_port_list ')' ';' + block_item_decls_opt + statement_or_null_list_opt + K_endtask + { current_task->set_ports($6); + current_task_set_statement(@3, $10); + pform_pop_scope(); + current_task = 0; + if ($10) delete $10; + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($13 && (strcmp($3,$13) != 0)) { + yyerror(@13, "error: End name doesn't match module/program name"); + } + if ($13 && !gn_system_verilog()) { + yyerror(@13, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($13) delete[]$13; + } + + | K_task K_automatic_opt IDENTIFIER '(' ')' ';' + { assert(current_task == 0); + current_task = pform_push_task_scope(@1, $3, $2); + } + block_item_decls_opt + statement_or_null_list + K_endtask + { current_task->set_ports(0); + current_task_set_statement(@3, $9); + pform_pop_scope(); + current_task = 0; + cerr << @3 << ": warning: task definition for \"" << $3 + << "\" has an empty port declaration list!" << endl; + if ($9->size() > 1 && !gn_system_verilog()) { + yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); + } + delete $9; + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($12 && (strcmp($3,$12) != 0)) { + yyerror(@12, "error: End name doesn't match module/program name"); + } + if ($12 && !gn_system_verilog()) { + yyerror(@12, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($12) delete[]$12; + } + + | K_task K_automatic_opt IDENTIFIER error K_endtask + { + assert(current_task == 0); + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($7 && (strcmp($3,$7) != 0)) { + yyerror(@7, "error: End name doesn't match module/program name"); + } + if ($7 && !gn_system_verilog()) { + yyerror(@7, "error: Task end names require System Verilog."); + } + delete[]$3; + if ($7) delete[]$7; + } + + ; + + +tf_port_declaration /* IEEE1800-2005: A.2.7 */ + : port_direction K_reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, + $2 ? IVL_VT_LOGIC : + IVL_VT_NO_TYPE, + $3, $4, $5); + $$ = tmp; + } + + /* When the port is an integer, infer a signed vector of the integer + shape. Generate a range ([31:0]) to make it work. */ + + | port_direction K_integer list_of_identifiers ';' + { list*range_stub = make_range_from_width(integer_width); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, true, + range_stub, $3, true); + $$ = tmp; + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction K_time list_of_identifiers ';' + { list*range_stub = make_range_from_width(64); + svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_LOGIC, false, + range_stub, $3); + $$ = tmp; + } + + /* Ports can be real or realtime. */ + + | port_direction real_or_realtime list_of_identifiers ';' + { svector*tmp = pform_make_task_ports(@1, $1, IVL_VT_REAL, false, + 0, $3); + $$ = tmp; + } + + ; + + + /* These rules for tf_port_item are slightly expanded from the + strict rules in the LRM to help with LALR parsing. + + NOTE: Some of these rules should be folded into the "data_type" + variant which uses the data_type rule to match data type + declarations. That some rules do not use the data_type production + is a consequence of legacy. */ + +tf_port_item /* IEEE1800-2005: A.2.7 */ + + /* Ports can be integer with a width of [31:0]. */ + + : port_direction_opt K_integer IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(integer_width); + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = true; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, use_port_type, + IVL_VT_LOGIC, true, + range_stub, + list_from_identifier($3), true); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Ports can be time with a width of [63:0] (unsigned). */ + + | port_direction_opt K_time IDENTIFIER range_opt tf_port_item_expr_opt + { list*range_stub = make_range_from_width(64); + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + + port_declaration_context.port_type = use_port_type; + port_declaration_context.var_type = IVL_VT_LOGIC; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = copy_range(range_stub); + svector*tmp = pform_make_task_ports(@3, use_port_type, IVL_VT_LOGIC, + false, range_stub, + list_from_identifier($3)); + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + | port_direction_opt data_type_or_implicit IDENTIFIER range_opt tf_port_item_expr_opt + { svector*tmp; + NetNet::PortType use_port_type = $1==NetNet::PIMPLICIT? NetNet::PINPUT : $1; + list* ilist = list_from_identifier($3); + + if (($2 == 0) && ($1==NetNet::PIMPLICIT)) { + // Detect special case this is an undecorated + // identifier and we need to get the declaration from + // left context. + if (port_declaration_context.var_type == IVL_VT_NO_TYPE) { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.data_type, + ilist); + } else { + tmp = pform_make_task_ports(@3, use_port_type, + port_declaration_context.var_type, + port_declaration_context.sign_flag, + copy_range(port_declaration_context.range), + ilist); + } + + } else { + // Otherwise, the decorations for this identifier + // indicate the type. Save the type for any right + // context thta may come later. + port_declaration_context.port_type = use_port_type; + port_declaration_context.var_type = IVL_VT_NO_TYPE; + port_declaration_context.sign_flag = false; + delete port_declaration_context.range; + port_declaration_context.range = 0; + if ($2 == 0) { + $2 = new vector_type_t(IVL_VT_LOGIC, false, 0); + FILE_NAME($2, @3); + } + port_declaration_context.data_type = $2; + tmp = pform_make_task_ports(@3, use_port_type, $2, ilist); + } + $$ = tmp; + if ($4) { + yyerror(@4, "sorry: Port variable dimensions not supported yet."); + delete $4; + } + if ($5) { + yyerror(@5, "sorry: Port default expressions not supported yet."); + delete $5; + } + } + + /* Rules to match error cases... */ + + | port_direction_opt data_type_or_implicit IDENTIFIER error + { yyerror(@3, "error: Error in task/function port item after port name %s.", $3); + yyerrok; + $$ = 0; + } + ; + + /* This rule matches the [ = ] part of the tf_port_item rules. */ + +tf_port_item_expr_opt + : '=' expression { $$ = $2; } + | { $$ = 0; } + ; + +tf_port_list /* IEEE1800-2005: A.2.7 */ + + : tf_port_list ',' tf_port_item + { svector*tmp; + if ($1 && $3) { + tmp = new svector(*$1, *$3); + delete $1; + delete $3; + } else if ($1) { + tmp = $1; + } else { + tmp = $3; + } + $$ = tmp; + } + + | tf_port_item + { $$ = $1; } + + /* Rules to handle some errors in tf_port_list items. */ + + | error ',' tf_port_item + { yyerror(@2, "error: Syntax error in task/function port declaration."); + $$ = $3; + } + | tf_port_list ',' + { yyerror(@2, "error: NULL port declarations are not allowed."); + $$ = $1; + } + | tf_port_list ';' + { yyerror(@2, "error: ';' is an invalid port declaration separator."); + $$ = $1; + } + ; + + +value_range /* IEEE1800-2005: A.8.3 */ + : expression + { } + | '[' expression ':' expression ']' + { } + ; + +variable_dimension /* IEEE1800-2005: A.2.5 */ + : '[' expression ':' expression ']' + { list *tmp = new list; + pform_range_t index ($2,$4); + tmp->push_back(index); + $$ = tmp; + } + | '[' expression ']' + { // SystemVerilog canonical range + if (generation_flag < GN_VER2005_SV) { + warn_count += 1; + cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " + << "Use at least -g2005-sv to remove this warning." << endl; + } + list *tmp = new list; + pform_range_t index; + index.first = new PENumber(new verinum((uint64_t)0, integer_width)); + index.second = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); + tmp->push_back(index); + $$ = tmp; + } + | '[' ']' + { list *tmp = new list; + pform_range_t index (0,0); + yyerror("sorry: Dynamic array ranges not supported."); + tmp->push_back(index); + $$ = tmp; + } + | '[' '$' ']' + { // SystemVerilog queue + list *tmp = new list; + pform_range_t index (0,0); + if (gn_system_verilog()) { + yyerror("sorry: Dynamic array ranges not supported."); + } else { + yyerror("error: Queue declarations require System Verilog."); + } + tmp->push_back(index); + $$ = tmp; + } + ; + /* Verilog-2001 supports attribute lists, which can be attached to a variety of different objects. The syntax inside the (* *) is a comma separated list of names or names with assigned values. */ @@ -633,47 +1792,12 @@ attribute rule has presumably set up the scope. */ block_item_decl - : attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt range - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($6, $5, $4, dtype); - if ($1) delete $1; - } - /* This differs from the above pattern only in the absence of the - range. This is the rule for a scalar. */ - - | attribute_list_opt K_reg - primitive_type_opt unsigned_signed_opt - register_variable_list ';' - { ivl_variable_type_t dtype = $3; - if (dtype == IVL_VT_NO_TYPE) - dtype = IVL_VT_LOGIC; - pform_set_net_range($5, 0, $4, dtype); - if ($1) delete $1; - } - - | attribute_list_opt K_bit unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_BOOL); - if ($1) delete $1; - } - - | attribute_list_opt K_logic unsigned_signed_opt range_opt - register_variable_list ';' - { - pform_set_net_range($5, $4, $3, IVL_VT_LOGIC); - if ($1) delete $1; - } /* Integer atom declarations are simpler in that they do not have all the trappings of a general variable declaration. All of that is implicit in the "integer" of the declaration. */ - | attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' + : attribute_list_opt K_integer signed_unsigned_opt register_variable_list ';' { pform_set_reg_integer($4); if ($1) delete $1; } @@ -683,27 +1807,18 @@ block_item_decl if ($1) delete $1; } - | attribute_list_opt atom2_type signed_unsigned_opt register_variable_list ';' - { pform_set_integer_2atom($2, $3, $4); - if ($1) delete $1; - } + /* variable declarations. Note that data_type can be 0 if we are + recovering from an error. */ - /* Enum data types are possible here. */ - - | attribute_list_opt enum_data_type register_variable_list ';' - { pform_set_enum(@2, $2, $3); + | attribute_list_opt data_type register_variable_list ';' + { if ($2) pform_set_data_type(@2, $2, $3); if ($1) delete $1; } - /* real declarations are fairly simple as there is no range of - signed flag in the declaration. Create the real as a NetNet::REG - with real value. Note that real and realtime are interchangeable - in this context. */ - - | attribute_list_opt K_real real_variable_list ';' - { delete $3; } - | attribute_list_opt K_realtime real_variable_list ';' - { delete $3; } + | attribute_list_opt K_reg data_type register_variable_list ';' + { if ($3) pform_set_data_type(@3, $3, $4); + if ($1) delete $1; + } | K_event list_of_identifiers ';' { pform_make_events($2, @1.text, @1.first_line); @@ -712,14 +1827,12 @@ block_item_decl | K_parameter parameter_assign_decl ';' | K_localparam localparam_assign_decl ';' + /* Blocks can have type declarations. */ + + | type_declaration + /* Recover from errors that happen within variable lists. Use the trailing semi-colon to resync the parser. */ - - | attribute_list_opt K_reg error ';' - { yyerror(@2, "error: syntax error in reg variable list."); - yyerrok; - if ($1) delete $1; - } | attribute_list_opt K_integer error ';' { yyerror(@2, "error: syntax error in integer variable list."); yyerrok; @@ -729,14 +1842,7 @@ block_item_decl { yyerror(@2, "error: syntax error in time variable list."); yyerrok; } - | attribute_list_opt K_real error ';' - { yyerror(@2, "error: syntax error in real variable list."); - yyerrok; - } - | attribute_list_opt K_realtime error ';' - { yyerror(@2, "error: syntax error in realtime variable list."); - yyerrok; - } + | K_parameter error ';' { yyerror(@1, "error: syntax error in parameter list."); yyerrok; @@ -757,6 +1863,41 @@ block_item_decls_opt | ; + /* Type declarations are parsed here. The rule actions call pform + functions that add the declaration to the current lexical scope. */ +type_declaration + : K_typedef data_type IDENTIFIER ';' + { perm_string name = lex_strings.make($3); + pform_set_typedef(name, $2); + delete[]$3; + } + + /* These are forward declarations... */ + + | K_typedef K_class IDENTIFIER ';' + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($3); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$3; + } + | K_typedef K_enum IDENTIFIER ';' + { yyerror(@1, "sorry: Enum forward declarations not supported yet.") } + | K_typedef K_struct IDENTIFIER ';' + { yyerror(@1, "sorry: Struct forward declarations not supported yet.") } + | K_typedef K_union IDENTIFIER ';' + { yyerror(@1, "sorry: Union forward declarations not supported yet.") } + | K_typedef IDENTIFIER ';' + { // Create a synthetic typedef for the class name so that the + // lexor detects the name as a type. + perm_string name = lex_strings.make($2); + class_type_t*tmp = new class_type_t(name); + pform_set_typedef(name, tmp); + delete[]$2; + } + ; + /* The structure for an enumeration data type is the keyword "enum", followed by the enumeration values in curly braces. Also allow for an optional base type. The default base type is "int", but it @@ -765,50 +1906,56 @@ block_item_decls_opt enum_data_type : K_enum '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($3); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = true; - enum_type->range.reset( make_range_from_width(32) ); + enum_type->range.reset(make_range_from_width(32)); $$ = enum_type; } | K_enum atom2_type signed_unsigned_opt '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($5); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; - enum_type->range.reset( make_range_from_width($2) ); + enum_type->range.reset(make_range_from_width($2)); $$ = enum_type; } | K_enum K_integer signed_unsigned_opt '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($5); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( make_range_from_width(integer_width) ); + enum_type->range.reset(make_range_from_width(integer_width)); $$ = enum_type; } | K_enum K_logic unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } | K_enum K_reg unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_LOGIC; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } | K_enum K_bit unsigned_signed_opt range '{' enum_name_list '}' { enum_type_t*enum_type = new enum_type_t; + FILE_NAME(enum_type, @1); enum_type->names .reset($6); enum_type->base_type = IVL_VT_BOOL; enum_type->signed_flag = $3; - enum_type->range.reset( $4 ); + enum_type->range.reset($4); $$ = enum_type; } ; @@ -879,6 +2026,64 @@ enum_name } ; +struct_data_type + : K_struct K_packed_opt '{' struct_union_member_list '}' + { struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + tmp->members .reset($4); + $$ = tmp; + } + | K_struct K_packed_opt '{' error '}' + { yyerror(@4, "error: Errors in struct/union member list."); + yyerrok; + struct_type_t*tmp = new struct_type_t; + FILE_NAME(tmp, @1); + tmp->packed_flag = $2; + $$ = tmp; + } + ; + +struct_union_member_list + : struct_union_member_list struct_union_member + { list*tmp = $1; + tmp->push_back($2); + $$ = tmp; + } + | struct_union_member + { list*tmp = new list; + tmp->push_back($1); + $$ = tmp; + } + ; + +struct_union_member + : attribute_list_opt K_bit range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt K_logic range_opt list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_LOGIC; + tmp->range .reset($3); + tmp->names .reset($4); + $$ = tmp; + } + | attribute_list_opt atom2_type list_of_variable_decl_assignments ';' + { struct_member_t*tmp = new struct_member_t; + FILE_NAME(tmp, @2); + tmp->type = IVL_VT_BOOL; + tmp->range .reset(make_range_from_width($2)); + tmp->names .reset($3); + $$ = tmp; + } + ; + case_item : expression_list_proper ':' statement_or_null { PCase::Item*tmp = new PCase::Item; @@ -1298,34 +2503,14 @@ branch_probe_expression ; expression - : expr_primary - { $$ = $1; } + : expr_primary + { $$ = $1; } + | inc_or_dec_expression + { $$ = $1; } + | inside_expression + { $$ = $1; } | '+' expr_primary %prec UNARY_PREC { $$ = $2; } - | K_INCR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('I', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_INCR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('i', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_DECR expr_primary %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('D', $2); - FILE_NAME(tmp, @2); - $$ = tmp; - } - | expr_primary K_DECR %prec UNARY_PREC - { - PEUnary*tmp = new PEUnary('d', $1); - FILE_NAME(tmp, @1); - $$ = tmp; - } | '-' expr_primary %prec UNARY_PREC { PEUnary*tmp = new PEUnary('-', $2); FILE_NAME(tmp, @2); @@ -1687,6 +2872,16 @@ expr_primary } } + | implicit_class_handle + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: Implicit class handles (this/super) are not supported."); + $$ = 0; + } + /* Many of the VAMS built-in functions are available as builtin functions with $system_function equivalents. */ @@ -1890,6 +3085,16 @@ expr_primary yyerrok; } + | '{' '}' + { // This is the empty queue syntax. + if (gn_system_verilog()) { + yyerror(@1, "sorry: Expty queue expressions not supported."); + } else { + yyerror(@1, "error: Concatenations are not allowed to be empty."); + } + $$ = 0; + } + /* Cast expressions are primaries */ | DEC_NUMBER '\'' '(' expression ')' @@ -1904,30 +3109,52 @@ expr_primary $$ = base; } } + + /* Aggregate literals are primaries. */ + + | assignment_pattern + { $$ = $1; } + + /* SystemVerilog supports streaming concatenation */ + | streaming_concatenation + { $$ = $1; } + + | K_null + { yyerror("sorry: null expressions not supported yet."); + $$ = 0; + } ; /* A function_item_list borrows the task_port_item run to match declarations of ports. We check later to make sure there are no - output or inout ports actually used. */ + output or inout ports actually used. + + The function_item is the same as tf_item_declaration. */ +function_item_list_opt + : function_item_list { $$ = $1; } + | { $$ = 0; } + ; + function_item_list - : function_item - { $$ = $1; } - | function_item_list function_item - { if ($1 && $2) { - svector*tmp = new svector(*$1, *$2); - delete $1; - delete $2; - $$ = tmp; - } else if ($1) { - $$ = $1; - } else { - $$ = $2; - } - } - ; + : function_item + { $$ = $1; } + | function_item_list function_item + { /* */ + if ($1 && $2) { + svector*tmp = new svector(*$1, *$2); + delete $1; + delete $2; + $$ = tmp; + } else if ($1) { + $$ = $1; + } else { + $$ = $2; + } + } + ; function_item - : task_port_item + : tf_port_declaration { $$ = $1; } | block_item_decl { $$ = 0; } @@ -1946,20 +3173,21 @@ gate_instance $$ = tmp; } - | IDENTIFIER range '(' expression_list_with_nuls ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' expression_list_with_nuls ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } + | '(' expression_list_with_nuls ')' { lgate*tmp = new lgate; tmp->name = ""; @@ -1971,50 +3199,50 @@ gate_instance /* Degenerate modules can have no ports. */ - | IDENTIFIER range - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = 0; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = 0; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } /* Modules can also take ports by port-name expressions. */ - | IDENTIFIER '(' port_name_list ')' - { lgate*tmp = new lgate; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $3; - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - $$ = tmp; - } + | IDENTIFIER '(' port_name_list ')' + { lgate*tmp = new lgate; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $3; + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + $$ = tmp; + } - | IDENTIFIER range '(' port_name_list ')' - { lgate*tmp = new lgate; - list*rng = $2; - tmp->name = $1; - tmp->parms = 0; - tmp->parms_by_name = $4; - tmp->range[0] = rng->front(); rng->pop_front(); - tmp->range[1] = rng->front(); rng->pop_front(); - assert(rng->empty()); - tmp->file = @1.text; - tmp->lineno = @1.first_line; - delete[]$1; - delete rng; - $$ = tmp; - } + | IDENTIFIER range '(' port_name_list ')' + { lgate*tmp = new lgate; + list*rng = $2; + tmp->name = $1; + tmp->parms = 0; + tmp->parms_by_name = $4; + tmp->range = rng->front(); + rng->pop_front(); + assert(rng->empty()); + tmp->file = @1.text; + tmp->lineno = @1.first_line; + delete[]$1; + delete rng; + $$ = tmp; + } | IDENTIFIER '(' error ')' { lgate*tmp = new lgate; @@ -2267,7 +3495,7 @@ port_declaration K_input atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list* use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::PINPUT, @@ -2413,7 +3641,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -2432,7 +3660,7 @@ port_declaration K_output atom2_type signed_unsigned_opt IDENTIFIER '=' expression { Module::port_t*ptmp; perm_string name = lex_strings.make($5); - list*use_range = make_range_from_width($3); + list*use_range = make_range_from_width($3); ptmp = pform_module_port_reference(name, @2.text, @2.first_line); pform_module_define_port(@2, name, NetNet::POUTPUT, @@ -2514,19 +3742,33 @@ atom2_type assignments. It is more limited than the general expr_primary rule to reflect the rules for assignment l-values. */ lpvalue - : hierarchy_identifier - { PEIdent*tmp = new PEIdent(*$1); - FILE_NAME(tmp, @1); - $$ = tmp; - delete $1; - } - | '{' expression_list_proper '}' - { PEConcat*tmp = new PEConcat(*$2); - FILE_NAME(tmp, @1); - delete $2; - $$ = tmp; - } - ; + : hierarchy_identifier + { PEIdent*tmp = new PEIdent(*$1); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $1; + } + + | implicit_class_handle '.' hierarchy_identifier + { yyerror(@1, "sorry: implicit class handles (this/super) not supported."); + PEIdent*tmp = new PEIdent(*$3); + FILE_NAME(tmp, @1); + $$ = tmp; + delete $3; + } + + | '{' expression_list_proper '}' + { PEConcat*tmp = new PEConcat(*$2); + FILE_NAME(tmp, @1); + delete $2; + $$ = tmp; + } + + | streaming_concatenation + { yyerror(@1, "sorry: streaming concatenation not supported in l-values."); + $$ = 0; + } + ; /* Continuous assignments have a list of individual assignments. */ @@ -2575,40 +3817,90 @@ local_timeunit_prec_decl section, with optional ports, then an optional list of module items, and finally an end marker. */ -module : attribute_list_opt module_start IDENTIFIER - { pform_startmodule($3, @2.text, @2.first_line, $1); } - module_parameter_port_list_opt - module_port_list_opt - module_attribute_foreign ';' - { pform_module_set_ports($6); } - local_timeunit_prec_decl_opt - { have_timeunit_decl = true; // Every thing past here is - have_timeprec_decl = true; // a check! - pform_check_timeunit_prec(); - } - module_item_list_opt - K_endmodule - { Module::UCDriveType ucd; - switch (uc_drive) { - case UCD_NONE: - default: - ucd = Module::UCD_NONE; - break; - case UCD_PULL0: - ucd = Module::UCD_PULL0; - break; - case UCD_PULL1: - ucd = Module::UCD_PULL1; - break; - } - pform_endmodule($3, in_celldefine, ucd); - delete[]$3; - have_timeunit_decl = false; // We will allow decls again. - have_timeprec_decl = false; - } - ; +module + : attribute_list_opt module_start IDENTIFIER + { pform_startmodule($3, @2.text, @2.first_line, $1); } + module_parameter_port_list_opt + module_port_list_opt + module_attribute_foreign ';' + { pform_module_set_ports($6); } + local_timeunit_prec_decl_opt + { have_timeunit_decl = true; // Every thing past here is + have_timeprec_decl = true; // a check! + pform_check_timeunit_prec(); + } + module_item_list_opt + module_end + { Module::UCDriveType ucd; + // The lexor detected `unconnected_drive directives and + // marked what it found in the uc_drive variable. Use that + // to generate a UCD flag for the module. + switch (uc_drive) { + case UCD_NONE: + default: + ucd = Module::UCD_NONE; + break; + case UCD_PULL0: + ucd = Module::UCD_PULL0; + break; + case UCD_PULL1: + ucd = Module::UCD_PULL1; + break; + } + // Check that program/endprogram and module/endmodule + // keywords match. + if ($2 != $13) { + switch ($2) { + case K_module: + yyerror(@13, "error: module not closed by endmodule."); + break; + case K_program: + yyerror(@13, "error: program not closed by endprogram."); + break; + default: + break; + } + } + if ($2 == K_program) { + yyerror(@2, "sorry: Program blocks not supported yet."); + } + pform_endmodule($3, in_celldefine, ucd); + delete[]$3; + have_timeunit_decl = false; // We will allow decls again. + have_timeprec_decl = false; + } + endname_opt + { // Last step: check any closing name. This is done late so + // that the parser can look ahead to detect the present + // endname_opt but still have the pform_endmodule() called + // early enough that the lexor can know we are outside the + // module. + if ($15 && (strcmp($3,$15) != 0)) { + yyerror(@15, "error: End name doesn't match module/program name"); + } + if ($15) delete[]$15; + } + ; -module_start : K_module | K_macromodule ; + /* Modules start with module/macromodule or program keyword, and end + with the endmodule or endprogram keyword. The syntax for modules + and programs is almost identical, so let semantics sort out the + differences. */ +module_start + : K_module { $$ = K_module; } + | K_macromodule { $$ = K_module; } + | K_program { $$ = K_program; } + ; + +module_end + : K_endmodule { $$ = K_module; } + | K_endprogram { $$ = K_program; } + ; + +endname_opt + : ':' IDENTIFIER { $$ = $2; } + | { $$ = 0; } + ; module_attribute_foreign : K_PSTAR IDENTIFIER K_integer IDENTIFIER '=' STRING ';' K_STARP { $$ = 0; } @@ -2695,6 +3987,19 @@ module_item } } + /* Allow struct nets. */ + + | attribute_list_opt net_type struct_data_type net_variable_list ';' + + { pform_makewire(@2, $3, NetNet::NOT_A_PORT, $4, $1); + delete $1; + } + + | attribute_list_opt net_type struct_data_type error ';' + + { yyerror(@5, "error: Errors in net variable list."); + } + /* This form doesn't have the range, but does have strengths. This gives strength to the assignment drivers. */ @@ -2728,7 +4033,7 @@ module_item delete $4; } - | port_type unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' + | port_direction unsigned_signed_opt range_opt delay3_opt list_of_identifiers ';' { pform_set_port_type(@1, $5, $3, $2, $1); } @@ -2736,7 +4041,7 @@ module_item input wire signed [h:l] ; This creates the wire and sets the port type all at once. */ - | port_type net_type unsigned_signed_opt range_opt list_of_identifiers ';' + | port_direction net_type unsigned_signed_opt range_opt list_of_identifiers ';' { pform_makewire(@1, $4, $3, $5, $2, $1, IVL_VT_NO_TYPE, 0, SR_BOTH); } @@ -2757,7 +4062,7 @@ module_item delete $5; } - | port_type K_wreal list_of_identifiers ';' + | port_direction K_wreal list_of_identifiers ';' { pform_makewire(@1, 0, true, $3, NetNet::WIRE, $1, IVL_VT_REAL, 0, SR_BOTH); } @@ -2778,7 +4083,7 @@ module_item yyerror(@2, "error: reg variables cannot be inouts."); } - | port_type unsigned_signed_opt range_opt delay3_opt error ';' + | port_direction unsigned_signed_opt range_opt delay3_opt error ';' { yyerror(@1, "error: Invalid variable list" " in port declaration."); if ($3) delete $3; @@ -2795,7 +4100,7 @@ module_item /* block_item_decl rule is shared with task blocks and named begin/end. */ - | block_item_decl + | block_item_decl /* */ @@ -2910,151 +4215,11 @@ module_item | attribute_list_opt K_analog analog_statement { 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 - definitions in the task_body to take on the scope of the task - instead of the module. Note that these runs accept for the task - body statement_or_null, although the standard does not allow null - statements in the task body. But we continue to accept it as an - extension. */ + | class_declaration - | K_task automatic_opt IDENTIFIER ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_item_list_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($7); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($7->size() > 1 && !gn_system_verilog()) { - yyerror(@7, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $7; - } + | task_declaration - | K_task automatic_opt IDENTIFIER '(' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - task_port_decl_list ')' ';' - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports($6); - current_task_set_statement($10); - pform_pop_scope(); - current_task = 0; - delete[]$3; - if ($10->size() > 1 && !gn_system_verilog()) { - yyerror(@10, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $10; - } - - | K_task automatic_opt IDENTIFIER '(' ')' ';' - { assert(current_task == 0); - current_task = pform_push_task_scope(@1, $3, $2); - } - block_item_decls_opt - statement_or_null_list - K_endtask - { current_task->set_ports(0); - current_task_set_statement($9); - pform_pop_scope(); - current_task = 0; - cerr << @3 << ": warning: task definition for \"" << $3 - << "\" has an empty port declaration list!" << endl; - delete[]$3; - if ($9->size() > 1 && !gn_system_verilog()) { - yyerror(@9, "error: Task body with multiple statements requres SystemVerilog."); - } - delete $9; - } - - | K_task automatic_opt IDENTIFIER error K_endtask - { - assert(current_task == 0); - delete[]$3; - } - - /* The function declaration rule matches the function declaration - header, then pushes the function scope. This causes the - definitions in the func_body to take on the scope of the function - instead of the module. */ - - | K_function automatic_opt function_range_or_type_opt IDENTIFIER ';' - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - function_item_list statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($8 && $8->size() > 0); - if ($8->size() == 1) { - current_function->set_statement((*$8)[0]); - delete $8; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @8); - tmp->set_statement( *$8 ); - current_function->set_statement(tmp); - delete $8; - if (!gn_system_verilog()) { - yyerror(@8, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - } - - | K_function automatic_opt function_range_or_type_opt IDENTIFIER - { assert(current_function == 0); - current_function = pform_push_function_scope(@1, $4, $2); - } - '(' task_port_decl_list_opt ')' ';' - block_item_decls_opt - statement_list - K_endfunction - { current_function->set_ports($7); - current_function->set_return($3); - assert($11 && $11->size() > 0); - if ($11->size() == 1) { - current_function->set_statement((*$11)[0]); - delete $11; - } else { - PBlock*tmp = new PBlock(PBlock::BL_SEQ); - FILE_NAME(tmp, @11); - tmp->set_statement( *$11 ); - current_function->set_statement(tmp); - delete $11; - if (!gn_system_verilog()) { - yyerror(@11, "error: Function body with multiple statements requres SystemVerilog."); - } - } - pform_pop_scope(); - current_function = 0; - delete[]$4; - if ($7==0 && !gn_system_verilog()) { - yyerror(@7, "error: Empty parenthesis syntax requires SystemVerilog."); - } - } - | K_function automatic_opt function_range_or_type_opt IDENTIFIER error K_endfunction - { /* */ - if (current_function) { - pform_pop_scope(); - current_function = 0; - } - assert(current_function == 0); - yyerror(@1, "error: Syntax error defining function."); - yyerrok; - delete[]$4; - } + | function_declaration /* A generate region can contain further module items. Actually, it is supposed to be limited to certain kinds of module items, but @@ -3185,11 +4350,6 @@ module_item { pform_set_timeprecision($2, true, true); } ; -automatic_opt - : K_automatic { $$ = true; } - | { $$ = false;} - ; - generate_if : K_if '(' expression ')' { pform_start_generate_if(@1, $3); } generate_case_items @@ -3362,6 +4522,16 @@ parameter_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } + | atom2_type + { param_active_range = make_range_from_width($1); + param_active_signed = true; + param_active_type = IVL_VT_BOOL; + } + parameter_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } ; parameter_assign_list @@ -3487,6 +4657,16 @@ localparam_assign_decl param_active_signed = false; param_active_type = IVL_VT_LOGIC; } + | atom2_type + { param_active_range = make_range_from_width($1); + param_active_signed = true; + param_active_type = IVL_VT_BOOL; + } + localparam_assign_list + { param_active_range = 0; + param_active_signed = false; + param_active_type = IVL_VT_LOGIC; + } ; localparam_assign_list @@ -3780,112 +4960,76 @@ port_reference_list } ; -port_type - : K_input { $$ = NetNet::PINPUT; } - | K_output { $$ = NetNet::POUTPUT; } - | K_inout { $$ = NetNet::PINOUT; } - ; - + /* The range is a list of variable dimensions. */ range - : '[' expression ':' expression ']' - { list*tmp = new list; - tmp->push_back($2); - tmp->push_back($4); + : variable_dimension + { $$ = $1; } + | range variable_dimension + { list*tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } $$ = tmp; } ; range_opt - : range - | { $$ = 0; } - ; + : range + | { $$ = 0; } + ; + dimensions_opt : { $$ = 0; } | dimensions { $$ = $1; } dimensions - : '[' expression ':' expression ']' - { list *tmp = new list; - index_component_t index; - index.msb = $2; - index.lsb = $4; - tmp->push_back(index); - $$ = tmp; - } - | '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = new list; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $2, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ':' expression ']' - { list *tmp = $1; - index_component_t index; - index.msb = $3; - index.lsb = $5; - tmp->push_back(index); - $$ = tmp; - } - | dimensions '[' expression ']' - { if (generation_flag < GN_VER2005_SV) { - warn_count += 1; - cerr << @2 << ": warning: Use of SystemVerilog [size] dimension. " - << "Use at least -g2005-sv to remove this warning." << endl; - } - list *tmp = $1; - index_component_t index; - index.msb = new PENumber(new verinum((uint64_t)0, integer_width)); - index.lsb = new PEBinary('-', $3, new PENumber(new verinum((uint64_t)1, integer_width))); - tmp->push_back(index); - $$ = tmp; - } + : variable_dimension + { $$ = $1; } + | dimensions variable_dimension + { list *tmp = $1; + if ($2) { + tmp->splice(tmp->end(), *$2); + delete $2; + } + $$ = tmp; + } + ; - /* This is used to express the return type of a function. */ + /* This is used to express the return type of a function. This is + not quite right, and should be replaced with a variant that uses + the data_type rule. This will get us by for now. */ function_range_or_type_opt : unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($1) - $$.type = PTF_REG_S; - if ($2) - $$.range = make_range_vector($2); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = $2; + if ($1) + $$.type = PTF_REG_S; + } | K_reg unsigned_signed_opt range_opt - { - /* the default type is reg unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is reg unsigned and no range */ + $$.type = PTF_REG; + $$.range = $3; + if ($2) + $$.type = PTF_REG_S; + } | bit_logic unsigned_signed_opt range_opt - { - /* the default type is bit/logic unsigned and no range */ - $$.type = PTF_REG; - $$.range = 0; - if ($2) - $$.type = PTF_REG_S; - if ($3) - $$.range = make_range_vector($3); - } + { /* the default type is bit/logic unsigned and no range */ + $$.type = PTF_REG; + $$.range = $3; + if ($2) + $$.type = PTF_REG_S; + } | K_integer { $$.range = 0; $$.type = PTF_INTEGER; } | K_real { $$.range = 0; $$.type = PTF_REAL; } | K_realtime { $$.range = 0; $$.type = PTF_REALTIME; } + | K_string { $$.range = 0; $$.type = PTF_STRING; } | K_time { $$.range = 0; $$.type = PTF_TIME; } - | atom2_type { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_signed { $$.range = make_range_vector($1); $$.type = PTF_ATOM2_S; } - | atom2_type K_unsigned { $$.range = make_range_vector($1); $$.type = PTF_ATOM2; } + | K_void { $$.range = 0; $$.type = PTF_VOID; } + | atom2_type { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_signed { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2_S; } + | atom2_type K_unsigned { $$.range = make_range_from_width($1); $$.type = PTF_ATOM2; } ; /* The register_variable rule is matched only when I am parsing @@ -3899,13 +5043,13 @@ register_variable pform_makewire(@1, ident_name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); if ($2 != 0) { - index_component_t index; + pform_range_t index; if ($2->size() > 1) { yyerror(@2, "sorry: only 1 dimensional arrays " "are currently supported."); } index = $2->front(); - pform_set_reg_idx(ident_name, index.msb, index.lsb); + pform_set_reg_idx(ident_name, index.first, index.second); delete $2; } $$ = $1; @@ -3934,58 +5078,19 @@ register_variable_list } ; -real_variable - : IDENTIFIER dimensions_opt - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - if ($2 != 0) { - 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; - } - | IDENTIFIER '=' expression - { perm_string name = lex_strings.make($1); - pform_makewire(@1, name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_REAL, 0); - pform_make_reginit(@1, name, $3); - $$ = $1; - } - ; - -real_variable_list - : real_variable - { list*tmp = new list; - tmp->push_back(lex_strings.make($1)); - $$ = tmp; - delete[]$1; - } - | real_variable_list ',' real_variable - { list*tmp = $1; - tmp->push_back(lex_strings.make($3)); - $$ = tmp; - delete[]$3; - } - ; - net_variable : IDENTIFIER dimensions_opt { perm_string name = lex_strings.make($1); pform_makewire(@1, name, NetNet::IMPLICIT, NetNet::NOT_A_PORT, IVL_VT_NO_TYPE, 0); if ($2 != 0) { - index_component_t index; + pform_range_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); + pform_set_reg_idx(name, index.first, index.second); delete $2; } $$ = $1; @@ -4340,7 +5445,7 @@ spec_notifier ; -statement +statement /* This is roughly statement_item in the LRM */ /* assign and deassign statements are procedural code to do structural assignments, and to turn that structural assignment @@ -4385,7 +5490,7 @@ statement FILE_NAME(tmp, @1); $$ = tmp; } - | K_begin statement_list K_end + | K_begin statement_or_null_list K_end { PBlock*tmp = new PBlock(PBlock::BL_SEQ); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -4398,7 +5503,7 @@ statement current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_end + statement_or_null_list_opt K_end { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -4421,7 +5526,7 @@ statement FILE_NAME(tmp, @1); $$ = tmp; } - | K_fork statement_list K_join + | K_fork statement_or_null_list K_join { PBlock*tmp = new PBlock(PBlock::BL_PAR); FILE_NAME(tmp, @1); tmp->set_statement(*$2); @@ -4434,7 +5539,7 @@ statement current_block_stack.push(tmp); } block_item_decls_opt - statement_list_or_null K_join + statement_or_null_list_opt K_join { pform_pop_scope(); assert(! current_block_stack.empty()); PBlock*tmp = current_block_stack.top(); @@ -4459,16 +5564,11 @@ statement delete $2; $$ = tmp; } - | K_forever statement - { PForever*tmp = new PForever($2); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_repeat '(' expression ')' statement - { PRepeat*tmp = new PRepeat($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } + + | loop_statement { $$ = $1; } + + | jump_statement { $$ = $1; } + | K_case '(' expression ')' case_items K_endcase { PCase*tmp = new PCase(NetCase::EQ, $3, $5); FILE_NAME(tmp, @1); @@ -4508,45 +5608,28 @@ statement { yyerror(@1, "error: Malformed conditional expression."); $$ = $5; } - | K_for '(' lpvalue '=' expression ';' expression ';' - lpvalue '=' expression ')' statement - { PForStatement*tmp = new PForStatement($3, $5, $7, $9, $11, $13); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_for '(' lpvalue '=' expression ';' expression ';' - error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop step assignment."); - } - | K_for '(' lpvalue '=' expression ';' error ';' - lpvalue '=' expression ')' statement - { $$ = 0; - yyerror(@1, "error: Error in for loop condition expression."); - } - | K_for '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Incomprehensible for loop."); - } - | K_while '(' expression ')' statement - { PWhile*tmp = new PWhile($3, $5); - FILE_NAME(tmp, @1); - $$ = tmp; - } - | K_while '(' error ')' statement - { $$ = 0; - yyerror(@1, "error: Error in while loop condition."); - } - | compressed_statement ';' - { $$ = $1; } - | delay1 statement_or_null - { PExpr*del = $1->front(); - assert($1->size() == 1); - delete $1; - PDelayStatement*tmp = new PDelayStatement(del, $2); - FILE_NAME(tmp, @1); - $$ = tmp; - } + /* SytemVerilog adds the compressed_statement */ + + | compressed_statement ';' + { $$ = $1; } + + /* increment/decrement expressions can also be statements. When used + as statements, we can rewrite a++ as a += 1, and so on. */ + + | inc_or_dec_expression ';' + { $$ = pform_compressed_assign_from_inc_dec(@1, $1); } + + /* */ + + | delay1 statement_or_null + { PExpr*del = $1->front(); + assert($1->size() == 1); + delete $1; + PDelayStatement*tmp = new PDelayStatement(del, $2); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | event_control attribute_list_opt statement_or_null { PEventStatement*tmp = $1; if (tmp == 0) { @@ -4572,11 +5655,15 @@ statement tmp->set_statement($6); $$ = tmp; } + + /* Various assignment statements */ + | lpvalue '=' expression ';' { PAssign*tmp = new PAssign($1,$3); FILE_NAME(tmp, @1); $$ = tmp; } + | error '=' expression ';' { yyerror(@2, "Syntax in assignment statement l-value."); yyerrok; @@ -4627,6 +5714,27 @@ statement FILE_NAME(tmp, @1); $$ = tmp; } + + /* The IEEE1800 standard defines dynamic_array_new assignment as a + different rule from regular assignment. That implies that the + dynamic_array_new is not an expression in general, which makes + some sense. Elaboration should make sure the lpvalue is an array name. */ + + | lpvalue '=' dynamic_array_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + + /* The class new and dynamic array new expressions are special, so + sit in rules of their own. */ + + | lpvalue '=' class_new ';' + { PAssign*tmp = new PAssign($1,$3); + FILE_NAME(tmp, @1); + $$ = tmp; + } + | K_wait '(' expression ')' statement_or_null { PEventStatement*tmp; PEEvent*etmp = new PEEvent(PEEvent::POSITIVE, $3); @@ -4649,38 +5757,65 @@ statement delete[]$1; $$ = tmp; } - | hierarchy_identifier '(' expression_list_proper ')' ';' - { PCallTask*tmp = new PCallTask(*$1, *$3); - FILE_NAME(tmp, @1); - delete $1; - delete $3; - $$ = tmp; - } - /* NOTE: The standard doesn't really support an empty argument list - between parentheses, but it seems natural, and people commonly - want it. So accept it explicitly. */ + | hierarchy_identifier '(' expression_list_with_nuls ')' ';' + { PCallTask*tmp = new PCallTask(*$1, *$3); + FILE_NAME(tmp, @1); + delete $1; + delete $3; + $$ = tmp; + } - | hierarchy_identifier '(' ')' ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } - | hierarchy_identifier ';' - { listpt; - PCallTask*tmp = new PCallTask(*$1, pt); - FILE_NAME(tmp, @1); - delete $1; - $$ = tmp; - } - | error ';' - { yyerror(@2, "error: malformed statement"); - yyerrok; - $$ = new PNoop; - } - ; + | hierarchy_identifier K_with '{' constraint_block_item_list_opt '}' ';' + { /* ....randomize with { } */ + if ($1 && peek_tail_name(*$1) == "randomize") { + if (!gn_system_verilog()) + yyerror(@2, "error: Randomize with constraint requires SystemVerilog."); + else + yyerror(@2, "sorry: Randomize with constraint not supported."); + } else { + yyerror(@2, "error: Constraint block can only be applied to randomize method."); + } + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + + | implicit_class_handle '.' hierarchy_identifier '(' expression_list_with_nuls ')' ';' + { PCallTask*tmp = new PCallTask(*$3, *$5); + yyerror(@1, "sorry: Implicit class handle not supported in front of task names."); + FILE_NAME(tmp, @1); + delete $3; + delete $5; + $$ = tmp; + } + + | hierarchy_identifier ';' + { listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + + | hierarchy_identifier '(' error ')' ';' + { yyerror(@3, "error: Syntax error in task arguments."); + listpt; + PCallTask*tmp = new PCallTask(*$1, pt); + FILE_NAME(tmp, @1); + delete $1; + $$ = tmp; + } + + | error ';' + { yyerror(@2, "error: malformed statement"); + yyerrok; + $$ = new PNoop; + } + + ; compressed_statement : lpvalue K_PLUS_EQ expression @@ -4740,38 +5875,11 @@ compressed_statement } ; -statement_list_or_null - : statement_list_or_null statement - { vector*tmp = $1; - if (tmp) { - tmp->push_back($2); - } else { - tmp = new vector(1); - tmp->at(0) = $2; - } - $$ = tmp; - } - | - { $$ = 0; } - ; -statement_list - : statement_list statement - { vector*tmp = $1; - tmp->push_back($2); - $$ = tmp; - } - | statement - { vector*tmp = new vector(1); - tmp->at(0) = $1; - $$ = tmp; - } - ; - -statement_or_null - : statement +statement_or_null_list_opt + : statement_or_null_list { $$ = $1; } - | ';' + | { $$ = 0; } ; @@ -4797,123 +5905,9 @@ analog_statement other block items. */ task_item : block_item_decl { $$ = new svector(0); } - | task_port_item { $$ = $1; } + | tf_port_declaration { $$ = $1; } ; -reg_opt - : K_reg { $$ = true; } - | { $$ = false; } - ; - -task_port_item - : K_input reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout reg_opt unsigned_signed_opt range_opt list_of_identifiers ';' - { svector*tmp = pform_make_task_ports(NetNet::PINOUT, - $2 ? IVL_VT_LOGIC : - IVL_VT_NO_TYPE, - $3, $4, $5, - @1.text, @1.first_line); - $$ = tmp; - } - - /* When the port is an integer, infer a signed vector of the integer - shape. Generate a range ([31:0]) to make it work. */ - - | K_input K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer list_of_identifiers ';' - { list*range_stub = make_range_from_width(integer_width); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, - range_stub, $3, - @1.text, @1.first_line, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | K_input K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time list_of_identifiers ';' - { list*range_stub = make_range_from_width(64); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, - range_stub, $3, - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | K_input real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime list_of_identifiers ';' - { svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, true, - 0, $3, - @1.text, @1.first_line); - $$ = tmp; - } - ; - task_item_list : task_item_list task_item { svector*tmp = new svector(*$1, *$2); @@ -4932,309 +5926,11 @@ task_item_list_opt { $$ = 0; } ; -task_port_decl - - : K_input reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_output reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout reg_opt unsigned_signed_opt range_opt IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_input bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_output bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::POUTPUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_inout bit_logic unsigned_signed_opt range_opt IDENTIFIER - { - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = $2; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range($4); - svector*tmp = - pform_make_task_ports(NetNet::PINOUT, $2, $3, - $4, list_from_identifier($5), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be integer with a width of [31:0]. */ - - | K_input K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_output K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - | K_inout K_integer IDENTIFIER - { list*range_stub = make_range_from_width(integer_width); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = true; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, true, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line, true); - $$ = tmp; - } - - /* Ports can be time with a width of [63:0] (unsigned). */ - - | K_input K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout K_time IDENTIFIER - { list*range_stub = make_range_from_width(64); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_LOGIC; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_LOGIC, false, - range_stub, - list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be real or realtime. */ - - | K_input real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_output real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - | K_inout real_or_realtime IDENTIFIER - { port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_REAL; - port_declaration_context.sign_flag = false; - delete port_declaration_context.range; - port_declaration_context.range = 0; - svector*tmp - = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_REAL, false, - 0, list_from_identifier($3), - @1.text, @1.first_line); - $$ = tmp; - } - - /* Ports can be 2-value atom types. */ - - | K_input atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_output atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::POUTPUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::POUTPUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } - - | K_inout atom2_type signed_unsigned_opt IDENTIFIER - { list*range_stub = make_range_from_width($2); - port_declaration_context.port_type = NetNet::PINOUT; - port_declaration_context.var_type = IVL_VT_BOOL; - port_declaration_context.sign_flag = $3; - delete port_declaration_context.range; - port_declaration_context.range = copy_range(range_stub); - svector*tmp = pform_make_task_ports(NetNet::PINOUT, - IVL_VT_BOOL, $3, - range_stub, list_from_identifier($4), - @1.text, @1.first_line); - $$ = tmp; - } -; - -task_port_decl_list_opt - : task_port_decl_list { $$ = $1; } +tf_port_list_opt + : tf_port_list { $$ = $1; } | { $$ = 0; } ; -task_port_decl_list - : task_port_decl_list ',' task_port_decl - { svector*tmp = new svector(*$1, *$3); - delete $1; - delete $3; - $$ = tmp; - } - | task_port_decl - { $$ = $1; } - | task_port_decl_list ',' IDENTIFIER - { svector*new_decl - = pform_make_task_ports( - port_declaration_context.port_type, - port_declaration_context.var_type, - port_declaration_context.sign_flag, - copy_range(port_declaration_context.range), - list_from_identifier($3), - @3.text, @3.first_line); - svector*tmp = new svector(*$1, *new_decl); - delete $1; - delete new_decl; - $$ = tmp; - } - | task_port_decl_list ',' - { - yyerror(@2, "error: NULL port declarations are not " - "allowed."); - } - | task_port_decl_list ';' - { - yyerror(@2, "error: ';' is an invalid port declaration " - "separator."); - } - ; - ; - udp_body : K_table { lex_start_table(); } udp_entry_list @@ -5484,3 +6180,13 @@ udp_primitive delete[]$6; } ; + + /* Many keywords can be optional in the syntax, although their + presence is significant. This is a fairly common pattern so + collect those rules here. */ + +K_automatic_opt: K_automatic { $$ = true; } | { $$ = false;} ; +K_packed_opt : K_packed { $$ = true; } | { $$ = false; } ; +K_reg_opt : K_reg { $$ = true; } | { $$ = false; } ; +K_static_opt : K_static { $$ = true; } | { $$ = false; } ; +K_virtual_opt : K_virtual { $$ = true; } | { $$ = false; } ; diff --git a/parse_misc.cc b/parse_misc.cc index ed631d0b3..241341564 100644 --- a/parse_misc.cc +++ b/parse_misc.cc @@ -20,6 +20,8 @@ # include "config.h" # include "parse_misc.h" +# include +# include # include extern const char*vl_file; @@ -42,10 +44,16 @@ void VLerror(const char*msg) cerr << yylloc.text << ":" << yylloc.first_line << ": " << msg << endl; } -void VLerror(const YYLTYPE&loc, const char*msg) +void VLerror(const YYLTYPE&loc, const char*msg, ...) { + va_list ap; + va_start(ap, msg); + + fprintf(stderr, "%s:%d: ", loc.text, loc.first_line); + vfprintf(stderr, msg, ap); + fprintf(stderr, "\n"); + error_count += 1; - cerr << loc << ": " << msg << endl; based_size = 0; /* Clear the base information if we have an error. */ } diff --git a/parse_misc.h b/parse_misc.h index f3b5dfc9b..037fefffe 100644 --- a/parse_misc.h +++ b/parse_misc.h @@ -56,7 +56,7 @@ extern YYLTYPE yylloc; */ extern int VLlex(); extern void VLerror(const char*msg); -extern void VLerror(const YYLTYPE&loc, const char*msg); +extern void VLerror(const YYLTYPE&loc, const char*msg, ...) __attribute__((format(printf,2,3))); #define yywarn VLwarn extern void VLwarn(const YYLTYPE&loc, const char*msg); @@ -77,6 +77,14 @@ extern UCDriveType uc_drive; extern bool have_timeunit_decl; extern bool have_timeprec_decl; +/* + * Test if this identifier is a type identifier in the current + * context. The pform code needs to help the lexor here because the + * parser detects typedefs and marks the typedef'ed identifiers as + * type names. + */ +extern data_type_t* pform_test_type_identifier(const char*txt); + /* * Export these functions because we have to generate PENumber class * in pform.cc for user defparam definition from command file. @@ -87,4 +95,6 @@ extern verinum*make_unsized_binary(const char*txt); extern verinum*make_unsized_octal(const char*txt); extern verinum*make_unsized_hex(const char*txt); +extern char* strdupnew(char const *str); + #endif diff --git a/pform.cc b/pform.cc index 64405fc19..7fb93e9c2 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -23,6 +23,7 @@ # include "pform.h" # include "parse_misc.h" # include "parse_api.h" +# include "PClass.h" # include "PEvent.h" # include "PUdp.h" # include "PGenerate.h" @@ -267,12 +268,30 @@ void pform_pop_scope() lexical_scope = lexical_scope->parent_scope(); } +PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name) +{ + PClass*class_scope = new PClass(name, lexical_scope); + FILE_NAME(class_scope, loc); + + lexical_scope = class_scope; + return class_scope; +} + PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) { perm_string task_name = lex_strings.make(name); PTask*task = new PTask(task_name, lexical_scope, is_auto); FILE_NAME(task, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the task is already in the dictionary. if (pform_cur_generate->tasks.find(task->pscope_name()) != @@ -286,15 +305,15 @@ PTask* pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto) pform_cur_generate->tasks[task->pscope_name()] = task; } else { // Check if the task is already in the dictionary. - if (pform_cur_module->tasks.find(task->pscope_name()) != - pform_cur_module->tasks.end()) { + if (scopex->tasks.find(task->pscope_name()) != scopex->tasks.end()) { cerr << task->get_fileline() << ": error: duplicate " "definition for task '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->tasks[task->pscope_name()] = task; + scopex->tasks[task->pscope_name()] = task; } + lexical_scope = task; return task; @@ -307,6 +326,15 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, PFunction*func = new PFunction(func_name, lexical_scope, is_auto); FILE_NAME(func, loc); + + LexicalScope*scope = lexical_scope; + PScopeExtra*scopex = dynamic_cast (scope); + while (scope && !scopex) { + scope = scope->parent_scope(); + scopex = dynamic_cast (scope); + } + assert(scopex); + if (pform_cur_generate) { // Check if the function is already in the dictionary. if (pform_cur_generate->funcs.find(func->pscope_name()) != @@ -320,14 +348,13 @@ PFunction* pform_push_function_scope(const struct vlltype&loc, char*name, pform_cur_generate->funcs[func->pscope_name()] = func; } else { // Check if the function is already in the dictionary. - if (pform_cur_module->funcs.find(func->pscope_name()) != - pform_cur_module->funcs.end()) { + if (scopex->funcs.find(func->pscope_name()) != scopex->funcs.end()) { cerr << func->get_fileline() << ": error: duplicate " "definition for function '" << name << "' in '" - << pform_cur_module->mod_name() << "'." << endl; + << scopex->pscope_name() << "'." << endl; error_count += 1; } - pform_cur_module->funcs[func->pscope_name()] = func; + scopex->funcs[func->pscope_name()] = func; } lexical_scope = func; @@ -385,7 +412,7 @@ static void pform_put_enum_type_in_scope(enum_type_t*enum_set) lexical_scope->enum_sets.push_back(enum_set); } -static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) +PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type) { PWire*cur = pform_get_wire_in_scope(name); if (cur == 0) { @@ -401,6 +428,33 @@ static PWire*pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_typ return cur; } +void pform_set_typedef(perm_string name, data_type_t*data_type) +{ + data_type_t*&ref = lexical_scope->typedefs[name]; + ivl_assert(*data_type, ref == 0); + ref = data_type; +} + +data_type_t* pform_test_type_identifier(const char*txt) +{ + // If there is no lexical_scope yet, then there is NO WAY the + // identifier can be a type_identifier. + if (lexical_scope == 0) + return 0; + + perm_string name = lex_strings.make(txt); + map::iterator cur; + LexicalScope*cur_scope = lexical_scope; + do { + cur = cur_scope->typedefs.find(name); + if (cur != cur_scope->typedefs.end()) + return cur->second; + + cur_scope = cur_scope->parent_scope(); + } while (cur_scope); + return 0; +} + static void pform_put_behavior_in_scope(PProcess*pp) { lexical_scope->behaviors.push_back(pp); @@ -1464,7 +1518,7 @@ void pform_make_udp(perm_string name, bool synchronous_flag, * and the name that I receive only has the tail component. */ static void pform_set_net_range(perm_string name, - const list*range, + const list*range, bool signed_flag, ivl_variable_type_t dt, PWSRType rt) @@ -1478,11 +1532,10 @@ static void pform_set_net_range(perm_string name, if (range == 0) { /* This is the special case that we really mean a scalar. Set a fake range. */ - cur->set_range(0, 0, rt, true); + cur->set_range_scalar(rt); } else { - assert(range->size() == 2); - cur->set_range(range->front(), range->back(), rt, false); + cur->set_range(*range, rt); } cur->set_signed(signed_flag); @@ -1491,17 +1544,14 @@ static void pform_set_net_range(perm_string name, } void pform_set_net_range(list*names, - list*range, + list*range, bool signed_flag, - ivl_variable_type_t dt, - PWSRType rt) + ivl_variable_type_t dt) { - assert((range == 0) || (range->size() == 2)); - for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_net_range(txt, range, signed_flag, dt, rt); + pform_set_net_range(txt, range, signed_flag, dt, SR_NET); } delete names; @@ -1565,8 +1615,8 @@ static void pform_makegate(PGBuiltin::Type type, perm_string dev_name = lex_strings.make(info.name); PGBuiltin*cur = new PGBuiltin(type, dev_name, info.parms, delay); - if (info.range[0]) - cur->set_range(info.range[0], info.range[1]); + if (info.range.first) + cur->set_range(info.range.first, info.range.second); // The pform_makegates() that calls me will take care of // deleting the attr pointer, so tell the @@ -1705,7 +1755,7 @@ void pform_make_modgates(perm_string type, if (cur.parms_by_name) { pform_make_modgate(type, cur_name, overrides, cur.parms_by_name, - cur.range[0], cur.range[1], + cur.range.first, cur.range.second, cur.file, cur.lineno); } else if (cur.parms) { @@ -1719,14 +1769,14 @@ void pform_make_modgates(perm_string type, } pform_make_modgate(type, cur_name, overrides, cur.parms, - cur.range[0], cur.range[1], + cur.range.first, cur.range.second, cur.file, cur.lineno); } else { list*wires = new list; pform_make_modgate(type, cur_name, overrides, wires, - cur.range[0], cur.range[1], + cur.range.first, cur.range.second, cur.file, cur.lineno); } } @@ -1799,8 +1849,8 @@ void pform_make_pgassign_list(list*alist, void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr) { - if (! pform_at_module_level()) { - VLerror(li, "variable declaration assignments are only " + if (! pform_at_module_level() && !gn_system_verilog()) { + VLerror(li, "error: variable declaration assignments are only " "allowed at the module level."); delete expr; return; @@ -1839,7 +1889,7 @@ void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr) { PWire*cur = pform_get_wire_in_scope(name); @@ -1862,17 +1912,10 @@ void pform_module_define_port(const struct vlltype&li, cur->set_signed(signed_flag); if (range == 0) { - cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : - SR_BOTH, - true); + cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - cur->set_range(range->front(), range->back(), - (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, - false); + cur->set_range(*range, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } pform_bind_attributes(cur->attributes, attr); @@ -1898,6 +1941,36 @@ void pform_module_define_port(const struct vlltype&li, * function is called for every declaration. */ +static PWire* pform_get_or_make_wire(const vlltype&li, perm_string name, + NetNet::Type type, NetNet::PortType ptype, + ivl_variable_type_t dtype) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur) { + // If this is not implicit ("implicit" meaning we don't + // know what the type is yet) then set the type now. + if (type != NetNet::IMPLICIT) { + bool rc = cur->set_wire_type(type); + if (rc == false) { + ostringstream msg; + msg << name << " " << type + << " definition conflicts with " << cur->get_wire_type() + << " definition at " << cur->get_fileline() + << "."; + VLerror(msg.str().c_str()); + } + FILE_NAME(cur, li.text, li.first_line); + } + return cur; + } + + cur = new PWire(name, type, ptype, dtype); + FILE_NAME(cur, li.text, li.first_line); + + pform_put_wire_in_scope(name, cur); + return cur; +} + /* * this is the basic form of pform_makewire. This takes a single simple * name, port type, net type, data type, and attributes, and creates @@ -1909,33 +1982,13 @@ void pform_makewire(const vlltype&li, perm_string name, ivl_variable_type_t dt, list*attr) { - PWire*cur = pform_get_wire_in_scope(name); + PWire*cur = pform_get_or_make_wire(li, name, type, pt, dt); - // If this is not implicit ("implicit" meaning we don't know - // what the type is yet) then set the type now. - if (cur && type != NetNet::IMPLICIT) { - bool rc = cur->set_wire_type(type); - if (rc == false) { - ostringstream msg; - msg << name << " " << type - << " definition conflicts with " << cur->get_wire_type() - << " definition at " << cur->get_fileline() - << "."; - VLerror(msg.str().c_str()); - } - - } - - bool new_wire_flag = false; if (! cur) { - new_wire_flag = true; cur = new PWire(name, type, pt, dt); FILE_NAME(cur, li.text, li.first_line); } - if (type != NetNet::IMPLICIT) - FILE_NAME(cur, li.text, li.first_line); - bool flag; switch (dt) { case IVL_VT_REAL: @@ -1947,7 +2000,7 @@ void pform_makewire(const vlltype&li, perm_string name, << " to " << dt << "." << endl; } ivl_assert(*cur, flag); - cur->set_range(0, 0, SR_NET, true); + cur->set_range_scalar(SR_NET); cur->set_signed(true); break; default: @@ -1960,9 +2013,6 @@ void pform_makewire(const vlltype&li, perm_string name, cur->attributes[attr_cur->name] = attr_cur->parm; } } - - if (new_wire_flag) - pform_put_wire_in_scope(name, cur); } /* @@ -1971,7 +2021,7 @@ void pform_makewire(const vlltype&li, perm_string name, * pform_makewire above. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -1998,7 +2048,7 @@ void pform_makewire(const vlltype&li, * This form makes nets with delays and continuous assignments. */ void pform_makewire(const vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -2033,39 +2083,6 @@ void pform_makewire(const vlltype&li, } } -void pform_set_port_type(perm_string name, NetNet::PortType pt, - const char*file, unsigned lineno) -{ - PWire*cur = pform_get_wire_in_scope(name); - if (cur == 0) { - cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); - FILE_NAME(cur, file, lineno); - pform_put_wire_in_scope(name, cur); - } - - switch (cur->get_port_type()) { - case NetNet::PIMPLICIT: - if (! cur->set_port_type(pt)) - VLerror("error setting port direction."); - break; - - case NetNet::NOT_A_PORT: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " is not in the port list." - << endl; - error_count += 1; - break; - - default: - cerr << file << ":" << lineno << ": error: " - << "port " << name << " already has a port declaration." - << endl; - error_count += 1; - break; - } - -} - /* * This function is called by the parser to create task ports. The * resulting wire (which should be a register) is put into a list to @@ -2105,15 +2122,15 @@ void pform_set_port_type(perm_string name, NetNet::PortType pt, * constraints as those of tasks, so this works fine. Functions have * no output or inout ports. */ -svector*pform_make_task_ports(NetNet::PortType pt, +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, - const char* file, - unsigned lineno, bool isint) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); assert(names); svector*res = new svector(0); for (list::iterator cur = names->begin() @@ -2128,7 +2145,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, curw->set_port_type(pt); } else { curw = new PWire(name, NetNet::IMPLICIT_REG, pt, vtype); - FILE_NAME(curw, file, lineno); + FILE_NAME(curw, loc); pform_put_wire_in_scope(name, curw); } @@ -2137,8 +2154,7 @@ svector*pform_make_task_ports(NetNet::PortType pt, /* If there is a range involved, it needs to be set. */ if (range) { - assert(range->size() == 2); - curw->set_range(range->front(), range->back(), SR_PORT, false); + curw->set_range(*range, SR_PORT); } svector*tmp = new svector(*res, curw); @@ -2152,6 +2168,71 @@ svector*pform_make_task_ports(NetNet::PortType pt, return res; } +svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names) +{ + if (atom2_type_t*atype = dynamic_cast (vtype)) { + list*range_tmp = make_range_from_width(atype->type_code); + return pform_make_task_ports(loc, pt, IVL_VT_BOOL, + atype->signed_flag, + range_tmp, names); + } + + if (vector_type_t*vec_type = dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, vec_type->base_type, + vec_type->signed_flag, + copy_range(vec_type->pdims.get()), + names); + } + + if (/*real_type_t*real_type = */ dynamic_cast (vtype)) { + return pform_make_task_ports(loc, pt, IVL_VT_REAL, + true, 0, names); + } + + VLerror(loc, "sorry: Given type not supported here."); + return 0; +} + +/* + * The parser calls this in the rule that matches increment/decrement + * statements. The rule that does the matching creates a PEUnary with + * all the information we need, but here we convert that expression to + * a compressed assignment statement. + */ +PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, PExpr*exp) +{ + PEUnary*expu = dynamic_cast (exp); + ivl_assert(*exp, expu != 0); + + char use_op = 0; + switch (expu->get_op()) { + case 'i': + case 'I': + use_op = '+'; + break; + case 'd': + case 'D': + use_op = '-'; + break; + default: + ivl_assert(*exp, 0); + break; + } + + PExpr*lval = expu->get_expr(); + PExpr*rval = new PENumber(new verinum((uint64_t)1, 1)); + FILE_NAME(rval, loc); + + PAssign*tmp = new PAssign(lval, use_op, rval); + FILE_NAME(tmp, loc); + + delete exp; + return tmp; +} + void pform_set_attrib(perm_string name, perm_string key, char*value) { if (PWire*cur = lexical_scope->wires_find(name)) { @@ -2220,7 +2301,7 @@ LexicalScope::range_t* pform_parameter_value_range(bool exclude_flag, void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr, + bool signed_flag, list*range, PExpr*expr, LexicalScope::range_t*value_range) { LexicalScope*scope = lexical_scope; @@ -2255,11 +2336,12 @@ void pform_set_parameter(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + pform_range_t&rng = range->front(); + assert(rng.first); + assert(rng.second); + parm.msb = rng.first; + parm.lsb = rng.second; } else { parm.msb = 0; parm.lsb = 0; @@ -2273,7 +2355,7 @@ void pform_set_parameter(const struct vlltype&loc, void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, - bool signed_flag, list*range, PExpr*expr) + bool signed_flag, list*range, PExpr*expr) { LexicalScope*scope = lexical_scope; @@ -2303,11 +2385,12 @@ void pform_set_localparam(const struct vlltype&loc, parm.type = type; if (range) { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - parm.msb = range->front(); - parm.lsb = range->back(); + assert(range->size() == 1); + pform_range_t&rng = range->front(); + assert(rng.first); + assert(rng.second); + parm.msb = rng.first; + parm.lsb = rng.second; } else { parm.msb = 0; parm.lsb = 0; @@ -2404,12 +2487,48 @@ extern void pform_module_specify_path(PSpecPath*obj) pform_cur_module->specify_paths.push_back(obj); } + +static void pform_set_port_type(perm_string name, NetNet::PortType pt, + const char*file, unsigned lineno) +{ + PWire*cur = pform_get_wire_in_scope(name); + if (cur == 0) { + cur = new PWire(name, NetNet::IMPLICIT, NetNet::PIMPLICIT, IVL_VT_NO_TYPE); + FILE_NAME(cur, file, lineno); + pform_put_wire_in_scope(name, cur); + } + + switch (cur->get_port_type()) { + case NetNet::PIMPLICIT: + if (! cur->set_port_type(pt)) + VLerror("error setting port direction."); + break; + + case NetNet::NOT_A_PORT: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " is not in the port list." + << endl; + error_count += 1; + break; + + default: + cerr << file << ":" << lineno << ": error: " + << "port " << name << " already has a port declaration." + << endl; + error_count += 1; + break; + } + +} + void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType pt) { + assert(pt != NetNet::PIMPLICIT && pt != NetNet::NOT_A_PORT); + for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; @@ -2427,9 +2546,12 @@ static void pform_set_reg_integer(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + pform_range_t rng; + rng.first = new PENumber(new verinum(integer_width-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); cur->set_signed(true); } @@ -2448,9 +2570,12 @@ static void pform_set_reg_time(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + pform_range_t rng; + rng.first = new PENumber(new verinum(TIME_WIDTH-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_reg_time(list*names) @@ -2469,9 +2594,13 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin assert(cur); cur->set_signed(signed_flag); - cur->set_range(new PENumber(new verinum(width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + + pform_range_t rng; + rng.first = new PENumber(new verinum(width-1, integer_width)); + rng.second = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names) @@ -2484,6 +2613,47 @@ void pform_set_integer_2atom(uint64_t width, bool signed_flag, list delete names; } +/* + * This function detects the derived class for the given type and + * dispatches the type to the proper subtype function. + */ +void pform_set_data_type(const struct vlltype&li, data_type_t*data_type, list*names) +{ + if (atom2_type_t*atom2_type = dynamic_cast (data_type)) { + pform_set_integer_2atom(atom2_type->type_code, atom2_type->signed_flag, names); + return; + } + + if (struct_type_t*struct_type = dynamic_cast (data_type)) { + pform_set_struct_type(struct_type, names); + return; + } + + if (enum_type_t*enum_type = dynamic_cast (data_type)) { + pform_set_enum(li, enum_type, names); + return; + } + + if (vector_type_t*vec_type = dynamic_cast (data_type)) { + pform_set_net_range(names, vec_type->pdims.get(), + vec_type->signed_flag, + vec_type->base_type); + return; + } + + if (/*real_type_t*real_type =*/ dynamic_cast (data_type)) { + pform_set_net_range(names, 0, true, IVL_VT_REAL); + return; + } + + if (/*class_type_t*class_type =*/ dynamic_cast (data_type)) { + VLerror(li, "sorry: Class types not supported."); + return; + } + + assert(0); +} + static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, perm_string name) { @@ -2494,8 +2664,8 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, cur->set_signed(enum_type->signed_flag); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); - cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false); + assert(enum_type->range->size() == 1); + cur->set_range(*enum_type->range, SR_NET); cur->set_enumeration(enum_type); } @@ -2506,7 +2676,7 @@ void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, listbase_type==IVL_VT_LOGIC || enum_type->base_type==IVL_VT_BOOL); assert(enum_type->range.get() != 0); - assert(enum_type->range->size() == 2); + assert(enum_type->range->size() == 1); // Add the file and line information to the enumeration type. FILE_NAME(&(enum_type->li), li); diff --git a/pform.h b/pform.h index 030e37105..be4d744d8 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef __pform_H #define __pform_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -58,6 +58,7 @@ class PGate; class PExpr; class PSpecPath; +class PClass; struct vlltype; /* @@ -101,22 +102,23 @@ struct net_decl_assign_t { /* The lgate is gate instantiation information. */ struct lgate { - lgate(int =0) + inline lgate(int =0) : parms(0), parms_by_name(0), file(NULL), lineno(0) - { range[0] = 0; - range[1] = 0; - } + { } string name; list*parms; list*parms_by_name; - PExpr*range[2]; + pform_range_t range; const char* file; unsigned lineno; }; +extern std::list* make_range_from_width(uint64_t wid); +extern std::list* copy_range(std::list* orig); + /* Use this function to transform the parted form of the attribute list to the attribute map that is used later. */ extern void pform_bind_attributes(map&attributes, @@ -135,6 +137,8 @@ extern void pform_set_default_nettype(NetNet::Type net, */ extern PWire* pform_get_wire_in_scope(perm_string name); +extern PWire* pform_get_make_wire_in_scope(perm_string name, NetNet::Type net_type, NetNet::PortType port_type, ivl_variable_type_t vt_type); + /* * The parser uses startmodule and endmodule together to build up a * module as it parses it. The startmodule tells the pform code that a @@ -156,7 +160,7 @@ extern void pform_module_define_port(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t data_type, bool signed_flag, - list*range, + list*range, list*attr); extern Module::port_t* pform_module_port_reference(perm_string name, @@ -165,6 +169,10 @@ extern Module::port_t* pform_module_port_reference(perm_string name, extern void pform_endmodule(const char*, bool inside_celldefine, Module::UCDriveType uc_drive_def); +extern void pform_start_class_declaration(const struct vlltype&loc, + class_type_t*type); +extern void pform_end_class_declaration(void); + extern void pform_make_udp(perm_string name, list*parms, svector*decl, list*table, Statement*init, @@ -184,6 +192,7 @@ extern void pform_make_udp(perm_string name, */ extern void pform_pop_scope(); +extern PClass* pform_push_class_scope(const struct vlltype&loc, perm_string name); extern PTask*pform_push_task_scope(const struct vlltype&loc, char*name, bool is_auto); extern PFunction*pform_push_function_scope(const struct vlltype&loc, char*name, @@ -222,6 +231,8 @@ extern void pform_endgenerate(); */ extern PGenerate* pform_parent_generate(void); +extern void pform_set_typedef(perm_string name, data_type_t*data_type); + /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. @@ -234,7 +245,7 @@ extern void pform_makewire(const struct vlltype&li, perm_string name, /* This form handles simple declarations */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*names, NetNet::Type type, @@ -243,9 +254,15 @@ extern void pform_makewire(const struct vlltype&li, list*attr, PWSRType rt = SR_NET); +extern void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + list*names, + NetNet::PortType, + list*attr); + /* This form handles assignment declarations. */ extern void pform_makewire(const struct vlltype&li, - list*range, + list*range, bool signed_flag, list*delay, str_pair_t str, @@ -253,6 +270,13 @@ extern void pform_makewire(const struct vlltype&li, NetNet::Type type, ivl_variable_type_t); +/* This form handles nets declared as structures. (See pform_struct_type.cc) */ +extern void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType, + list*names, + list*attr); + extern void pform_make_reginit(const struct vlltype&li, perm_string name, PExpr*expr); @@ -261,25 +285,26 @@ extern void pform_make_reginit(const struct vlltype&li, it. The second form takes a single name. */ extern void pform_set_port_type(const struct vlltype&li, list*names, - list*range, + list*range, bool signed_flag, NetNet::PortType); -extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, - const char*file, unsigned lineno); extern void pform_set_net_range(list*names, - list*, + list*, bool signed_flag, - ivl_variable_type_t, - PWSRType rt = SR_NET); + ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); extern void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names); +extern void pform_set_data_type(const struct vlltype&li, data_type_t*, list*names); + extern void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, list*names); +extern void pform_set_struct_type(struct_type_t*struct_type, list*names); + /* pform_set_attrib and pform_set_type_attrib exist to support the $attribute syntax, which can only set string values to attributes. The functions keep the value strings that are @@ -297,13 +322,13 @@ extern void pform_set_parameter(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*range, PExpr*expr, LexicalScope::range_t*value_range); extern void pform_set_localparam(const struct vlltype&loc, perm_string name, ivl_variable_type_t type, bool signed_flag, - list*range, + list*range, PExpr*expr); extern void pform_set_defparam(const pform_name_t&name, PExpr*expr); @@ -363,15 +388,26 @@ extern void pform_make_pgassign_list(list*alist, /* Given a port type and a list of names, make a list of wires that can be used as task port information. */ -extern svector*pform_make_task_ports(NetNet::PortType pt, +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, ivl_variable_type_t vtype, bool signed_flag, - list*range, + list*range, list*names, - const char* file, - unsigned lineno, bool isint = false); +extern svector*pform_make_task_ports(const struct vlltype&loc, + NetNet::PortType pt, + data_type_t*vtype, + list*names); + +/* + * The parser uses this function to convert a unary + * increment/decrement expression to the equivalent compressed + * assignment statement. + */ +extern PAssign* pform_compressed_assign_from_inc_dec(const struct vlltype&loc, + PExpr*exp); /* * These are functions that the outside-the-parser code uses the do diff --git a/pform_dump.cc b/pform_dump.cc index cd8829ccf..f5859b69a 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 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 @@ -141,6 +141,11 @@ std::ostream& operator << (std::ostream&out, ivl_dis_domain_t dom) return out; } +void data_type_t::pform_dump(ostream&out, unsigned indent) const +{ + out << setw(indent) << "" << typeid(*this).name() << endl; +} + static void dump_attributes_map(ostream&out, const map&attributes, int ind) @@ -331,6 +336,9 @@ void PWire::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << " inout"; break; + case NetNet::PREF: + out << " ref"; + break; case NetNet::NOT_A_PORT: break; } @@ -346,17 +354,23 @@ void PWire::dump(ostream&out, unsigned ind) const } if (port_set_) { - if (port_msb_ == 0) { + if (port_.empty()) { out << " port"; } else { - out << " port[" << *port_msb_ << ":" << *port_lsb_ << "]"; + out << " port"; + for (list::const_iterator cur = port_.begin() + ; cur != port_.end() ; ++cur) + out << "[" << *cur->first << ":" << *cur->second << "]"; } } if (net_set_) { - if (net_msb_ == 0) { + if (net_.empty()) { out << " net"; } else { - out << " net[" << *net_msb_ << ":" << *net_lsb_ << "]"; + out << " net"; + for (list::const_iterator cur = net_.begin() + ; cur != net_.end() ; ++cur) + out << "[" << *cur->first << ":" << *cur->second << "]"; } } @@ -563,7 +577,10 @@ void PAssign::dump(ostream&out, unsigned ind) const if (delay_) out << "#" << *delay_ << " "; if (count_) out << "repeat(" << *count_ << ") "; if (event_) out << *event_ << " "; - out << *rval() << ";" << " /* " << get_fileline() << " */" << endl; + PExpr*rexpr = rval(); + if (rexpr) out << *rval() << ";"; + else out << ";"; + out << " /* " << get_fileline() << " */" << endl; } void PAssignNB::dump(ostream&out, unsigned ind) const @@ -763,8 +780,8 @@ void PForever::dump(ostream&out, unsigned ind) const void PForStatement::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "for (" << *name1_ << " = " << *expr1_ - << "; " << *cond_ << "; " << *name2_ << " = " << *expr2_ << - ")" << endl; + << "; " << *cond_ << "; )" << endl; + step_->dump(out, ind+6); statement_->dump(out, ind+3); } @@ -798,7 +815,13 @@ void PFunction::dump(ostream&out, unsigned ind) const out << "int unsigned "; break; case PTF_ATOM2_S: - cout << "int signed "; + out << "int signed "; + break; + case PTF_STRING: + out << "string "; + break; + case PTF_VOID: + out << "void "; break; } @@ -849,6 +872,10 @@ void PTask::dump(ostream&out, unsigned ind) const out << pscope_name() << ";" << endl; if (ports_) for (unsigned idx = 0 ; idx < ports_->count() ; idx += 1) { + if ((*ports_)[idx] == 0) { + out << setw(ind) << "" << "ERROR PORT" << endl; + continue; + } out << setw(ind) << ""; switch ((*ports_)[idx]->get_port_type()) { case NetNet::PINPUT: @@ -860,6 +887,12 @@ void PTask::dump(ostream&out, unsigned ind) const case NetNet::PINOUT: out << "inout "; break; + case NetNet::PIMPLICIT: + out << "PIMPLICIT"; + break; + case NetNet::NOT_A_PORT: + out << "NOT_A_PORT"; + break; default: assert(0); break; @@ -1050,6 +1083,15 @@ void PGenerate::dump(ostream&out, unsigned indent) const } } +void LexicalScope::dump_typedefs_(ostream&out, unsigned indent) const +{ + typedef map::const_iterator iter_t; + for (iter_t cur = typedefs.begin() ; cur != typedefs.end() ; ++ cur) { + out << setw(indent) << "" << "typedef of " << cur->first << ":" << endl; + cur->second->pform_dump(out, indent+4); + } +} + void LexicalScope::dump_parameters_(ostream&out, unsigned indent) const { typedef map::const_iterator parm_iter_t; @@ -1189,6 +1231,8 @@ void Module::dump(ostream&out) const out << ")" << endl; } + dump_typedefs_(out, 4); + dump_parameters_(out, 4); dump_localparams_(out, 4); diff --git a/pform_pclass.cc b/pform_pclass.cc new file mode 100644 index 000000000..935734a62 --- /dev/null +++ b/pform_pclass.cc @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2012 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 "pform.h" +# include "PClass.h" + +static PClass*pform_cur_class = 0; + +void pform_start_class_declaration(const struct vlltype&loc, class_type_t*type) +{ + PClass*class_scope = pform_push_class_scope(loc, type->name); + assert(pform_cur_class == 0); + pform_cur_class = class_scope; +} + +void pform_end_class_declaration(void) +{ + assert(pform_cur_class); + pform_cur_class = 0; + pform_pop_scope(); +} diff --git a/pform_struct_type.cc b/pform_struct_type.cc new file mode 100644 index 000000000..1fe44bbe8 --- /dev/null +++ b/pform_struct_type.cc @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011-2012 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 "pform.h" +# include "parse_misc.h" +# include "ivl_assert.h" + +static ivl_variable_type_t figure_struct_base_type(struct_type_t*struct_type) +{ + ivl_variable_type_t base_type = IVL_VT_BOOL; + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + struct_member_t*tmp = *cur; + + if (tmp->type == IVL_VT_BOOL) { + continue; + } + + if (tmp->type == IVL_VT_LOGIC) { + base_type = IVL_VT_LOGIC; + continue; + } + } + + return base_type; +} + +/* + * When we parse a packed struct, we can early on (right here) figure + * out the base type of the packed variable. Elaboration, later on, + * well figure out the rest. + */ +static void pform_set_packed_struct(struct_type_t*struct_type, perm_string name) +{ + ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + + PWire*net = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, base_type); + net->set_struct_type(struct_type); +} + +static void pform_set_struct_type(struct_type_t*struct_type, perm_string name) +{ + if (struct_type->packed_flag) { + pform_set_packed_struct(struct_type, name); + return; + } + + // For now, can only handle packed structs. + ivl_assert(*struct_type, 0); +} + +void pform_set_struct_type(struct_type_t*struct_type, list*names) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur) { + pform_set_struct_type(struct_type, *cur); + } +} + +static void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType ptype, + perm_string name, + list*) +{ + ivl_variable_type_t base_type = figure_struct_base_type(struct_type); + + PWire*cur = pform_get_make_wire_in_scope(name, NetNet::WIRE, ptype, base_type); + FILE_NAME(cur, li); + cur->set_struct_type(struct_type); +} + +void pform_makewire(const struct vlltype&li, + struct_type_t*struct_type, + NetNet::PortType ptype, + list*names, + list*attr) +{ + for (list::iterator cur = names->begin() + ; cur != names->end() ; ++ cur ) { + perm_string txt = *cur; + pform_makewire(li, struct_type, ptype, txt, attr); + } + + delete names; +} diff --git a/pform_types.cc b/pform_types.cc index 1f5787f27..9a85b5b7e 100644 --- a/pform_types.cc +++ b/pform_types.cc @@ -19,3 +19,7 @@ # include "pform_types.h" + +data_type_t::~data_type_t() +{ +} diff --git a/pform_types.h b/pform_types.h index 609641e1f..ed3f20f53 100644 --- a/pform_types.h +++ b/pform_types.h @@ -1,7 +1,7 @@ #ifndef __pform_types_H #define __pform_types_H /* - * Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2012 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 @@ -37,6 +37,7 @@ class PExpr; typedef named named_number_t; typedef named named_pexpr_t; +typedef std::pair pform_range_t; struct index_component_t { enum ctype_t { SEL_NONE, SEL_BIT, SEL_PART, SEL_IDX_UP, SEL_IDX_DO }; @@ -57,20 +58,76 @@ struct name_component_t { std::listindex; }; +struct decl_assignment_t { + perm_string name; + std::listindex; + std::auto_ptr expr; +}; + +/* + * This is the base class for data types that are matched by the + * "data_type" rule in the parse rule. We make the type virtual so + * that dynamic types will work. + */ +struct data_type_t : public LineInfo { + virtual ~data_type_t() = 0; + + // This method is used by the pform dumper to diagnostic dump. + virtual void pform_dump(std::ostream&out, unsigned indent) const; +}; + /* * The enum_type_t holds the parsed declaration to represent an * enumeration. Since this is in the pform, it represents the type * before elaboration to the range, for example, man not be complete * until it is elaborated in a scope. */ -struct enum_type_t { +struct enum_type_t : public data_type_t { ivl_variable_type_t base_type; bool signed_flag; - std::auto_ptr< list > range; + std::auto_ptr< list > range; std::auto_ptr< list > names; LineInfo li; }; +struct struct_member_t : public LineInfo { + ivl_variable_type_t type; + std::auto_ptr< list > range; + std::auto_ptr< list > names; +}; + +struct struct_type_t : public data_type_t { + bool packed_flag; + std::auto_ptr< list > members; +}; + +struct atom2_type_t : public data_type_t { + inline explicit atom2_type_t(int tc, bool flag) + : type_code(tc), signed_flag(flag) { } + int type_code; + bool signed_flag; +}; + +struct vector_type_t : public data_type_t { + inline explicit vector_type_t(ivl_variable_type_t bt, bool sf, + std::list*pd) + : base_type(bt), signed_flag(sf), pdims(pd) { } + ivl_variable_type_t base_type; + bool signed_flag; + std::auto_ptr< list > pdims; +}; + +struct real_type_t : public data_type_t { + inline explicit real_type_t(int tc) : type_code(tc) { } + int type_code; +}; + +struct class_type_t : public data_type_t { + inline explicit class_type_t(perm_string n) + : name(n) { } + + perm_string name; +}; /* * The pform_name_t is the general form for a hierarchical diff --git a/scripts/devel-stub.conf b/scripts/devel-stub.conf index 01009dc3d..5982f4988 100644 --- a/scripts/devel-stub.conf +++ b/scripts/devel-stub.conf @@ -20,6 +20,7 @@ debug:elaborate debug:elab_pexpr debug:scopes debug:synth2 +debug:optimizer out:a.out ivlpp:./ivlpp/ivlpp -D__ICARUS__ -L -Pfoo.pp sys_func:scripts/devel-stub.sft diff --git a/synth.cc b/synth.cc index 98d992098..0617bae76 100644 --- a/synth.cc +++ b/synth.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -114,12 +114,12 @@ class synth_f : public functor_t { public: synth_f() { top_ = NULL; } - void process(class Design*, class NetProcTop*); + void process(Design*, NetProcTop*); private: - void proc_always_(class Design*); - void proc_initial_(class Design*); - void proc_final_(class Design*); + void proc_always_(Design*); + void proc_initial_(Design*); + void proc_final_(Design*); NetProcTop*top_; }; @@ -129,7 +129,7 @@ class synth_f : public functor_t { * Look at a process, and divide the problem into always and initial * threads. */ -void synth_f::process(class Design*des, class NetProcTop*top) +void synth_f::process(Design*des, NetProcTop*top) { top_ = top; switch (top->type()) { @@ -145,19 +145,19 @@ void synth_f::process(class Design*des, class NetProcTop*top) } } -void synth_f::proc_always_(class Design*des) +void synth_f::proc_always_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } -void synth_f::proc_initial_(class Design*des) +void synth_f::proc_initial_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); } -void synth_f::proc_final_(class Design*des) +void synth_f::proc_final_(Design*des) { do_expr expr_pat(des, top_->scope()); top_->statement()->match_proc(&expr_pat); diff --git a/synth2.cc b/synth2.cc index 3a4b5367c..9adc21f5d 100644 --- a/synth2.cc +++ b/synth2.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2012 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 @@ -900,7 +900,7 @@ bool NetProcTop::synth_sync(Design*des) class synth2_f : public functor_t { public: - void process(class Design*, class NetProcTop*); + void process(Design*, NetProcTop*); private: }; @@ -910,7 +910,7 @@ class synth2_f : public functor_t { * Look at a process. If it is asynchronous, then synthesize it as an * asynchronous process and delete the process itself for its gates. */ -void synth2_f::process(class Design*des, class NetProcTop*top) +void synth2_f::process(Design*des, NetProcTop*top) { if (top->attribute(perm_string::literal("ivl_synthesis_off")).as_ulong() != 0) return; diff --git a/t-dll-api.cc b/t-dll-api.cc index b45da977e..008847127 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -2147,15 +2147,39 @@ extern "C" ivl_nexus_t ivl_signal_nex(ivl_signal_t net, unsigned word) } } +extern "C" unsigned ivl_signal_packed_dimensions(ivl_signal_t net) +{ + return net->packed_dims.size(); +} + +extern "C" int ivl_signal_packed_msb(ivl_signal_t net, unsigned dim) +{ + assert(dim < net->packed_dims.size()); + return net->packed_dims[dim].msb; +} + +extern "C" int ivl_signal_packed_lsb(ivl_signal_t net, unsigned dim) +{ + assert(dim < net->packed_dims.size()); + return net->packed_dims[dim].lsb; +} + extern "C" int ivl_signal_msb(ivl_signal_t net) { - assert(net->lsb_dist == 1 || net->lsb_dist == -1); - return net->lsb_index + net->lsb_dist * (net->width_ - 1); + if (net->packed_dims.size() == 0) + return 0; + + assert(net->packed_dims.size() == 1); + return net->packed_dims[0].msb; } extern "C" int ivl_signal_lsb(ivl_signal_t net) { - return net->lsb_index; + if (net->packed_dims.size() == 0) + return 0; + + assert(net->packed_dims.size() == 1); + return net->packed_dims[0].lsb; } extern "C" ivl_scope_t ivl_signal_scope(ivl_signal_t net) diff --git a/t-dll.cc b/t-dll.cc index 7ac03ae15..e6b44c75f 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-2012 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 @@ -963,7 +963,7 @@ bool dll_target::tran(const NetTran*net) { struct ivl_switch_s*obj = new struct ivl_switch_s; obj->type = net->type(); - obj->width = 0; + obj->width = net->vector_width(); obj->part = 0; obj->offset = 0; obj->name = net->name(); @@ -996,7 +996,6 @@ bool dll_target::tran(const NetTran*net) } if (obj->type == IVL_SW_TRAN_VP) { - obj->width = net->vector_width(); obj->part = net->part_width(); obj->offset= net->part_offset(); } @@ -2400,10 +2399,17 @@ void dll_target::signal(const NetNet*net) /* Save the primitive properties of the signal in the ivl_signal_t object. */ + { size_t idx = 0; + list::const_iterator cur; + obj->packed_dims.resize(net->packed_dims().size()); + for (cur = net->packed_dims().begin(), idx = 0 + ; cur != net->packed_dims().end() ; ++cur, idx += 1) { + obj->packed_dims[idx] = *cur; + } + } + obj->width_ = net->vector_width(); obj->signed_= net->get_signed()? 1 : 0; - obj->lsb_index = net->lsb(); - obj->lsb_dist = net->msb() >= net->lsb() ? 1 : -1; obj->isint_ = false; obj->local_ = net->local_flag()? 1 : 0; obj->forced_net_ = (net->type() != NetNet::REG) && @@ -2504,7 +2510,7 @@ void dll_target::signal(const NetNet*net) obj->array_words = net->array_count(); obj->array_addr_swapped = net->array_addr_swapped() ? 1 : 0; - assert(obj->array_words == net->pin_count()); + ivl_assert(*net, obj->array_words == net->pin_count()); if (debug_optimizer && obj->array_words > 1000) cerr << "debug: " "t-dll creating nexus array " << obj->array_words << " long" << endl; if (obj->array_words > 1 && net->pins_are_virtual()) { diff --git a/t-dll.h b/t-dll.h index 62f2df303..2bdae36bb 100644 --- a/t-dll.h +++ b/t-dll.h @@ -688,10 +688,9 @@ struct ivl_signal_s { unsigned array_dimensions_ : 1; unsigned array_addr_swapped : 1; - /* These encode the run-time index for the least significant - bit, and the distance to the second bit. */ - signed lsb_index; - signed lsb_dist; + /* These encode the declared packed dimensions for the + signal, in case they are needed by the run-time */ + std::vector packed_dims; perm_string name_; ivl_scope_t scope_; diff --git a/tgt-fpga/Makefile.in b/tgt-fpga/Makefile.in index db72580a6..7aa2e1f14 100644 --- a/tgt-fpga/Makefile.in +++ b/tgt-fpga/Makefile.in @@ -65,7 +65,7 @@ cppcheck: $(O:.o=.c) cppcheck --enable=all -f $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status - cd ..; ./config.status --file=tgt-fpga$@ + cd ..; ./config.status --file=tgt-fpga/$@ dep: mkdir dep @@ -83,7 +83,7 @@ else endif fpga.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) iverilog-fpga.ps: $(srcdir)/iverilog-fpga.man man -t $(srcdir)/iverilog-fpga.man > iverilog-fpga.ps diff --git a/tgt-null/Makefile.in b/tgt-null/Makefile.in index c3b2d6f85..8a354ef97 100644 --- a/tgt-null/Makefile.in +++ b/tgt-null/Makefile.in @@ -78,7 +78,7 @@ else endif null.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/null.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/null.conf $(libdir)/ivl$(suffix)/null-s.conf diff --git a/tgt-pal/Makefile.in b/tgt-pal/Makefile.in index 31f3ce7f3..7ae034a09 100644 --- a/tgt-pal/Makefile.in +++ b/tgt-pal/Makefile.in @@ -77,7 +77,7 @@ else endif pal.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal + $(CC) @shared@ $(LDFLAGS)-o $@ $O $(TGTLDFLAGS) $(LDFLAGS) -lipal install: all installdirs $(libdir)/ivl/pal.tgt diff --git a/tgt-pcb/Makefile.in b/tgt-pcb/Makefile.in index 652d7ab80..efa3949fb 100644 --- a/tgt-pcb/Makefile.in +++ b/tgt-pcb/Makefile.in @@ -58,8 +58,9 @@ clean: distclean: clean rm -f Makefile config.log + rm -f stamp-pcb_config-h pcb_config.h -cppcheck: $(O:.o=.c) +cppcheck: $(O:.o=.cc) cppcheck --enable=all -f $(INCLUDE_PATH) $^ Makefile: $(srcdir)/Makefile.in ../config.status @@ -68,9 +69,10 @@ Makefile: $(srcdir)/Makefile.in ../config.status dep: mkdir dep -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o - mv $*.d dep +stamp-pcb_config-h: $(srcdir)/pcb_config.h.in ../config.status + @rm -f $@ + cd ..; ./config.status --header=tgt-pcb/pcb_config.h +pcb_config.h: stamp-pcb_config-h %.o: %.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) @DEPENDENCY_FLAG@ -c $< -o $*.o @@ -92,7 +94,7 @@ else endif pcb.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CXX) @shared@ -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/pcb.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/pcb.conf $(libdir)/ivl$(suffix)/pcb-s.conf diff --git a/tgt-pcb/pcb.cc b/tgt-pcb/pcb.cc index 8d72eba02..da895dc2f 100644 --- a/tgt-pcb/pcb.cc +++ b/tgt-pcb/pcb.cc @@ -24,7 +24,9 @@ # include "version_base.h" # include "version_tag.h" # include "pcb_config.h" -# include +# include +# include +# include # include "pcb_priv.h" # include "ivl_target.h" diff --git a/tgt-pcb/pcb_priv.h b/tgt-pcb/pcb_priv.h index ef47c57ee..3dab1b9cd 100644 --- a/tgt-pcb/pcb_priv.h +++ b/tgt-pcb/pcb_priv.h @@ -23,7 +23,7 @@ # include # include # include -# include +# include "ivl_target.h" extern int scan_scope(ivl_scope_t scope); diff --git a/tgt-pcb/scope.cc b/tgt-pcb/scope.cc index 545945abd..a5ed9ec62 100644 --- a/tgt-pcb/scope.cc +++ b/tgt-pcb/scope.cc @@ -21,6 +21,7 @@ # include # include # include +# include using namespace std; @@ -85,7 +86,7 @@ int scan_scope(ivl_scope_t scope) return 0; } -static int child_scan_fun(ivl_scope_t scope, void*) +extern "C" int child_scan_fun(ivl_scope_t scope, void*) { int rc = scan_scope(scope); return 0; diff --git a/tgt-pcb/show_netlist.cc b/tgt-pcb/show_netlist.cc index a2a5d6be2..992be0c5e 100644 --- a/tgt-pcb/show_netlist.cc +++ b/tgt-pcb/show_netlist.cc @@ -18,6 +18,7 @@ */ # include "pcb_priv.h" +# include # include using namespace std; diff --git a/tgt-pcb/show_pcb.cc b/tgt-pcb/show_pcb.cc index 163691640..2a0d7a52c 100644 --- a/tgt-pcb/show_pcb.cc +++ b/tgt-pcb/show_pcb.cc @@ -19,6 +19,8 @@ # include "pcb_config.h" # include "pcb_priv.h" +# include +# include using namespace std; diff --git a/tgt-stub/Makefile.in b/tgt-stub/Makefile.in index a1fa69549..b9df1d927 100644 --- a/tgt-stub/Makefile.in +++ b/tgt-stub/Makefile.in @@ -79,7 +79,7 @@ else endif stub.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/stub.tgt \ $(libdir)/ivl$(suffix)/stub.conf $(libdir)/ivl$(suffix)/stub-s.conf diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 24fd5bdb4..3cddd2ab6 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -1288,11 +1288,14 @@ static void show_signal(ivl_signal_t net) for (idx = 0 ; idx < ivl_signal_array_count(net) ; idx += 1) { ivl_nexus_t nex = ivl_signal_nex(net, idx); + unsigned dim; - fprintf(out, " %s %s %s%s[%d:%d] %s[word=%u, adr=%d] " - " ", - type, sign, port, data_type, - ivl_signal_msb(net), ivl_signal_lsb(net), + fprintf(out, " %s %s %s%s", type, sign, port, data_type); + for (dim = 0 ; dim < ivl_signal_packed_dimensions(net) ; dim += 1) { + fprintf(out, "[%d:%d]", ivl_signal_packed_msb(net,dim), + ivl_signal_packed_lsb(net,dim)); + } + fprintf(out, " %s[word=%u, adr=%d] ", ivl_signal_basename(net), idx, ivl_signal_array_base(net)+idx, ivl_signal_width(net), diff --git a/tgt-verilog/Makefile.in b/tgt-verilog/Makefile.in index 60f692780..b1ba3d771 100644 --- a/tgt-verilog/Makefile.in +++ b/tgt-verilog/Makefile.in @@ -77,7 +77,7 @@ else endif verilog.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl/verilog.tgt \ $(includedir)/vpi_user.h diff --git a/tgt-vhdl/Makefile.in b/tgt-vhdl/Makefile.in index 553edceab..8487fc1ab 100644 --- a/tgt-vhdl/Makefile.in +++ b/tgt-vhdl/Makefile.in @@ -82,7 +82,7 @@ else endif vhdl.tgt: $O $(TGTDEPLIBS) - $(CXX) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CXX) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) stamp-vhdl_config-h: $(srcdir)/vhdl_config.h.in ../config.status @rm -f $@ diff --git a/tgt-vhdl/cast.cc b/tgt-vhdl/cast.cc index f54dacf94..11dd34eb5 100644 --- a/tgt-vhdl/cast.cc +++ b/tgt-vhdl/cast.cc @@ -1,7 +1,7 @@ /* * Generate code to convert between VHDL types. * - * Copyright (C) 2008-2009 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -219,6 +219,7 @@ vhdl_expr *vhdl_expr::to_std_ulogic() } else assert(false); + return NULL; } /* diff --git a/tgt-vhdl/vhdl_helper.hh b/tgt-vhdl/vhdl_helper.hh index 814c5369d..d801f190b 100644 --- a/tgt-vhdl/vhdl_helper.hh +++ b/tgt-vhdl/vhdl_helper.hh @@ -1,7 +1,7 @@ /* * Helper functions for VHDL syntax elements. * - * Copyright (C) 2008-2010 Nick Gasson (nick@nickg.me.uk) + * Copyright (C) 2008-2012 Nick Gasson (nick@nickg.me.uk) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -64,6 +64,7 @@ static inline char vl_to_vhdl_bit(char bit) return '-'; } assert(false); + return 0; } #endif diff --git a/tgt-vlog95/Makefile.in b/tgt-vlog95/Makefile.in index cfe1b5973..2c95d9e55 100644 --- a/tgt-vlog95/Makefile.in +++ b/tgt-vlog95/Makefile.in @@ -78,7 +78,7 @@ else endif vlog95.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) install: all installdirs $(libdir)/ivl$(suffix)/vlog95.tgt $(INSTALL_DOC) $(libdir)/ivl$(suffix)/vlog95.conf $(libdir)/ivl$(suffix)/vlog95-s.conf diff --git a/tgt-vlog95/event.c b/tgt-vlog95/event.c index 8454a3727..5af509168 100644 --- a/tgt-vlog95/event.c +++ b/tgt-vlog95/event.c @@ -36,7 +36,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) for (idx = 0; idx < count; idx += 1) { if (first) first = 0; else fprintf(vlog_out, " or "); - emit_name_of_nexus(scope, ivl_event_any(event, idx)); + emit_nexus_as_ca(scope, ivl_event_any(event, idx), 0); } /* Check for positive edge events. */ @@ -46,7 +46,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) if (first) first = 0; else fprintf(vlog_out, " or "); fprintf(vlog_out, "posedge "); - emit_name_of_nexus(scope, ivl_event_pos(event, idx)); + emit_nexus_as_ca(scope, ivl_event_pos(event, idx), 0); } /* Check for negative edge events. */ @@ -56,7 +56,7 @@ void emit_event(ivl_scope_t scope, ivl_statement_t stmt) if (first) first = 0; else fprintf(vlog_out, " or "); fprintf(vlog_out, "negedge "); - emit_name_of_nexus(scope, ivl_event_neg(event, idx)); + emit_nexus_as_ca(scope, ivl_event_neg(event, idx), 0); } /* We have a named event if there were no edge events. */ diff --git a/tgt-vlog95/expr.c b/tgt-vlog95/expr.c index f1c22f531..3d32ca023 100644 --- a/tgt-vlog95/expr.c +++ b/tgt-vlog95/expr.c @@ -79,7 +79,7 @@ static void emit_expr_array(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { char *oper = ""; - switch(ivl_expr_opcode(expr)) { + switch (ivl_expr_opcode(expr)) { case '+': oper = "+"; break; case '-': oper = "-"; break; case '*': oper = "*"; break; @@ -108,7 +108,7 @@ static void emit_expr_binary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) } fprintf(vlog_out, "("); - switch(ivl_expr_opcode(expr)) { + switch (ivl_expr_opcode(expr)) { case '%': if (ivl_expr_value(expr) == IVL_VT_REAL) { fprintf(stderr, "%s:%u: vlog95 error: Real modulus operator " @@ -427,6 +427,18 @@ static void emit_expr_select(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) } else { // HERE: Should this sign extend if the expression is signed? emit_expr(scope, sig_expr, wid); + /* Select part of a signal when needed. */ + if ((ivl_expr_type(sig_expr) == IVL_EX_SIGNAL) && + (ivl_expr_width(expr) < ivl_expr_width(sig_expr))) { + ivl_signal_t sig = ivl_expr_signal(sig_expr); + int msb = ivl_signal_msb(sig); + int lsb = ivl_signal_lsb(sig); + int64_t value = lsb; + unsigned e_wid = ivl_expr_width(expr) - 1; + if (msb >= lsb) value += e_wid; + else value -= e_wid; + fprintf(vlog_out, "[%"PRId64":%u]", value, lsb); + } } } @@ -508,6 +520,46 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) /* A cast is a noop. */ emit_expr(scope, ivl_expr_oper1(expr), wid); break; + case 'I': + fprintf(vlog_out, "(++"); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'i': + fprintf(vlog_out, "("); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, "++)"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-increment " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'D': + fprintf(vlog_out, "(--"); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, ")"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; + case 'd': + fprintf(vlog_out, "("); + emit_expr(scope, ivl_expr_oper1(expr), wid); + fprintf(vlog_out, "--)"); + fprintf(stderr, "%s:%u: vlog95 sorry: Pre-decrement " + "operator is not currently translated.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; default: fprintf(vlog_out, ""); emit_expr(scope, ivl_expr_oper1(expr), wid); @@ -516,13 +568,14 @@ static void emit_expr_unary(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) ivl_expr_file(expr), ivl_expr_lineno(expr), ivl_expr_opcode(expr)); + vlog_errors += 1; break; } } void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) { - switch(ivl_expr_type(expr)) { + switch (ivl_expr_type(expr)) { case IVL_EX_ARRAY: emit_expr_array(scope, expr, wid); break; @@ -535,6 +588,14 @@ void emit_expr(ivl_scope_t scope, ivl_expr_t expr, unsigned wid) case IVL_EX_DELAY: emit_expr_delay(scope, expr, wid); break; + case IVL_EX_ENUMTYPE: + fprintf(vlog_out, ""); + fprintf(stderr, "%s:%u: vlog95 error: Enum expressions " + "are not supported.\n", + ivl_expr_file(expr), + ivl_expr_lineno(expr)); + vlog_errors += 1; + break; case IVL_EX_EVENT: emit_expr_event(scope, expr, wid); break; diff --git a/tgt-vlog95/logic_lpm.c b/tgt-vlog95/logic_lpm.c index 2ce8ba45a..4a57e6616 100644 --- a/tgt-vlog95/logic_lpm.c +++ b/tgt-vlog95/logic_lpm.c @@ -157,23 +157,33 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t rise, ivl_expr_t fall, static unsigned is_local_nexus(ivl_scope_t scope, ivl_nexus_t nex) { unsigned idx, count = ivl_nexus_ptrs(nex); - unsigned is_local = 0; + unsigned is_local = 1; + unsigned has_output_driver = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); if (! sig) continue; + /* Check to see if there is an output port driving into + * the local scope. */ + if ((scope == ivl_scope_parent(ivl_signal_scope(sig))) && + (ivl_signal_port(sig) == IVL_SIP_OUTPUT)) { + has_output_driver = 1; + continue; + } if (scope != ivl_signal_scope(sig)) continue; if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; if (ivl_signal_local(sig)) { -// assert(! is_local); is_local = 1; } else { is_local = 0; break; } } - return is_local; + /* We return is_local=true only if there is not an output driving + * into this scope. This is needed since some module outputs are + * combined with a concatenation. */ + return is_local && !has_output_driver; } /* @@ -252,10 +262,30 @@ static void emit_nexus_port_signal(ivl_scope_t scope, ivl_nexus_t nex) } } /* There will not be a signal for an empty port. */ - if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0), 0); else fprintf(vlog_out, "/* Empty */"); } +static ivl_signal_t find_local_signal(ivl_scope_t scope, ivl_nexus_t nex, + unsigned *word) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + ivl_signal_t sig = 0; + *word = 0; + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (!t_sig) continue; + if (ivl_signal_local(t_sig) && + (ivl_signal_port(t_sig) != IVL_SIP_INPUT)) continue; + if (ivl_signal_scope(t_sig) != scope) continue; + assert(! sig); + sig = t_sig; + *word = ivl_nexus_ptr_pin(nex_ptr); + } + return sig; +} + /* * Emit the input port driving expression. */ @@ -264,13 +294,15 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) unsigned idx, count = ivl_nexus_ptrs(nex); ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + unsigned word = 0; + /* Look for the nexus driver. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; @@ -282,29 +314,46 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); - net_logic = t_net_logic; + if (t_nlogic) { + assert(! nlogic); + nlogic = t_nlogic; } if (t_sig) { assert(! sig); sig = t_sig; + word = ivl_nexus_ptr_pin(nex_ptr); } } + /* An LPM is driving the nexus. */ if (lpm) { assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); - emit_lpm_as_ca(scope, lpm); + /* If there is a signal in this scope that is also driven by + * the LPM then use the signal instead. */ + sig = find_local_signal(scope, ivl_lpm_q(lpm), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_lpm_as_ca(scope, lpm); + /* A constant is driving the nexus. */ } else if (net_const) { - assert( !net_logic); + assert( !nlogic); assert(! sig); - emit_const_nexus(scope, net_const); - } else if (net_logic) { + /* If there is a signal in this scope that is also driven by + * the constant then use the signal instead. */ + sig = find_local_signal(scope, ivl_const_nex(net_const), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_const_nexus(scope, net_const); + /* A logic gate is driving the nexus. */ + } else if (nlogic) { assert(! sig); - emit_logic_as_ca(scope, net_logic); + /* If there is a signal in this scope that is also driven by + * the logic then use the signal instead. */ + sig = find_local_signal(scope, ivl_logic_pin(nlogic, 0), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_logic_as_ca(scope, nlogic); + /* A signal is driving the nexus. */ } else if (sig) { - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); /* If there is no driver then look for a single signal that is * driven by this nexus that has the correct scope. This is needed * to translate top level ports. */ @@ -313,7 +362,7 @@ void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex) } } -void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) +void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD) { /* If there is no nexus then there is nothing to print. */ if (! nex) return; @@ -324,13 +373,14 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) unsigned out_of_scope_drive = 0; ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + unsigned word = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) { @@ -352,23 +402,32 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); - net_logic = t_net_logic; + if (t_nlogic) { + assert(! nlogic); + nlogic = t_nlogic; } if (t_sig) { assert(! sig); sig = t_sig; + word = ivl_nexus_ptr_pin(nex_ptr); } } if (lpm) { assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); assert(! must_be_sig); +// HERE: I think we need special input code like the following. +#if 0 + /* If these is a signal in this scope that is also driven by + * the LPM then use the signal instead. */ + sig = find_local_signal(scope, ivl_lpm_q(lpm), &word); + if (sig) emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + else emit_lpm_as_ca(scope, lpm); +#endif emit_lpm_as_ca(scope, lpm); } else if (net_const) { - assert( !net_logic); + assert( !nlogic); assert(! sig); assert(! must_be_sig); if (out_of_scope_drive) { @@ -380,14 +439,15 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) // For now report this as missing. fprintf(vlog_out, ""); } else emit_const_nexus(scope, net_const); - } else if (net_logic) { + } else if (nlogic) { assert(! sig); assert(! must_be_sig); - emit_logic_as_ca(scope, net_logic); + emit_logic_as_ca(scope, nlogic); } else if (sig) { +// HERE: should these be allow_UD? if (must_be_sig) { - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); - } else emit_name_of_nexus(scope, nex); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, word), 0); + } else emit_name_of_nexus(scope, nex, 0); // HERE: The assert causes pr1703959 to fail. // } else assert(0); } else { @@ -397,7 +457,7 @@ void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex) fprintf(vlog_out, ""); } } else { - emit_name_of_nexus(scope, nex); + emit_name_of_nexus(scope, nex, allow_UD); } } @@ -408,61 +468,61 @@ static void emit_logic_as_ca(ivl_scope_t scope, ivl_net_logic_t nlogic) case IVL_LO_AND: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " & "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_BUF: -// case IVL_LO_BUFT: + case IVL_LO_BUFT: case IVL_LO_BUFZ: assert(inputs == 1); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); break; case IVL_LO_NAND: assert(inputs == 2); fprintf(vlog_out, "~("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " & "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_NOR: assert(inputs == 2); fprintf(vlog_out, "~("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_NOT: assert(inputs == 1); fprintf(vlog_out, "(~ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LO_OR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_XNOR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " ~^ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; case IVL_LO_XOR: assert(inputs == 2); fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, " ^ "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 2), 0); fprintf(vlog_out, ")"); break; default: @@ -482,7 +542,7 @@ static void emit_lpm_array(ivl_scope_t scope, ivl_lpm_t lpm) emit_id(ivl_signal_basename(sig)); fprintf(vlog_out, "["); // HERE: Need to remove the scale to match array base instead of adding it back. - emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0); fprintf(vlog_out, " + %d]", ivl_signal_array_base(sig)); } @@ -500,56 +560,92 @@ static void emit_lpm_concat(ivl_scope_t scope, ivl_lpm_t lpm) /* If all the nexus match then we have a repeat. */ if ((idx == count) && (count > 1)) { fprintf(vlog_out, "%u{", count); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, "}"); + /* Icarus uses a concat to combine the output from multiple devices + * into a single vector, because of this we need to also look for + * the nexus driver outside the scope. emit_nexus_as_ca( , , 1) */ } else { for (idx = count-1; idx > 0; idx -= 1) { - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx), 1); fprintf(vlog_out, ", "); } - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1); } fprintf(vlog_out, "}"); } +/* + * Look for an output signal in the nexus that is driving into this scope. + */ +static ivl_signal_t find_output_signal(ivl_scope_t scope, ivl_nexus_t nex, + unsigned*array_word) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + /* The signal must not be a driver. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || + (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; + /* The signal must be an output. */ + if (ivl_signal_port(t_sig) != IVL_SIP_OUTPUT) continue; + /* The signal must be driving into this scope. */ + if (ivl_scope_parent(ivl_signal_scope(t_sig)) == scope) { + return t_sig; + } + } + return 0; +} + static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, - int*base, int*array_word) + int*base, unsigned*array_word) { unsigned idx, count = ivl_nexus_ptrs(nex); ivl_lpm_t lpm = 0; ivl_net_const_t net_const = 0; - ivl_net_logic_t net_logic = 0; + ivl_net_logic_t nlogic = 0; ivl_signal_t sig = 0; + /* Look for a signal in the local scope first. */ + sig = find_local_signal(scope, nex, array_word); + if (sig) return sig; + /* Now look for an output signal driving into the local scope. */ + sig = find_output_signal(scope, nex, array_word); + if (sig) return sig; + /* Now scan the nexus looking for a driver. */ for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); - if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && - (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; ivl_lpm_t t_lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t t_net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t t_net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t t_nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ)) continue; if (t_lpm) { assert(! lpm); /* The real signal could be hidden behind a select. */ if (ivl_lpm_type(t_lpm) == IVL_LPM_PART_VP) { t_sig = nexus_is_signal(scope, ivl_lpm_data(t_lpm, 0), base, array_word); - if (t_sig) *base += ivl_lpm_base(t_lpm); - } else lpm = t_lpm; + } + + if (t_sig) *base += ivl_lpm_base(t_lpm); + else lpm = t_lpm; } if (t_net_const) { assert(! net_const); net_const = t_net_const; } - if (t_net_logic) { - assert(! net_logic); + if (t_nlogic) { + assert(! nlogic); /* The real signal could be hidden behind a BUFZ gate. */ - if (ivl_logic_type(t_net_logic) == IVL_LO_BUFZ) { - assert(ivl_logic_pins(t_net_logic) == 2); + if (ivl_logic_type(t_nlogic) == IVL_LO_BUFZ) { + assert(ivl_logic_pins(t_nlogic) == 2); t_sig = nexus_is_signal(scope, - ivl_logic_pin(t_net_logic, 1), + ivl_logic_pin(t_nlogic, 1), base, array_word); - } else net_logic = t_net_logic; + } else nlogic = t_nlogic; } if (t_sig) { assert(! sig); @@ -558,18 +654,13 @@ static ivl_signal_t nexus_is_signal(ivl_scope_t scope, ivl_nexus_t nex, *array_word = ivl_nexus_ptr_pin(nex_ptr); } } - if (sig) { - assert(! lpm); - assert(! net_const); - assert(! net_logic); - } return sig; } static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) { unsigned width = ivl_lpm_width(lpm); - int array_word = 0; + unsigned array_word = 0; int base = ivl_lpm_base(lpm); int msb, lsb; ivl_signal_t sig = nexus_is_signal(scope, ivl_lpm_data(lpm, 0), @@ -587,7 +678,7 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) /* Check if the compiler used a select for a shift. */ assert(base >= 0); if (base) fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); if (base) { fprintf(vlog_out, " "); if (sign_extend) fprintf(vlog_out, ">"); @@ -598,6 +689,7 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) } if (sign_extend) fprintf(vlog_out, "("); + emit_scope_call_path(scope, ivl_signal_scope(sig)); emit_id(ivl_signal_basename(sig)); if (ivl_signal_dimensions(sig)) { array_word += ivl_signal_array_base(sig); @@ -615,13 +707,13 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) return; } - fprintf(vlog_out, "["); if (width == 1) { ivl_nexus_t sel = ivl_lpm_data(lpm, 1); if (sel) { + fprintf(vlog_out, "["); // HERE: Need to scale the select nexus. if ((msb >= lsb) && (lsb == 0)) { - emit_nexus_as_ca(scope, sel); + emit_nexus_as_ca(scope, sel, 0); } else { fprintf(stderr, "%s:%u: vlog95 sorry: Non-zero based " "variable part selects are not " @@ -631,11 +723,15 @@ static void emit_lpm_part_select(ivl_scope_t scope, ivl_lpm_t lpm) fprintf(vlog_out, ""); } } else { + /* Skip a select of the entire bit. */ + if ((msb == lsb) && (lsb == base)) return; + fprintf(vlog_out, "["); if (msb >= lsb) base += lsb; else base = lsb - base; fprintf(vlog_out, "%d", base); } } else { + fprintf(vlog_out, "["); // HERE: No support for an indexed part select. ivl_nexus_t sel = ivl_lpm_data(lpm, 1); if (sel) { @@ -666,10 +762,10 @@ static void emit_lpm_func(ivl_scope_t scope, ivl_lpm_t lpm) count -= 1; fprintf(vlog_out, "("); for (idx = 0; idx < count; idx += 1) { - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, idx), 0); fprintf(vlog_out, ", "); } - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, count)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, count), 0); fprintf(vlog_out, ")"); } } @@ -679,9 +775,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) switch (ivl_lpm_type(lpm)) { case IVL_LPM_ADD: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " + "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_ARRAY: @@ -690,48 +786,48 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) case IVL_LPM_CAST_INT: case IVL_LPM_CAST_INT2: case IVL_LPM_CAST_REAL: - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); break; case IVL_LPM_CMP_EEQ: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " === "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_EQ: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " == "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " >= "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_GT: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " > "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " != "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CMP_NEE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " !== "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_CONCAT: @@ -739,9 +835,9 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) break; case IVL_LPM_DIVIDE: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " / "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MOD: @@ -753,66 +849,66 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) vlog_errors += 1; } fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " %% "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MULT: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " * "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_MUX: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_select(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_select(lpm), 0); fprintf(vlog_out, " ? "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, " : "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_PART_PV: - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 1); break; case IVL_LPM_PART_VP: emit_lpm_part_select(scope, lpm); break; case IVL_LPM_RE_AND: fprintf(vlog_out, "(&"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NAND: fprintf(vlog_out, "(~&"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_NOR: fprintf(vlog_out, "(~|"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_OR: fprintf(vlog_out, "(|"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XOR: fprintf(vlog_out, "(^"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_RE_XNOR: fprintf(vlog_out, "(~^"); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_REPEAT: fprintf(vlog_out, "{%u{", ivl_lpm_size(lpm)); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, "}}"); break; case IVL_LPM_SFUNC: @@ -821,30 +917,30 @@ static void emit_lpm_as_ca(ivl_scope_t scope, ivl_lpm_t lpm) break; case IVL_LPM_SHIFTL: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " << "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_SHIFTR: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " "); assert(! sign_extend); fprintf(vlog_out, " >> "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_SIGN_EXT: // assert(! sign_extend); sign_extend = 1; - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); break; case IVL_LPM_SUB: fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 0), 0); fprintf(vlog_out, " - "); - emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1)); + emit_nexus_as_ca(scope, ivl_lpm_data(lpm, 1), 0); fprintf(vlog_out, ")"); break; case IVL_LPM_UFUNC: @@ -980,29 +1076,29 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) } fprintf(vlog_out, " ("); /* Emit the q pin. */ - emit_name_of_nexus(scope, ivl_lpm_q(lpm)); + emit_name_of_nexus(scope, ivl_lpm_q(lpm), 0); fprintf(vlog_out, ", "); /* Emit the clock pin. */ - emit_nexus_as_ca(scope, ivl_lpm_clk(lpm)); + emit_nexus_as_ca(scope, ivl_lpm_clk(lpm), 0); fprintf(vlog_out, ", "); /* Emit the enable pin expression(s) if needed. */ emitted = 0; nex = ivl_lpm_enable(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } nex = ivl_lpm_sync_clr(lpm); if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } have_sset = 0; nex = ivl_lpm_sync_set(lpm); if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; have_sset = 1; } @@ -1012,37 +1108,37 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) have_data = ivl_lpm_data(lpm, 0) != 0; nex = ivl_lpm_sync_clr(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data | have_sset) fprintf(vlog_out, " & "); if (have_data & have_sset) fprintf(vlog_out, "("); } nex = ivl_lpm_sync_set(lpm); if (nex) { if (! sset_bits || (sset_bits && (sset_bits[0] == '1'))) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data) fprintf(vlog_out, " | "); } else { fprintf(vlog_out, "~"); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); if (have_data) fprintf(vlog_out, " & "); } } nex = ivl_lpm_data(lpm, 0); - if (nex) emit_nexus_as_ca(scope, nex); + if (nex) emit_nexus_as_ca(scope, nex, 0); if (have_data & have_sset) fprintf(vlog_out, ")"); fprintf(vlog_out, ", "); /* Emit the clear pin expression(s) if needed. */ emitted = 0; nex = ivl_lpm_async_clr(lpm); if (nex) { - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } nex = ivl_lpm_async_set(lpm); if (aset_bits && (aset_bits[0] != '0')) nex = 0; if (nex) { if (emitted) fprintf(vlog_out, " | "); - emit_nexus_as_ca(scope, nex); + emit_nexus_as_ca(scope, nex, 0); emitted = 1; } if (!emitted) fprintf(vlog_out, "1'b0"); @@ -1050,7 +1146,7 @@ static void emit_lpm_ff(ivl_scope_t scope, ivl_lpm_t lpm) /* Emit the set pin expression(s) if needed. */ nex = ivl_lpm_async_set(lpm); if (aset_bits && (aset_bits[0] != '1')) nex = 0; - if (nex) emit_nexus_as_ca(scope, nex); + if (nex) emit_nexus_as_ca(scope, nex, 0); else fprintf(vlog_out, "1'b0"); fprintf(vlog_out, ");\n"); /* We need to emit a primitive for this instance. */ @@ -1145,6 +1241,31 @@ static void emit_lpm_part_pv(ivl_scope_t scope, ivl_lpm_t lpm) fprintf(vlog_out, "]"); } +unsigned output_is_module_instantiation_input(ivl_scope_t scope, + ivl_nexus_t nex) +{ + unsigned idx, count = ivl_nexus_ptrs(nex); + unsigned rtn = 0; + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + /* Skip drivers. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) != IVL_DR_HiZ) || + (ivl_nexus_ptr_drive0(nex_ptr) != IVL_DR_HiZ)) continue; + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + /* If the nexus is driving other things or signals that are + * not a module instantiation input then return false. */ +// HERE: debug this to see if the output can drive other things local to the +// module that is being called. +// if (! t_sig) return 0; + if (! t_sig) continue; + if (ivl_signal_port(t_sig) != IVL_SIP_INPUT) return 0; + if (ivl_scope_parent(ivl_signal_scope(t_sig)) != scope) return 0; + if (rtn) return 0; + rtn = 1; + } + return rtn; +} + void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) { ivl_nexus_t output = get_lpm_output(scope, lpm); @@ -1156,6 +1277,9 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) emit_lpm_ff(scope, lpm); return; } +// HERE: Look for a select passed to a pull device (pr2019553). + /* Skip assignments to a module instantiation input. */ + if (output_is_module_instantiation_input(scope, output)) return; fprintf(vlog_out, "%*cassign", indent, ' '); emit_lpm_strength(lpm); emit_delay(scope, @@ -1165,7 +1289,7 @@ void emit_lpm(ivl_scope_t scope, ivl_lpm_t lpm) 3); fprintf(vlog_out, " "); if (type == IVL_LPM_PART_PV) emit_lpm_part_pv(scope, lpm); - else emit_name_of_nexus(scope, output); + else emit_name_of_nexus(scope, output, 0); fprintf(vlog_out, " = "); emit_lpm_as_ca(scope, lpm); fprintf(vlog_out, ";"); @@ -1200,9 +1324,9 @@ static void emit_bufz(ivl_scope_t scope, ivl_net_logic_t nlogic) ivl_logic_delay(nlogic, 2), 3); fprintf(vlog_out, " "); - emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0)); + emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0), 0); fprintf(vlog_out, " = "); - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, 1), 0); fprintf(vlog_out, ";"); emit_logic_file_line(nlogic); fprintf(vlog_out, "\n"); @@ -1219,7 +1343,7 @@ static void emit_name_of_logic_nexus(ivl_scope_t scope, ivl_net_logic_t nlogic, ivl_nexus_t nex) { if (nex) { - emit_name_of_nexus(scope, nex); + emit_name_of_nexus(scope, nex, 0); } else { if (ivl_logic_type(nlogic) != IVL_LO_UDP) { fprintf(stderr, "%s:%u: vlog95 warning: Missing logic pin " @@ -1242,7 +1366,6 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) // short circuit. Verify input count. unsigned idx, count, dly_count, strength_type = 2; unsigned outputs = 1; - unsigned width = ivl_logic_width(nlogic); const char *name; /* Skip gates that have a local nexus as the output since they are * part of a continuous assignment. */ @@ -1262,7 +1385,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) ivl_logic_delay(nlogic, 2), 3); fprintf(vlog_out, " "); - emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0)); + emit_name_of_nexus(scope, ivl_logic_pin(nlogic, 0), 0); fprintf(vlog_out, " = "); emit_logic_as_ca(scope, nlogic); fprintf(vlog_out, ";"); @@ -1390,6 +1513,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) if (name && *name) { char *fixed_name = strdup(name); unsigned lp = strlen(name) - 1; + unsigned width = ivl_logic_width(nlogic); if (fixed_name[lp] == '>') { while (fixed_name[lp] != '<') { assert(lp > 0); @@ -1413,11 +1537,11 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) fprintf(vlog_out, ", "); } for (/* None */; idx < count; idx += 1) { - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx), 0); fprintf(vlog_out, ", "); } if (strength_type == 2) { - emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx)); + emit_nexus_as_ca(scope, ivl_logic_pin(nlogic, idx), 0); } else { /* A pull gate only has a single output connection. */ assert(count == 0); @@ -1431,6 +1555,7 @@ void emit_logic(ivl_scope_t scope, ivl_net_logic_t nlogic) void emit_tran(ivl_scope_t scope, ivl_switch_t tran) { unsigned dly_count, pins; + const char *name; fprintf(vlog_out, "%*c", indent, ' '); switch (ivl_switch_type(tran)) { case IVL_SW_RTRAN: @@ -1482,14 +1607,32 @@ void emit_tran(ivl_scope_t scope, ivl_switch_t tran) dly_count); assert(pins == 2 || pins == 3); // The same problem here as for the gates above. -// fprintf(vlog_out, " %s(", ivl_switch_basename(tran)); + name = ivl_switch_basename(tran); + if (name && *name) { + char *fixed_name = strdup(name); + unsigned lp = strlen(name) - 1; + unsigned width = ivl_switch_width(tran); + if (fixed_name[lp] == '>') { + while (fixed_name[lp] != '<') { + assert(lp > 0); + lp -= 1; + } + fixed_name[lp] = 0; + } + fprintf(vlog_out, " "); + emit_id(fixed_name); + free(fixed_name); + if (width > 1) { + fprintf(vlog_out, " [%u:0]", width-1); + } + } fprintf(vlog_out, " ("); - emit_name_of_nexus(scope, ivl_switch_a(tran)); + emit_name_of_nexus(scope, ivl_switch_a(tran), 0); fprintf(vlog_out, ", "); - emit_name_of_nexus(scope, ivl_switch_b(tran)); + emit_name_of_nexus(scope, ivl_switch_b(tran), 0); if (pins == 3) { fprintf(vlog_out, ", "); - emit_nexus_as_ca(scope, ivl_switch_enable(tran)); + emit_nexus_as_ca(scope, ivl_switch_enable(tran), 0); } fprintf(vlog_out, ");"); if (emit_file_line) { @@ -1561,14 +1704,16 @@ static void dump_drive(ivl_drive_t drive) */ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) { - unsigned idx, count = ivl_nexus_ptrs(nex); - fprintf(stderr, "Dumping nexus from scope: %s\n", + unsigned idx, count; + if ((scope == 0) || (nex == 0)) return; + count = ivl_nexus_ptrs(nex); + fprintf(stderr, "Dumping nexus %p from scope: %s\n", nex, ivl_scope_name(scope)); for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_lpm_t lpm = ivl_nexus_ptr_lpm(nex_ptr); ivl_net_const_t net_const = ivl_nexus_ptr_con(nex_ptr); - ivl_net_logic_t net_logic = ivl_nexus_ptr_log(nex_ptr); + ivl_net_logic_t nlogic = ivl_nexus_ptr_log(nex_ptr); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); fprintf(stderr, " %u (", idx); dump_drive(ivl_nexus_ptr_drive1(nex_ptr)); @@ -1578,12 +1723,12 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) if (lpm) { ivl_scope_t lpm_scope = ivl_lpm_scope(lpm); assert(! net_const); - assert(! net_logic); + assert(! nlogic); assert(! sig); fprintf(stderr, "LPM: "); - fprintf(stderr, "%s:%d ", ivl_lpm_file(lpm), + fprintf(stderr, "{%s:%d} ", ivl_lpm_file(lpm), ivl_lpm_lineno(lpm)); - if (scope != lpm_scope) fprintf(stderr, "%s ", + if (scope != lpm_scope) fprintf(stderr, "(%s) ", ivl_scope_name(lpm_scope)); switch (ivl_lpm_type(lpm)) { case IVL_LPM_ABS: fprintf(stderr, "abs"); break; @@ -1604,7 +1749,9 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_LPM_MOD: fprintf(stderr, "mod"); break; case IVL_LPM_MULT: fprintf(stderr, "mult"); break; case IVL_LPM_MUX: fprintf(stderr, "mux"); break; - case IVL_LPM_PART_VP: fprintf(stderr, "part-VP"); break; + case IVL_LPM_PART_VP: fprintf(stderr, "part-VP"); + fprintf(stderr, "(%u+%u)", ivl_lpm_base(lpm), + ivl_lpm_width(lpm)); break; case IVL_LPM_PART_PV: fprintf(stderr, "part-PV"); break; case IVL_LPM_POW: fprintf(stderr, "pow"); break; case IVL_LPM_RE_AND: fprintf(stderr, "R-AND"); break; @@ -1620,22 +1767,69 @@ void dump_nexus_information(ivl_scope_t scope, ivl_nexus_t nex) case IVL_LPM_SIGN_EXT: fprintf(stderr, "sign"); break; case IVL_LPM_SUB: fprintf(stderr, "sub"); break; case IVL_LPM_UFUNC: fprintf(stderr, "U-func"); break; + default: fprintf(stderr, "<%d>", ivl_lpm_type(lpm)); } } else if (net_const) { - assert(! net_logic); + ivl_scope_t const_scope = ivl_const_scope(net_const); + assert(! nlogic); assert(! sig); fprintf(stderr, "Const: "); - } else if (net_logic) { + if (scope != const_scope) fprintf(stderr, "(%s) ", + ivl_scope_name(const_scope)); + } else if (nlogic) { + ivl_scope_t logic_scope = ivl_logic_scope(nlogic); assert(! sig); fprintf(stderr, "Logic: "); + fprintf(stderr, "{%s:%d} ", ivl_logic_file(nlogic), + ivl_logic_lineno(nlogic)); + if (scope != logic_scope) fprintf(stderr, "(%s) ", + ivl_scope_name(logic_scope)); + switch (ivl_logic_type(nlogic)) { + case IVL_LO_AND: fprintf(stderr, "and"); break; + case IVL_LO_BUF: fprintf(stderr, "buf"); break; + case IVL_LO_BUFIF0: fprintf(stderr, "bufif0"); break; + case IVL_LO_BUFIF1: fprintf(stderr, "bufif1"); break; + case IVL_LO_BUFT: fprintf(stderr, "buft"); break; + case IVL_LO_BUFZ: fprintf(stderr, "bufz"); break; + case IVL_LO_CMOS: fprintf(stderr, "cmos"); break; + case IVL_LO_NAND: fprintf(stderr, "nand"); break; + case IVL_LO_NMOS: fprintf(stderr, "nmos"); break; + case IVL_LO_NOR: fprintf(stderr, "nor"); break; + case IVL_LO_NOT: fprintf(stderr, "not"); break; + case IVL_LO_NOTIF0: fprintf(stderr, "notif0"); break; + case IVL_LO_NOTIF1: fprintf(stderr, "notif1"); break; + case IVL_LO_OR: fprintf(stderr, "or"); break; + case IVL_LO_PMOS: fprintf(stderr, "pmos"); break; + case IVL_LO_PULLDOWN: fprintf(stderr, "pulldown"); break; + case IVL_LO_PULLUP: fprintf(stderr, "pullup"); break; + case IVL_LO_RCMOS: fprintf(stderr, "rcmos"); break; + case IVL_LO_RNMOS: fprintf(stderr, "rnmos"); break; + case IVL_LO_RPMOS: fprintf(stderr, "rpmos"); break; + case IVL_LO_UDP: { + ivl_udp_t udp = ivl_logic_udp(nlogic); + assert(udp); + fprintf(stderr, "UDP %s", ivl_udp_name(udp)); + break; + } + case IVL_LO_XNOR: fprintf(stderr, "xnor"); break; + case IVL_LO_XOR: fprintf(stderr, "xor"); break; + default: fprintf(stderr, "<%d>", ivl_logic_type(nlogic)); + } + fprintf(stderr, "(%u inputs)", ivl_logic_pins(nlogic) - 1); } else if (sig) { ivl_scope_t sig_scope = ivl_signal_scope(sig); - fprintf(stderr, "Signal: "); + fprintf(stderr, "Signal: \""); if (scope != sig_scope) fprintf(stderr, "%s.", ivl_scope_name(sig_scope)); fprintf(stderr, "%s", ivl_signal_basename(sig)); + if (ivl_signal_dimensions(sig) > 0) { + fprintf(stderr, "[]"); + } + fprintf(stderr, "\""); // HERE: Do we need to add support for an array word or is that an LPM. - if (ivl_signal_local(sig)) fprintf(stderr, " (local)"); + if (ivl_signal_local(sig)) fprintf(stderr, " {local}"); + else fprintf(stderr, " {%s:%d}", ivl_signal_file(sig), + ivl_signal_lineno(sig)); switch (ivl_signal_port(sig)) { case IVL_SIP_INPUT: fprintf(stderr, " input"); break; case IVL_SIP_OUTPUT: fprintf(stderr, " output"); break; diff --git a/tgt-vlog95/misc.c b/tgt-vlog95/misc.c index e23294770..492f88f68 100644 --- a/tgt-vlog95/misc.c +++ b/tgt-vlog95/misc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -70,7 +70,7 @@ static void emit_delay(ivl_scope_t scope, ivl_expr_t expr, unsigned is_stmt) ivl_signal_t sig = ivl_expr_signal(expr); if (ivl_signal_local(sig)) { assert(! is_stmt); - emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0)); + emit_nexus_as_ca(scope, ivl_signal_nex(sig, 0), 0); return; } } @@ -412,9 +412,8 @@ static unsigned find_signal_in_nexus(ivl_scope_t scope, ivl_nexus_t nex) unsigned is_driver = 0; unsigned is_array = 0; int64_t array_idx = 0; - unsigned idx, count; + unsigned idx, count = ivl_nexus_ptrs(nex); - count = ivl_nexus_ptrs(nex); for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t sig = ivl_nexus_ptr_sig(nex_ptr); @@ -501,9 +500,11 @@ static void emit_number_as_string(ivl_net_const_t net_const) /* Skip any NULL bytes. */ if (val == 0) continue; - /* Print some values that must be escapped. */ + /* Print some values that can be escaped. */ if (val == '"') fprintf(vlog_out, "\\\""); else if (val == '\\') fprintf(vlog_out, "\\\\"); + else if (val == '\n') fprintf(vlog_out, "\\n"); + else if (val == '\t') fprintf(vlog_out, "\\t"); /* Print the printable characters. */ else if (isprint((int)val)) fprintf(vlog_out, "%c", val); /* Print the non-printable characters as an octal escape. */ @@ -616,8 +617,84 @@ static unsigned find_const_nexus(ivl_scope_t scope, ivl_nexus_t nex) return 0; } +static unsigned find_driving_signal(ivl_scope_t scope, ivl_nexus_t nex) +{ + ivl_signal_t sig = 0; + unsigned is_array = 0; + int64_t array_idx = 0; + unsigned idx, count = ivl_nexus_ptrs(nex); + + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + if (ivl_signal_local(t_sig)) continue; + /* An output can be used if it is driven by this nexus. */ + if ((ivl_nexus_ptr_drive1(nex_ptr) == IVL_DR_HiZ) && + (ivl_nexus_ptr_drive0(nex_ptr) == IVL_DR_HiZ) && + (ivl_signal_port(t_sig) != IVL_SIP_OUTPUT)) { + continue; + } + /* We have a signal that can be used to find the name. */ + if (sig) { +// HERE: Which one should we use? For now it's the first one found. +// I believe this needs to be solved (see above). + fprintf(stderr, "%s:%u: vlog95 warning: Duplicate name (%s", + ivl_signal_file(t_sig), ivl_signal_lineno(t_sig), + ivl_signal_basename(t_sig)); + if (ivl_signal_dimensions(t_sig) > 0) { + int64_t tmp_idx = ivl_nexus_ptr_pin(nex_ptr); + tmp_idx += ivl_signal_array_base(t_sig); + fprintf(stderr, "[%"PRId64"]", tmp_idx); + } + fprintf(stderr, ") found for nexus (%s", + ivl_signal_basename(sig)); + if (is_array) fprintf(stderr, "[%"PRId64"]", array_idx); + fprintf(stderr, ")\n"); + } else { + sig = t_sig; + if (ivl_signal_dimensions(sig) > 0) { + is_array = 1; + array_idx = ivl_nexus_ptr_pin(nex_ptr); + array_idx += ivl_signal_array_base(sig); + } + } + } + + if (sig) { + emit_scope_call_path(scope, ivl_signal_scope(sig)); + emit_id(ivl_signal_basename(sig)); + if (is_array) fprintf(vlog_out, "[%"PRId64"]", array_idx); + return 1; + } + + return 0; +} + +static unsigned is_local_input(ivl_scope_t scope, ivl_nexus_t nex) +{ + ivl_signal_t sig = 0; + unsigned idx, count = ivl_nexus_ptrs(nex); + + for (idx = 0; idx < count; idx += 1) { + ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); + ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); + if (! t_sig) continue; + if (! ivl_signal_local(t_sig)) continue; + if (ivl_signal_port(t_sig) != IVL_SIP_INPUT) continue; + assert(! sig); + assert(ivl_signal_dimensions(t_sig) == 0); + sig = t_sig; + } + if (sig) { + fprintf(vlog_out, "ivlog%s", ivl_signal_basename(sig)); + return 1; + } + return 0; +} + // HERE: Does this work correctly with an array reference created from @*? -void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) +void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, unsigned allow_UD) { ivl_scope_t mod_scope; /* First look in the local scope for the nexus name. */ @@ -630,9 +707,16 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) if (find_signal_in_nexus(mod_scope, nex)) return; } + /* Look to see if this is a up/down reference. */ + if (allow_UD && find_driving_signal(scope, nex)) return; + /* If there is no signals driving this then look for a constant. */ if (find_const_nexus(scope, nex)) return; + /* Module inputs that are split (arg[7:4], arg[3:0]) need to use + * the local signal names. */ + if (is_local_input(scope, nex)) return; + // HERE: Need to check arr[var]? Can this be rebuilt? // Then look for down scopes and then any scope. For all this warn if // multiples are found in a given scope. This all needs to be before @@ -641,7 +725,7 @@ void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex) /* It is possible that the nexus does not have a name. For this * case do not print an actual name. */ fprintf(vlog_out, "/* Empty */"); - dump_nexus_information(scope, nex); +// dump_nexus_information(scope, nex); } /* @@ -758,6 +842,10 @@ static unsigned is_escaped(const char *id) return 1; } } + /* Any Verilog keyword should also be escaped. */ +// HERE: Create a keyword.gperf file to do this check. + if ((strcmp(id, "input") == 0) || + (strcmp(id, "output") == 0) ) return 1; /* We looked at all the digits, so this is a normal id. */ return 0; } diff --git a/tgt-vlog95/numbers.c b/tgt-vlog95/numbers.c index 2dd1bc1af..e81b4e0a1 100644 --- a/tgt-vlog95/numbers.c +++ b/tgt-vlog95/numbers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -61,6 +61,8 @@ static int32_t get_int32_from_bits(const char *bits, unsigned nbits, } } /* Sign extend as needed. */ +// HERE: Need to emit 1 instead of -1 for some of the constants. +// if (is_signed && (nbits > 1) && (msb == '1') && (trim_wid < 32U)) { if (is_signed && (msb == '1') && (trim_wid < 32U)) { value |= ~(((int32_t)1 << trim_wid) - (int32_t)1); } @@ -315,6 +317,17 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type) ivl_expr_signed(expr), result_type); } +/* + * Routine to remove two characters starting at the given address. + */ +static void remove_two_chars(char* str) +{ + for (; str[2]; str += 1) { + str[0] = str[2]; + } + str[0] = 0; +} + /* * Routine to print a string value as a string after removing any leading * escaped NULL bytes. @@ -322,12 +335,42 @@ int32_t get_int32_from_number(ivl_expr_t expr, int *result_type) void emit_string(const char* string) { char *buffer = strdup(string); - char *cptr = buffer; + char *bptr = buffer; + char *cptr; fprintf(vlog_out, "\""); /* Prune any leading escaped NULL bytes. */ - while ((cptr[0] == '\\') && (cptr[1] == '0') && - (cptr[2] == '0') && (cptr[3] == '0')) cptr += 4; - if (*cptr) fprintf(vlog_out, "%s", cptr); + while ((bptr[0] == '\\') && (bptr[1] == '0') && + (bptr[2] == '0') && (bptr[3] == '0')) bptr += 4; + for (cptr = bptr; *cptr; cptr += 1) { + if (*cptr == '\\') { + /* Replace any \011 with \t */ + if ((cptr[1] == '0') && (cptr[2] == '1') && + (cptr[3] == '1')) { + cptr[1] = 't'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \012 with \n */ + } else if ((cptr[1] == '0') && (cptr[2] == '1') && + (cptr[3] == '2')) { + cptr[1] = 'n'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \042 with \" */ + } else if ((cptr[1] == '0') && (cptr[2] == '4') && + (cptr[3] == '2')) { + cptr[1] = '"'; + remove_two_chars(cptr+2); + cptr += 1; + /* Replace any \134 with \\ */ + } else if ((cptr[1] == '1') && (cptr[2] == '3') && + (cptr[3] == '4')) { + cptr[1] = '\\'; + remove_two_chars(cptr+2); + cptr += 1; + } else cptr += 3; + } + } + if (*bptr) fprintf(vlog_out, "%s", bptr); free(buffer); fprintf(vlog_out, "\""); } diff --git a/tgt-vlog95/scope.c b/tgt-vlog95/scope.c index 767281111..a3bc6b34e 100644 --- a/tgt-vlog95/scope.c +++ b/tgt-vlog95/scope.c @@ -204,7 +204,7 @@ void emit_net_def(ivl_scope_t scope, ivl_signal_t sig) ivl_signal_lineno(sig), ivl_signal_basename(sig)); vlog_errors += 1; } else { - switch(ivl_signal_type(sig)) { + switch (ivl_signal_type(sig)) { case IVL_SIT_TRI: case IVL_SIT_UWIRE: // HERE: Need to add support for supply nets. Probably supply strength @@ -363,19 +363,21 @@ static void emit_module_ports(ivl_scope_t scope) if (count == 0) return; fprintf(vlog_out, "("); - emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0)); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, 0), 0); for (idx = 1; idx < count; idx += 1) { fprintf(vlog_out, ", "); - emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx)); + emit_nexus_as_ca(scope, ivl_scope_mod_port(scope, idx), 0); } fprintf(vlog_out, ")"); } -static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex) +static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex, + unsigned *word) { assert(nex); unsigned idx, count = ivl_nexus_ptrs(nex); ivl_signal_t sig = 0; + *word = 0; for (idx = 0; idx < count; idx += 1) { ivl_nexus_ptr_t nex_ptr = ivl_nexus_ptr(nex, idx); ivl_signal_t t_sig = ivl_nexus_ptr_sig(nex_ptr); @@ -383,6 +385,7 @@ static ivl_signal_t get_port_from_nexus(ivl_scope_t scope, ivl_nexus_t nex) if (ivl_signal_scope(t_sig) != scope) continue; assert(! sig); sig = t_sig; + *word = ivl_nexus_ptr_pin(nex_ptr); } } return sig; @@ -475,7 +478,12 @@ static void emit_port(ivl_signal_t port) } emit_sig_type(port); fprintf(vlog_out, " "); - emit_id(ivl_signal_basename(port)); + /* Split port (arg[7:4],arg[3:0]) are generated using local signals. */ + if (ivl_signal_local(port)) { + fprintf(vlog_out, "ivlog%s", ivl_signal_basename(port)); + } else { + emit_id(ivl_signal_basename(port)); + } fprintf(vlog_out, ";"); emit_sig_file_line(port); fprintf(vlog_out, "\n"); @@ -483,10 +491,11 @@ static void emit_port(ivl_signal_t port) static void emit_module_port_defs(ivl_scope_t scope) { - unsigned idx, count = ivl_scope_ports(scope); + unsigned word, idx, count = ivl_scope_ports(scope); for (idx = 0; idx < count; idx += 1) { ivl_nexus_t nex = ivl_scope_mod_port(scope, idx); - ivl_signal_t port = get_port_from_nexus(scope, nex); + ivl_signal_t port = get_port_from_nexus(scope, nex, &word); +// HERE: Do we need to use word? if (port) emit_port(port); else { fprintf(vlog_out, ""); @@ -502,15 +511,17 @@ static void emit_module_port_defs(ivl_scope_t scope) static void emit_module_call_expr(ivl_scope_t scope, unsigned idx) { + unsigned word; ivl_nexus_t nex = ivl_scope_mod_port(scope, idx); - ivl_signal_t port = get_port_from_nexus(scope, nex); + ivl_signal_t port = get_port_from_nexus(scope, nex, &word); /* For an input port we need to emit the driving expression. */ if (ivl_signal_port(port) == IVL_SIP_INPUT) { emit_nexus_port_driver_as_ca(ivl_scope_parent(scope), - ivl_signal_nex(port, 0)); + ivl_signal_nex(port, word)); /* For an output we need to emit the signal the output is driving. */ } else { - emit_nexus_as_ca(ivl_scope_parent(scope), ivl_signal_nex(port, 0)); + emit_nexus_as_ca(ivl_scope_parent(scope), + ivl_signal_nex(port, word), 0); } } @@ -536,6 +547,70 @@ static void emit_task_func_port_defs(ivl_scope_t scope) if (count) fprintf(vlog_out, "\n"); } +/* + * Look at all the processes to see if we can find one with the expected + * scope. If we don't find one then we can assume the block only has + * variable definitions and needs to be emitted here in the scope code. + */ +static int no_stmts_in_process(ivl_process_t proc, ivl_scope_t scope) +{ + ivl_statement_t stmt = ivl_process_stmt(proc); + switch (ivl_statement_type(stmt)) { + case IVL_ST_BLOCK: + case IVL_ST_FORK: + if (ivl_stmt_block_scope(stmt) == scope) return 1; + default: /* Do nothing. */ ; + } + return 0; +} + +/* + * If a named block has no statements then we may need to emit it here if + * there are variable definitions in the scope. We translate all this to + * an initial and named begin since that is enough to hold the variables. + */ +static void emit_named_block_scope(ivl_scope_t scope) +{ + unsigned idx, count = ivl_scope_events(scope); + unsigned named_ev = 0; + + /* If there are no parameters, signals or named events then skip + * this block. */ + for (idx = 0; idx < count; idx += 1) { + ivl_event_t event = ivl_scope_event(scope, idx); + /* If this event has any type of edge sensitivity then it is + * not a named event. */ + if (ivl_event_nany(event)) continue; + if (ivl_event_npos(event)) continue; + if (ivl_event_nneg(event)) continue; + named_ev = 1; + break; + } + if ((ivl_scope_params(scope) == 0) && (ivl_scope_sigs(scope) == 0) && + (named_ev == 0)) return; + /* Currently we only need to emit a named block for the variables + * if the parent scope is a module. This gets much more complicated + * if this is not true. */ + if (ivl_scope_type(ivl_scope_parent(scope)) != IVL_SCT_MODULE) return; + /* Scan all the processes looking for one that matches this scope. + * If a match is found then this named block was already emitted by + * the process code. */ + if (ivl_design_process(design, (ivl_process_f)no_stmts_in_process, + scope)) return; + /* A match was not found so emit the named block here to get the + * variable definitions. */ + fprintf(vlog_out, "\n%*cinitial begin: ", indent, ' '); + emit_id(ivl_scope_tname(scope)); + emit_scope_file_line(scope); + fprintf(vlog_out, "\n"); + indent += indent_incr; + emit_scope_variables(scope); + indent -= indent_incr; + fprintf(vlog_out, "%*cend /* ", indent, ' '); + emit_id(ivl_scope_tname(scope)); + fprintf(vlog_out, " */\n"); +} + /* * This search method may be slow for a large structural design with a * large number of gate types. That's not what this converter was built @@ -652,6 +727,7 @@ int emit_scope(ivl_scope_t scope, ivl_scope_t parent) case IVL_SCT_BEGIN: case IVL_SCT_FORK: assert(indent != 0); + emit_named_block_scope(scope); return 0; /* A named begin/fork is handled in line. */ default: fprintf(stderr, "%s:%u: vlog95 error: Unsupported scope type " diff --git a/tgt-vlog95/stmt.c b/tgt-vlog95/stmt.c index 96eac0654..31ee451a5 100644 --- a/tgt-vlog95/stmt.c +++ b/tgt-vlog95/stmt.c @@ -780,7 +780,7 @@ static void emit_stmt_case(ivl_scope_t scope, ivl_statement_t stmt) { char *case_type; unsigned idx, default_case, count = ivl_stmt_case_count(stmt); - switch(ivl_statement_type(stmt)) { + switch (ivl_statement_type(stmt)) { case IVL_ST_CASE: case IVL_ST_CASER: case_type = "case"; @@ -1047,7 +1047,7 @@ static void emit_stmt_while(ivl_scope_t scope, ivl_statement_t stmt) void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) { - switch(ivl_statement_type(stmt)) { + switch (ivl_statement_type(stmt)) { case IVL_ST_NOOP: /* If this is a statement termination then just finish the * statement, otherwise print an empty begin/end pair. */ @@ -1159,7 +1159,8 @@ void emit_stmt(ivl_scope_t scope, ivl_statement_t stmt) void emit_process(ivl_scope_t scope, ivl_process_t proc) { - ivl_statement_t stmt; + ivl_statement_t stmt = ivl_process_stmt(proc); + if (ivl_statement_type(stmt) == IVL_ST_NOOP) return; fprintf(vlog_out, "\n%*c", get_indent(), ' '); switch (ivl_process_type(proc)) { case IVL_PR_INITIAL: @@ -1181,7 +1182,6 @@ void emit_process(ivl_scope_t scope, ivl_process_t proc) ivl_process_file(proc), ivl_process_lineno(proc)); } - stmt = ivl_process_stmt(proc); if (ivl_statement_type(stmt) == IVL_ST_NOOP) { fprintf(vlog_out, " begin\n%*cend\n", get_indent(), ' '); } else { diff --git a/tgt-vlog95/udp.c b/tgt-vlog95/udp.c index 34feb356d..b33fe0752 100644 --- a/tgt-vlog95/udp.c +++ b/tgt-vlog95/udp.c @@ -25,7 +25,7 @@ static void emit_entry(ivl_udp_t udp, char entry, unsigned *rerun) { const char *value = 0; - switch(entry) { + switch (entry) { case '0': value = " 0 "; break; diff --git a/tgt-vlog95/vlog95.c b/tgt-vlog95/vlog95.c index 0266529a2..be00636f5 100644 --- a/tgt-vlog95/vlog95.c +++ b/tgt-vlog95/vlog95.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -30,7 +30,7 @@ static const char*version_string = "Icarus Verilog VLOG95 Code Generator " VERSION " (" VERSION_TAG ")\n\n" -"Copyright (C) 2010-2011 Cary R. (cygcary@yahoo.com)\n\n" +"Copyright (C) 2010-2012 Cary R. (cygcary@yahoo.com)\n\n" " This program is free software; you can redistribute it and/or modify\n" " it under the terms of the GNU General Public License as published by\n" " the Free Software Foundation; either version 2 of the License, or\n" @@ -195,6 +195,10 @@ int target_design(ivl_design_t des) fclose(vlog_out); + /* A do nothing call to prevent warnings about this routine not + * being used. */ + dump_nexus_information(0, 0); + return vlog_errors; } diff --git a/tgt-vlog95/vlog95_priv.h b/tgt-vlog95/vlog95_priv.h index 492057491..12ce11cc0 100644 --- a/tgt-vlog95/vlog95_priv.h +++ b/tgt-vlog95/vlog95_priv.h @@ -85,8 +85,10 @@ extern void emit_scope_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_scope_variables(ivl_scope_t scope); extern void emit_scope_call_path(ivl_scope_t scope, ivl_scope_t call_scope); extern void emit_scope_module_path(ivl_scope_t scope, ivl_scope_t call_scope); -extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex); -extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex); +extern void emit_name_of_nexus(ivl_scope_t scope, ivl_nexus_t nex, + unsigned allow_UD); +extern void emit_nexus_as_ca(ivl_scope_t scope, ivl_nexus_t nex, + unsigned allow_UD); extern void emit_nexus_port_driver_as_ca(ivl_scope_t scope, ivl_nexus_t nex); extern void emit_const_nexus(ivl_scope_t scope, ivl_net_const_t const_net); extern void emit_signal_net_const_as_ca(ivl_scope_t scope, ivl_signal_t sig); diff --git a/tgt-vvp/Makefile.in b/tgt-vvp/Makefile.in index 4438c8c62..9edeb32ec 100644 --- a/tgt-vvp/Makefile.in +++ b/tgt-vvp/Makefile.in @@ -85,7 +85,7 @@ else endif vvp.tgt: $O $(TGTDEPLIBS) - $(CC) @shared@ -o $@ $O $(TGTLDFLAGS) + $(CC) @shared@ $(LDFLAGS) -o $@ $O $(TGTLDFLAGS) vvp.conf: $(srcdir)/vvp.conf.in Makefile echo 'flag:VVP_EXECUTABLE=$(bindir)/vvp$(suffix)' | cat $(srcdir)/vvp.conf.in - > vvp.conf diff --git a/tgt-vvp/draw_switch.c b/tgt-vvp/draw_switch.c index d62ae102c..59d60614b 100644 --- a/tgt-vvp/draw_switch.c +++ b/tgt-vvp/draw_switch.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2010,2012 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 @@ -38,7 +38,6 @@ void draw_switch_in_scope(ivl_switch_t sw) ivl_expr_t fall_exp = ivl_switch_delay(sw, 1); ivl_expr_t decay_exp= ivl_switch_delay(sw, 2); - /* We do not support tran delays. */ if ((rise_exp || fall_exp || decay_exp) && (!number_is_immediate(rise_exp, 64, 0) || number_is_unknown(rise_exp) || @@ -76,15 +75,16 @@ void draw_switch_in_scope(ivl_switch_t sw) processing doesn't have to deal with it. */ const char*raw = draw_net_input(enable); + snprintf(str_e_buf, sizeof str_e_buf, "p%p", sw); + str_e = str_e_buf; + fprintf(vvp_out, "%s/d .delay 1 " "(%" PRIu64 ",%" PRIu64 ",%" PRIu64 ") %s;\n", - raw, get_number_immediate64(rise_exp), + str_e, get_number_immediate64(rise_exp), get_number_immediate64(fall_exp), get_number_immediate64(decay_exp), raw); - fprintf(vvp_out, "p%p .import I%p, %s/d;\n", enable, island, raw); - snprintf(str_e_buf, sizeof str_e_buf, "p%p", enable); - str_e = str_e_buf; + fprintf(vvp_out, "%s .import I%p, %s/d;\n", str_e, island, str_e); } else if (enable) { str_e = draw_island_net_input(island, enable); diff --git a/tgt-vvp/draw_vpi.c b/tgt-vvp/draw_vpi.c index 601b04378..ef4bf50c0 100644 --- a/tgt-vvp/draw_vpi.c +++ b/tgt-vvp/draw_vpi.c @@ -170,6 +170,7 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, case IVL_EX_SELECT: { ivl_expr_t vexpr = ivl_expr_oper1(expr); ivl_expr_t bexpr; + ivl_expr_t wexpr; assert(vexpr); @@ -179,20 +180,38 @@ static int get_vpi_taskfunc_signal_arg(struct args_info *result, /* The signal is part of an array. */ /* Add &APV<> code here when it is finished. */ - if (ivl_expr_oper1(vexpr)) return 0; - bexpr = ivl_expr_oper2(expr); /* This is a pad operation. */ if (!bexpr) return 0; + wexpr = ivl_expr_oper1(vexpr); + + /* If vexpr has an operand, then that operand is a word + index and we are taking a select from an array + word. This would come up in expressions like + "array[][]" where wexpr is */ + if (wexpr && number_is_immediate(wexpr, 64, 1) + && number_is_immediate(bexpr, 64, 1)) { + assert(! number_is_unknown(bexpr)); + assert(! number_is_unknown(wexpr)); + snprintf(buffer, sizeof buffer, "&APV", + ivl_expr_signal(vexpr), + get_number_immediate(wexpr), + get_number_immediate(bexpr), + ivl_expr_width(expr)); + + } else if (wexpr) { + return 0; + /* This is a constant bit/part select. */ - if (number_is_immediate(bexpr, 64, 1)) { + } else if (number_is_immediate(bexpr, 64, 1)) { assert(! number_is_unknown(bexpr)); snprintf(buffer, sizeof buffer, "&PV", ivl_expr_signal(vexpr), get_number_immediate(bexpr), ivl_expr_width(expr)); + /* This is an indexed bit/part select. */ } else if (ivl_expr_type(bexpr) == IVL_EX_SIGNAL || ivl_expr_type(bexpr) == IVL_EX_SELECT) { diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 5af817e48..3e7b548d0 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -2924,8 +2924,8 @@ static struct vector_info draw_sfunc_expr(ivl_expr_t expr, unsigned wid) static struct vector_info increment(ivl_expr_t e, unsigned wid, bool pre) { - ivl_signal_t s; - unsigned w; + ivl_signal_t s = 0; + unsigned w = 0; struct vector_info r; struct vector_info rc; @@ -3000,8 +3000,8 @@ static inline struct vector_info post_increment(ivl_expr_t e, unsigned wid) static struct vector_info decrement(ivl_expr_t e, unsigned wid, bool pre) { - ivl_signal_t s; - unsigned w; + ivl_signal_t s = 0; + unsigned w = 0; struct vector_info r; struct vector_info rc; diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index ce8c10d22..56fb2fe7b 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -590,6 +590,7 @@ static int draw_unary_real(ivl_expr_t expr) fprintf(stderr, "vvp.tgt error: unhandled real unary operator: %c.\n", ivl_expr_opcode(expr)); assert(0); + return 0; } int draw_eval_real(ivl_expr_t expr) diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 24b0e98dc..edb29b5e7 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -425,8 +425,17 @@ const char*draw_input_from_net(ivl_nexus_t nex) */ static void draw_reg_in_scope(ivl_signal_t sig) { - int msb = ivl_signal_msb(sig); - int lsb = ivl_signal_lsb(sig); + int msb; + int lsb; + if (ivl_signal_packed_dimensions(sig) > 1) { + // FIX ME: Improve this when vvp becomes aware of packed + // arrays. + msb = ivl_signal_width(sig) - 1; + lsb = 0; + } else { + msb = ivl_signal_msb(sig); + lsb = ivl_signal_lsb(sig); + } const char*datatype_flag = ivl_signal_integer(sig) ? "/i" : ivl_signal_signed(sig)? "/s" : ""; diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index 92b159fb6..b7c9115c8 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -110,9 +110,11 @@ parse.o: parse.cc lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -olexor.cc $(srcdir)/lexor.lex -parse.cc parse.h: $(srcdir)/parse.y - $(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h +# Build this in two steps to avoid parallel build issues (see pr3462585) +parse.cc: $(srcdir)/parse.y + $(YACC) --verbose -t -d -o $@ $< +parse.h: parse.cc + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ lexor_keyword.o: lexor_keyword.cc parse.h diff --git a/vpi/Makefile.in b/vpi/Makefile.in index 2cdef7762..a0aa48993 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -124,24 +124,28 @@ endif system.vpi: $O $(OPP) ../vvp/libvpi.a $(CXX) @shared@ -o $@ $O $(OPP) -L../vvp $(LDFLAGS) -lvpi $(SYSTEM_VPI_LDFLAGS) -sys_readmem_lex.c: sys_readmem_lex.lex - $(LEX) -t $(srcdir)/sys_readmem_lex.lex > sys_readmem_lex.c +sys_readmem_lex.c: $(srcdir)/sys_readmem_lex.lex + $(LEX) -t $< > $@ sdf_lexor.o: sdf_lexor.c sdf_parse.h -sdf_lexor.c: sdf_lexor.lex - $(LEX) -t $(srcdir)/sdf_lexor.lex > sdf_lexor.c +sdf_lexor.c: $(srcdir)/sdf_lexor.lex + $(LEX) -t $< > $@ -sdf_parse.c sdf_parse.h: $(srcdir)/sdf_parse.y - $(YACC) --verbose -d -p sdf -o sdf_parse.c $(srcdir)/sdf_parse.y +# Build this in two steps to avoid parallel build issues (see pr3462585) +sdf_parse.c: $(srcdir)/sdf_parse.y + $(YACC) --verbose -t -p sdf -d -o $@ $< +sdf_parse.h: sdf_parse.c table_mod_lexor.o: table_mod_lexor.c table_mod_parse.h table_mod_lexor.c: $(srcdir)/table_mod_lexor.lex $(LEX) -t $< > $@ -table_mod_parse.c table_mod_parse.h: $(srcdir)/table_mod_parse.y - $(YACC) --verbose -d -p tblmod -o table_mod_parse.c $< +# Build this in two steps to avoid parallel build issues (see pr3462585) +table_mod_parse.c: $(srcdir)/table_mod_parse.y + $(YACC) --verbose -t -p tblmod -d -o $@ $< +table_mod_parse.h: table_mod_parse.c v2005_math.vpi: $M ../vvp/libvpi.a $(CC) @shared@ -o $@ $M -L../vvp $(LDFLAGS) -lvpi $(VA_MATH_VPI_LDFLAGS) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 8e380572c..d5fdb4234 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -182,7 +182,6 @@ static char * format_as_string(int ljust, int plus, int ld_zero, int width, static void get_time(char *rtn, const char *value, int prec, PLI_INT32 time_units) { - int head, tail; int shift = time_units - timeformat_info.units; /* Strip any leading zeros, but leave a single zero. */ @@ -203,7 +202,9 @@ static void get_time(char *rtn, const char *value, int prec, /* We need to scale the number down. */ } else { - head = strlen(value) + shift; + int len = strlen(value); + int head = len + shift; + int tail; /* We have digits to the left of the decimal point. */ if (head > 0) { strncpy(rtn, value, head); @@ -222,18 +223,18 @@ static void get_time(char *rtn, const char *value, int prec, strcpy(rtn, "0"); if (prec > 0) strcat(rtn, "."); /* Add leading zeros as needed. */ - head = -shift - 1; + head = -head; if (head > prec) head = prec; while (head > 0) { strcat(rtn, "0"); head -= 1; } /* Add digits from the value if they fit. */ - tail = prec + shift + 1; + tail = prec + len + shift; if (tail > 0) { strncat(rtn, value, tail); /* Add trailing zeros to fill out the precision. */ - tail = prec + shift + 1 - strlen(value); + tail = prec + shift + 1 - len; while (tail > 0) { strcat(rtn, "0"); tail -= 1; diff --git a/vpi/sys_fileio.c b/vpi/sys_fileio.c index 305775390..667d78fef 100644 --- a/vpi/sys_fileio.c +++ b/vpi/sys_fileio.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -680,7 +680,8 @@ static PLI_INT32 sys_fread_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_free_object(argv); } - words = (width+31)/32; + assert(width > 0); + words = (width - 1)/32 + 1; vector = calloc(words, sizeof(s_vpi_vecval)); bpe = (width+7)/8; diff --git a/vpi/sys_queue.c b/vpi/sys_queue.c index c45fb63ec..4f1dc0e25 100644 --- a/vpi/sys_queue.c +++ b/vpi/sys_queue.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -587,7 +587,7 @@ static unsigned check_numeric_args(vpiHandle argv, unsigned count, /* Check that the first count arguments are numeric. Currently * only three are needed/supported. */ for (idx = 0; idx < count; idx += 1) { - char *loc; + char *loc = NULL; vpiHandle arg = vpi_scan(argv); /* Get the name for this argument. */ diff --git a/vpi/vhdl_table.c b/vpi/vhdl_table.c index e2bb3e8a1..694522119 100644 --- a/vpi/vhdl_table.c +++ b/vpi/vhdl_table.c @@ -104,7 +104,7 @@ static PLI_INT32 ivlh_attribute_event_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) vpi_register_cb(&cb); vpi_put_userdata(sys, mon); - /* Check that there are no more then one argument. */ + /* Check that there is no more than one argument. */ arg = vpi_scan(argv); if (arg != 0) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, sys), diff --git a/vpi/vpi_debug.c b/vpi/vpi_debug.c index 2b8e0cdfc..96f334201 100644 --- a/vpi/vpi_debug.c +++ b/vpi/vpi_debug.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2012 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 @@ -104,6 +104,7 @@ void sys_register() tf_data.sizetf = 0; tf_data.user_data = "$vpi_tree"; res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); } void (*vlog_startup_routines[])() = { diff --git a/vpi_user.h b/vpi_user.h index 7dbe6da81..3d5811835 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ #ifndef __vpi_user_H #define __vpi_user_H /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -46,7 +46,11 @@ EXTERN_C_START # include "_pli_types.h" #define ICARUS_VPI_CONST +#ifdef __cplusplus +typedef class __vpiHandle *vpiHandle; +#else typedef struct __vpiHandle *vpiHandle; +#endif /* * This structure is created by the VPI application to provide hooks diff --git a/vvp/Makefile.in b/vvp/Makefile.in index 6a7d278e2..4f3a59a80 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -129,7 +129,7 @@ vvp@EXEEXT@ libvpi.a: $O $(srcdir)/vvp.def $(CXX) $(LDFLAGS) -o vvp@EXEEXT@ vvp.exp $(LDFLAGS) $O $(dllib) $(LIBS) else libvpi.a: libvpi.c - $(CC) $(CFLAGS) -c $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< rm -f libvpi.a $(AR) cqv libvpi.a libvpi.o $(RANLIB) libvpi.a @@ -157,11 +157,11 @@ parse.o: parse.cc tables.o: tables.cc +# Build this in two steps to avoid parallel build issues (see pr3462585) parse.cc: $(srcdir)/parse.y - $(YACC) --verbose -t -d -o parse.cc $(srcdir)/parse.y - + $(YACC) --verbose -t -d -o $@ $< parse.h: parse.cc - mv parse.cc.h parse.h 2>/dev/null || mv parse.hh parse.h + mv parse.cc.h $@ 2>/dev/null || mv parse.hh $@ lexor.cc: $(srcdir)/lexor.lex $(LEX) -s -olexor.cc $(srcdir)/lexor.lex diff --git a/vvp/array.cc b/vvp/array.cc index 2d0be3155..958c83001 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2007-2012 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 @@ -80,8 +80,15 @@ vvp_array_t array_find(const char*label) * array of double variables. This is very much line the way the * vector4 array works. */ -struct __vpiArray { - struct __vpiHandle base; +struct __vpiArray : public __vpiHandle { + __vpiArray(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + struct __vpiScope*scope; const char*name; /* Permanently allocated string */ unsigned array_count; @@ -97,26 +104,43 @@ struct __vpiArray { vvp_realarray_t *valsr; struct __vpiArrayWord*vals_words; - class vvp_fun_arrayport*ports_; + vvp_fun_arrayport*ports_; struct __vpiCallback *vpi_callbacks; bool signed_flag; bool swap_addr; }; -struct __vpiArrayIterator { - struct __vpiHandle base; +struct __vpiArrayIterator : public __vpiHandle { + __vpiArrayIterator(); + int get_type_code(void) const; + vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); + struct __vpiArray*array; unsigned next; }; -struct __vpiArrayIndex { - struct __vpiHandle base; +struct __vpiArrayIndex : public __vpiHandle { + __vpiArrayIndex(); + int get_type_code(void) const; + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); + struct __vpiDecConst *index; unsigned done; }; -struct __vpiArrayVthrA { - struct __vpiHandle base; +struct __vpiArrayVthrA : public __vpiHandle { + + __vpiArrayVthrA(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + struct __vpiArray*array; // If this is set, then use it to get the index value. vpiHandle address_handle; @@ -133,15 +157,15 @@ struct __vpiArrayVthrA { s_vpi_value vp; /* Check to see if the value is defined. */ vp.format = vpiVectorVal; - vpi_get_value(address_handle, &vp); - int words = (vpi_get(vpiSize, address_handle)-1)/32 + 1; + address_handle->vpi_get_value(&vp); + int words = (address_handle->vpi_get(vpiSize)-1)/32 + 1; for(int idx = 0; idx < words; idx += 1) { /* Return UINT_MAX to indicate an X base. */ if (vp.value.vector[idx].bval != 0) return UINT_MAX; } /* The value is defined so get and return it. */ vp.format = vpiIntVal; - vpi_get_value(address_handle, &vp); + address_handle->vpi_get_value(&vp); return vp.value.integer; } @@ -182,6 +206,20 @@ struct __vpiArrayVthrA { } }; + +struct __vpiArrayVthrAPV : public __vpiHandle { + __vpiArrayVthrAPV(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + + struct __vpiArray*array; + unsigned word_sel; + unsigned part_bit; + unsigned part_wid; +}; + /* Get the array word size. */ unsigned get_array_word_size(vvp_array_t array) { @@ -191,7 +229,7 @@ unsigned get_array_word_size(vvp_array_t array) /* For a net array we need to get the width from the first element. */ if (array->nets) { assert(array->vals4 == 0 && array->valsr == 0); - struct __vpiSignal*vsig = vpip_signal_from_handle(array->nets[0]); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(array->nets[0]); assert(vsig); width = vpip_size(vsig); /* For a variable array we can get the width from vals_width. */ @@ -205,9 +243,9 @@ unsigned get_array_word_size(vvp_array_t array) bool is_net_array(vpiHandle obj) { - assert(obj->vpi_type->type_code == vpiMemory); + struct __vpiArray*rfp = dynamic_cast<__vpiArray*> (obj); + assert(rfp); - struct __vpiArray*rfp = (struct __vpiArray*) obj; if (rfp->nets != 0) return true; return false; } @@ -233,27 +271,34 @@ bool is_net_array(vpiHandle obj) * of vpi functions is bound to the same structure. All the details * for the word also apply when treating this as an index. */ + + struct __vpiArrayWord { - struct __vpiHandle as_word; - struct __vpiHandle as_index; + struct as_word_t : public __vpiHandle { + as_word_t(); + int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + } as_word; + + struct as_index_t : public __vpiHandle { + as_index_t(); + int get_type_code(void) const; + void vpi_get_value(p_vpi_value val); + } as_index; + union { struct __vpiArray*parent; struct __vpiArrayWord*word0; }; }; - -static int vpi_array_get(int code, vpiHandle ref); -static char*vpi_array_get_str(int code, vpiHandle ref); -static vpiHandle vpi_array_get_handle(int code, vpiHandle ref); -static vpiHandle vpi_array_iterate(int code, vpiHandle ref); -static vpiHandle vpi_array_index(vpiHandle ref, int index); - -static vpiHandle array_iterator_scan(vpiHandle ref, int); -static int array_iterator_free_object(vpiHandle ref); +static void array_make_vals_words(struct __vpiArray*parent); static vpiHandle array_index_scan(vpiHandle ref, int); -static int array_index_free_object(vpiHandle ref); static int vpi_array_var_word_get(int code, vpiHandle); static char*vpi_array_var_word_get_str(int code, vpiHandle); @@ -270,101 +315,235 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp); static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int); static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref); -static const struct __vpirt vpip_arraymem_rt = { - vpiMemory, - vpi_array_get, - vpi_array_get_str, - 0, - 0, - vpi_array_get_handle, - vpi_array_iterate, - vpi_array_index, - 0, - 0, - 0 -}; +static int vpi_array_vthr_APV_get(int code, vpiHandle); +static char*vpi_array_vthr_APV_get_str(int code, vpiHandle); +static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp); -static const struct __vpirt vpip_array_iterator_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - 0, - array_iterator_scan, - &array_iterator_free_object, - 0, - 0 -}; +inline __vpiArray::__vpiArray() +{ } -/* This should look a bit odd since it provides a fake iteration on - * this object. This trickery is used to implement the two forms of - * index access, simple handle access and iteration access. */ -static const struct __vpirt vpip_array_index_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - array_index_iterate, - array_index_scan, - array_index_free_object, - 0, - 0 -}; +int __vpiArray::get_type_code(void) const +{ return vpiMemory; } -static const struct __vpirt vpip_array_var_word_rt = { - vpiMemoryWord, - &vpi_array_var_word_get, - &vpi_array_var_word_get_str, - &vpi_array_var_word_get_value, - &vpi_array_var_word_put_value, - &vpi_array_var_word_get_handle, - 0, - 0, - 0, - 0, - 0 -}; +int __vpiArray::vpi_get(int code) +{ + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! -static const struct __vpirt vpip_array_var_index_rt = { - vpiIndex, - 0, - 0, - &vpi_array_var_index_get_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; + case vpiSize: + return (int) array_count; -static const struct __vpirt vpip_array_vthr_A_rt = { - vpiMemoryWord, - &vpi_array_vthr_A_get, - &vpi_array_vthr_A_get_str, - &vpi_array_vthr_A_get_value, - &vpi_array_vthr_A_put_value, - &vpi_array_vthr_A_get_handle, - 0, - 0, - 0, - 0, - 0 -}; + case vpiAutomatic: + return (int) scope->is_automatic; -# define ARRAY_HANDLE(ref) (assert(ref->vpi_type->type_code==vpiMemory), \ - (struct __vpiArray*)ref) + default: + return 0; + } +} + +char* __vpiArray::vpi_get_str(int code) +{ + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + return generic_get_str(code, scope, name, NULL); +} + +vpiHandle __vpiArray::vpi_handle(int code) +{ + switch (code) { + + case vpiLeftRange: + if (swap_addr) return &last_addr; + else return &first_addr; + + case vpiRightRange: + if (swap_addr) return &first_addr; + else return &last_addr; + + case vpiScope: + return scope; + + case vpiModule: + return vpip_module(scope); + } + + return 0; +} + +vpiHandle __vpiArray::vpi_iterate(int code) +{ + switch (code) { + + case vpiMemoryWord: { + struct __vpiArrayIterator*res; + res = new __vpiArrayIterator; + res->array = this; + res->next = 0; + return res; + } + + } + + return 0; +} + +/* +* VPI code passes indices that are not yet converted to canonical +* form, so this index function does it here. +*/ +vpiHandle __vpiArray::vpi_index(int index) +{ + index -= first_addr.value; + if (index >= (long)array_count) + return 0; + if (index < 0) + return 0; + + if (nets != 0) { + return nets[index]; + } + + if (vals_words == 0) + array_make_vals_words(this); + + return &(vals_words[index].as_word); +} + + +inline __vpiArrayIterator::__vpiArrayIterator() +{ } + +int __vpiArrayIterator::get_type_code(void) const +{ return vpiIterator; } + +vpiHandle __vpiArrayIterator::vpi_index(int) +{ + if (next >= array->array_count) { + vpi_free_object(this); + return 0; + } + + unsigned use_index = next; + next += 1; + + if (array->nets) return array->nets[use_index]; + + assert(array->vals4 || array->valsr); + + if (array->vals_words == 0) array_make_vals_words(array); + + return &(array->vals_words[use_index].as_word); +} + + +static int array_iterator_free_object(vpiHandle ref) +{ + struct __vpiArrayIterator*obj = dynamic_cast<__vpiArrayIterator*>(ref); + delete obj; + return 1; +} + +__vpiHandle::free_object_fun_t __vpiArrayIterator::free_object_fun(void) +{ return &array_iterator_free_object; } + +inline __vpiArrayIndex::__vpiArrayIndex() +{ } + +int __vpiArrayIndex::get_type_code(void) const +{ return vpiIterator; } + +vpiHandle __vpiArrayIndex::vpi_iterate(int code) +{ return array_index_iterate(code, this); } + +vpiHandle __vpiArrayIndex::vpi_index(int idx) +{ return array_index_scan(this, idx); } + +static int array_index_free_object(vpiHandle ref) +{ + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); + delete obj; + return 1; +} + +__vpiHandle::free_object_fun_t __vpiArrayIndex::free_object_fun(void) +{ return &array_index_free_object; } + +inline __vpiArrayWord::as_word_t::as_word_t() +{ } + +int __vpiArrayWord::as_word_t::get_type_code(void) const +{ return vpiMemoryWord; } + +int __vpiArrayWord::as_word_t::vpi_get(int code) +{ return vpi_array_var_word_get(code, this); } + +char* __vpiArrayWord::as_word_t::vpi_get_str(int code) +{ return vpi_array_var_word_get_str(code, this); } + +void __vpiArrayWord::as_word_t::vpi_get_value(p_vpi_value val) +{ vpi_array_var_word_get_value(this, val); } + +vpiHandle __vpiArrayWord::as_word_t::vpi_put_value(p_vpi_value val, int flags) +{ return vpi_array_var_word_put_value(this, val, flags); } + +vpiHandle __vpiArrayWord::as_word_t::vpi_handle(int code) +{ return vpi_array_var_word_get_handle(code, this); } + +inline __vpiArrayWord::as_index_t::as_index_t() +{ } + +int __vpiArrayWord::as_index_t::get_type_code(void) const +{ return vpiIndex; } + +void __vpiArrayWord::as_index_t::vpi_get_value(p_vpi_value val) +{ vpi_array_var_index_get_value(this, val); } + +inline __vpiArrayVthrA::__vpiArrayVthrA() +{ } + +int __vpiArrayVthrA::get_type_code(void) const +{ return vpiMemoryWord; } + +int __vpiArrayVthrA::vpi_get(int code) +{ return vpi_array_vthr_A_get(code, this); } + +char* __vpiArrayVthrA::vpi_get_str(int code) +{ return vpi_array_vthr_A_get_str(code, this); } + +void __vpiArrayVthrA::vpi_get_value(p_vpi_value val) +{ vpi_array_vthr_A_get_value(this, val); } + +vpiHandle __vpiArrayVthrA::vpi_put_value(p_vpi_value val, int flags) +{ return vpi_array_vthr_A_put_value(this, val, flags); } + +vpiHandle __vpiArrayVthrA::vpi_handle(int code) +{ return vpi_array_vthr_A_get_handle(code, this); } + + +inline __vpiArrayVthrAPV::__vpiArrayVthrAPV() +{ } + +int __vpiArrayVthrAPV::get_type_code(void) const +{ return vpiMemoryWord; } + +int __vpiArrayVthrAPV::vpi_get(int code) +{ return vpi_array_vthr_APV_get(code, this); } + +char* __vpiArrayVthrAPV::vpi_get_str(int code) +{ return vpi_array_vthr_APV_get_str(code, this); } + +void __vpiArrayVthrAPV::vpi_get_value(p_vpi_value val) +{ vpi_array_vthr_APV_get_value(this, val); } static struct __vpiArrayWord* array_var_word_from_handle(vpiHandle ref) { if (ref == 0) return 0; - if (ref->vpi_type != &vpip_array_var_word_rt) + __vpiArrayWord::as_word_t*ptr = dynamic_cast<__vpiArrayWord::as_word_t*> (ref); + if (ptr == 0) return 0; return (struct __vpiArrayWord*) ref; @@ -374,22 +553,15 @@ static struct __vpiArrayWord* array_var_index_from_handle(vpiHandle ref) { if (ref == 0) return 0; - if (ref->vpi_type != &vpip_array_var_index_rt) + __vpiArrayWord::as_index_t*ptr = dynamic_cast<__vpiArrayWord::as_index_t*> (ref); + if (ptr == 0) return 0; + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_index_t)); + assert(sizeof(__vpiHandle) == sizeof(__vpiArrayWord::as_word_t)); return (struct __vpiArrayWord*) (ref-1); } -static struct __vpiArrayVthrA* array_vthr_a_from_handle(vpiHandle ref) -{ - if (ref == 0) - return 0; - if (ref->vpi_type != &vpip_array_vthr_A_rt) - return 0; - - return (struct __vpiArrayVthrA*) ref; -} - static void array_make_vals_words(struct __vpiArray*parent) { assert(parent->vals_words == 0); @@ -402,8 +574,6 @@ static void array_make_vals_words(struct __vpiArray*parent) struct __vpiArrayWord*words = parent->vals_words; for (unsigned idx = 0 ; idx < parent->array_count ; idx += 1) { - words[idx].as_word.vpi_type = &vpip_array_var_word_rt; - words[idx].as_index.vpi_type = &vpip_array_var_index_rt; words[idx].word0 = words; } } @@ -416,104 +586,6 @@ static unsigned decode_array_word_pointer(struct __vpiArrayWord*word, return word - word0; } -static int vpi_array_get(int code, vpiHandle ref) -{ - struct __vpiArray*obj = ARRAY_HANDLE(ref); - - switch (code) { - case vpiLineNo: - return 0; // Not implemented for now! - - case vpiSize: - return (int) obj->array_count; - - case vpiAutomatic: - return (int) obj->scope->is_automatic; - - default: - return 0; - } -} - -static char*vpi_array_get_str(int code, vpiHandle ref) -{ - struct __vpiArray*obj = ARRAY_HANDLE(ref); - - if (code == vpiFile) { // Not implemented for now! - return simple_set_rbuf_str(file_names[0]); - } - - return generic_get_str(code, &obj->scope->base, obj->name, NULL); -} - -static vpiHandle vpi_array_get_handle(int code, vpiHandle ref) -{ - struct __vpiArray*obj = ARRAY_HANDLE(ref); - - switch (code) { - - case vpiLeftRange: - if (obj->swap_addr) return &(obj->last_addr.base); - else return &(obj->first_addr.base); - - case vpiRightRange: - if (obj->swap_addr) return &(obj->first_addr.base); - else return &(obj->last_addr.base); - - case vpiScope: - return &obj->scope->base; - - case vpiModule: - return vpip_module(obj->scope); - } - - return 0; -} - -static vpiHandle vpi_array_iterate(int code, vpiHandle ref) -{ - struct __vpiArray*obj = ARRAY_HANDLE(ref); - - switch (code) { - - case vpiMemoryWord: { - struct __vpiArrayIterator*res; - res = (struct __vpiArrayIterator*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_array_iterator_rt; - res->array = obj; - res->next = 0; - return &res->base; - } - - } - - return 0; -} - -/* -* VPI code passes indices that are not yet converted to canonical -* form, so this index function does it here. -*/ -static vpiHandle vpi_array_index(vpiHandle ref, int index) -{ - struct __vpiArray*obj = ARRAY_HANDLE(ref); - - index -= obj->first_addr.value; - if (index >= (long)obj->array_count) - return 0; - if (index < 0) - return 0; - - if (obj->nets != 0) { - return obj->nets[index]; - } - - if (obj->vals_words == 0) - array_make_vals_words(obj); - - return &(obj->vals_words[index].as_word); -} - static int vpi_array_var_word_get(int code, vpiHandle ref) { struct __vpiArrayWord*obj = array_var_word_from_handle(ref); @@ -569,7 +641,7 @@ static char*vpi_array_var_word_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%d", (int)index + parent->first_addr.value); - return generic_get_str(code, &parent->scope->base, parent->name, sidx); + return generic_get_str(code, parent->scope, parent->name, sidx); } static void vpi_array_var_word_get_value(vpiHandle ref, p_vpi_value vp) @@ -612,16 +684,16 @@ static vpiHandle vpi_array_var_word_get_handle(int code, vpiHandle ref) return &(obj->as_index); case vpiLeftRange: - return &parent->msb.base; + return &parent->msb; case vpiRightRange: - return &parent->lsb.base; + return &parent->lsb; case vpiParent: - return &parent->base; + return parent; case vpiScope: - return &parent->scope->base; + return parent->scope; case vpiModule: return vpip_module(parent->scope); @@ -642,79 +714,37 @@ static void vpi_array_var_index_get_value(vpiHandle ref, p_vpi_value vp) vp->value.integer = index; } -# define ARRAY_ITERATOR(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ - (struct __vpiArrayIterator*)ref) - -static vpiHandle array_iterator_scan(vpiHandle ref, int) -{ - struct __vpiArrayIterator*obj = ARRAY_ITERATOR(ref); - - if (obj->next >= obj->array->array_count) { - vpi_free_object(ref); - return 0; - } - - unsigned use_index = obj->next; - obj->next += 1; - - if (obj->array->nets) return obj->array->nets[use_index]; - - assert(obj->array->vals4 || obj->array->valsr); - - if (obj->array->vals_words == 0) array_make_vals_words(obj->array); - - return &(obj->array->vals_words[use_index].as_word); -} - -static int array_iterator_free_object(vpiHandle ref) -{ - struct __vpiArrayIterator*obj = ARRAY_ITERATOR(ref); - free(obj); - return 1; -} - -# define ARRAY_INDEX(ref) (assert(ref->vpi_type->type_code==vpiIterator), \ - (struct __vpiArrayIndex*)ref) - vpiHandle array_index_iterate(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiConstant); - struct __vpiDecConst*obj = (struct __vpiDecConst*)ref; + struct __vpiDecConst*obj = dynamic_cast<__vpiDecConst*>(ref); + assert(obj); if (code == vpiIndex) { struct __vpiArrayIndex*res; - res = (struct __vpiArrayIndex*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_array_index_rt; + res = new __vpiArrayIndex; res->index = obj; res->done = 0; - return &res->base; + return res; } return 0; } static vpiHandle array_index_scan(vpiHandle ref, int) { - struct __vpiArrayIndex*obj = ARRAY_INDEX(ref); + struct __vpiArrayIndex*obj = dynamic_cast<__vpiArrayIndex*>(ref); if (obj->done == 0) { obj->done = 1; - return &obj->index->base; + return obj->index; } vpi_free_object(ref); return 0; } -static int array_index_free_object(vpiHandle ref) -{ - struct __vpiArrayIndex*obj = ARRAY_INDEX(ref); - free(obj); - return 1; -} - static int vpi_array_vthr_A_get(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -757,7 +787,7 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -767,7 +797,7 @@ static char*vpi_array_vthr_A_get_str(int code, vpiHandle ref) char sidx [64]; snprintf(sidx, 63, "%d", (int)obj->get_address() + parent->first_addr.value); - return generic_get_str(code, &parent->scope->base, parent->name, sidx); + return generic_get_str(code, parent->scope, parent->name, sidx); } // This function return true if the underlying array words are real. @@ -780,10 +810,8 @@ static unsigned vpi_array_is_real(vvp_array_t arr) // This must be a net array so look at element 0 to find the type. assert(arr->nets != 0); assert(arr->array_count > 0); - struct __vpiRealVar*rsig = vpip_realvar_from_handle(arr->nets[0]); + struct __vpiRealVar*rsig = dynamic_cast<__vpiRealVar*>(arr->nets[0]); if (rsig) { - struct __vpiSignal*vsig = vpip_signal_from_handle(arr->nets[0]); - assert(vsig == 0); return 1U; } @@ -792,7 +820,7 @@ static unsigned vpi_array_is_real(vvp_array_t arr) static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -811,7 +839,7 @@ static void vpi_array_vthr_A_get_value(vpiHandle ref, p_vpi_value vp) static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -834,7 +862,7 @@ static vpiHandle vpi_array_vthr_A_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) { - struct __vpiArrayVthrA*obj = array_vthr_a_from_handle(ref); + struct __vpiArrayVthrA*obj = dynamic_cast<__vpiArrayVthrA*>(ref); assert(obj); struct __vpiArray*parent = obj->array; @@ -844,16 +872,16 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) break; // Not implemented! case vpiLeftRange: - return &parent->msb.base; + return &parent->msb; case vpiRightRange: - return &parent->lsb.base; + return &parent->lsb; case vpiParent: - return &parent->base; + return parent; case vpiScope: - return &parent->scope->base; + return parent->scope; case vpiModule: return vpip_module(parent->scope); @@ -862,6 +890,72 @@ static vpiHandle vpi_array_vthr_A_get_handle(int code, vpiHandle ref) return 0; } +static int vpi_array_vthr_APV_get(int code, vpiHandle ref) +{ + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); + struct __vpiArray*parent = obj->array; + + switch (code) { + case vpiLineNo: + return 0; // Not implemented for now! + + case vpiSize: + return obj->part_wid; + + case vpiLeftRange: + return parent->msb.value; + + case vpiRightRange: + return parent->lsb.value; + + case vpiIndex: + return (int)obj->word_sel; + + case vpiAutomatic: + return (int) parent->scope->is_automatic; + + case vpiConstantSelect: + return 1; + + default: + return 0; + } +} + +static char*vpi_array_vthr_APV_get_str(int code, vpiHandle ref) +{ + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); + assert(obj); + struct __vpiArray*parent = obj->array; + + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + char sidx [64]; + snprintf(sidx, 63, "%u", obj->word_sel + parent->first_addr.value); + return generic_get_str(code, parent->scope, parent->name, sidx); +} + +static void vpi_array_vthr_APV_get_value(vpiHandle ref, p_vpi_value vp) +{ + struct __vpiArrayVthrAPV*obj = dynamic_cast<__vpiArrayVthrAPV*>(ref); + assert(obj); + struct __vpiArray*parent = obj->array; + + assert(parent); + + unsigned index = obj->word_sel; + if (vpi_array_is_real(parent)) { + double tmp = array_get_word_r(parent, index); + vpip_real_get_value(tmp, vp); + } else { + vvp_vector4_t tmp = array_get_word(parent, index); + tmp = tmp.subvalue(obj->part_bit, obj->part_wid); + vpip_vec4_get_value(tmp, obj->part_wid, parent->signed_flag, vp); + } +} + void array_set_word(vvp_array_t arr, unsigned address, unsigned part_off, @@ -894,7 +988,7 @@ void array_set_word(vvp_array_t arr, // Select the word of the array that we affect. vpiHandle word = arr->nets[address]; - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vsig->node->send_vec4_pv(val, part_off, val.size(), vpip_size(vsig), 0); @@ -928,7 +1022,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) assert(arr->array_count > 0); vpiHandle word = arr->nets[0]; assert(word); - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->node->fil); assert(sig); @@ -936,7 +1030,7 @@ vvp_vector4_t array_get_word(vvp_array_t arr, unsigned address) } vpiHandle word = arr->nets[address]; - struct __vpiSignal*vsig = vpip_signal_from_handle(word); + struct __vpiSignal*vsig = dynamic_cast<__vpiSignal*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->node->fil); assert(sig); @@ -956,7 +1050,7 @@ double array_get_word_r(vvp_array_t arr, unsigned address) assert(arr->nets); vpiHandle word = arr->nets[address]; - struct __vpiRealVar*vsig = vpip_realvar_from_handle(word); + struct __vpiRealVar*vsig = dynamic_cast<__vpiRealVar*>(word); assert(vsig); vvp_signal_value*sig = dynamic_cast (vsig->net->fil); assert(sig); @@ -970,8 +1064,7 @@ static vpiHandle vpip_make_array(char*label, const char*name, int first_addr, int last_addr, bool signed_flag) { - struct __vpiArray*obj = (struct __vpiArray*) - malloc(sizeof(struct __vpiArray)); + struct __vpiArray*obj = new __vpiArray; obj->signed_flag = signed_flag; @@ -989,21 +1082,18 @@ static vpiHandle vpip_make_array(char*label, const char*name, // For now, treat all arrays as memories. This is not quite // correct, as arrays are arrays with memories a special case. - obj->base.vpi_type = &vpip_arraymem_rt; obj->scope = vpip_peek_current_scope(); obj->name = vpip_name_string(name); obj->array_count = array_count; - vpip_make_dec_const(&obj->first_addr, first_addr); - vpip_make_dec_const(&obj->last_addr, last_addr); + obj->first_addr.value = first_addr; + obj->last_addr.value = last_addr; // Start off now knowing if we are nets or variables. obj->nets = 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); obj->vals_words = 0; // Initialize (clear) the read-ports list. @@ -1020,12 +1110,12 @@ static vpiHandle vpip_make_array(char*label, const char*name, /* Add this into the table of VPI objects. This is used for contexts that try to look up VPI objects in general. (i.e. arguments to vpi_task calls.) */ - compile_vpi_symbol(label, &(obj->base)); + compile_vpi_symbol(label, obj); /* Blindly attach to the scope as an object. */ - vpip_attach_to_current_scope(&(obj->base)); + vpip_attach_to_current_scope(obj); - return &(obj->base); + return obj; } void array_alias_word(vvp_array_t array, unsigned long addr, vpiHandle word, @@ -1044,27 +1134,27 @@ void array_attach_word(vvp_array_t array, unsigned addr, vpiHandle word) assert(array->nets); array->nets[addr] = word; - if (struct __vpiSignal*sig = vpip_signal_from_handle(word)) { + if (struct __vpiSignal*sig = dynamic_cast<__vpiSignal*>(word)) { vvp_net_t*net = sig->node; assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); 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); + sig->within.parent = array; + sig->id.index = new __vpiDecConst(addr + array->first_addr.value); return; } - if (struct __vpiRealVar*sig = (struct __vpiRealVar*)word) { + if (struct __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(word)) { vvp_net_t*net = sig->net; assert(net); vvp_vpi_callback*fun = dynamic_cast(net->fil); 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); + sig->within.parent = array; + sig->id.index = new __vpiDecConst(addr + array->first_addr.value); return; } } @@ -1075,7 +1165,7 @@ void compile_var_array(char*label, char*name, int last, int first, vpiHandle obj = vpip_make_array(label, name, first, last, signed_flag != 0); - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ arr->vals_width = labs(msb-lsb) + 1; @@ -1086,8 +1176,8 @@ void compile_var_array(char*label, char*name, int last, int first, 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); + arr->msb.value = msb; + arr->lsb.value = lsb; count_var_arrays += 1; count_var_array_words += arr->array_count; @@ -1101,7 +1191,7 @@ 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); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); /* Make the words. */ arr->valsr = new vvp_realarray_t(arr->array_count); @@ -1121,7 +1211,7 @@ void compile_net_array(char*label, char*name, int last, int first) { vpiHandle obj = vpip_make_array(label, name, first, last, false); - struct __vpiArray*arr = ARRAY_HANDLE(obj); + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(obj); arr->nets = (vpiHandle*)calloc(arr->array_count, sizeof(vpiHandle)); count_net_arrays += 1; @@ -1381,6 +1471,16 @@ static void array_attach_port(vvp_array_t array, vvp_fun_arrayport*fun) } } +class array_word_value_callback : public value_callback { + public: + inline explicit array_word_value_callback(p_cb_data data) + : value_callback(data) + { } + + public: + long word_addr; +}; + void array_word_change(vvp_array_t array, unsigned long addr) { for (vvp_fun_arrayport*cur = array->ports_; cur; cur = cur->next_) @@ -1391,48 +1491,51 @@ void array_word_change(vvp_array_t array, unsigned long addr) struct __vpiCallback *prev = 0; while (next) { - struct __vpiCallback*cur = next; + array_word_value_callback*cur = dynamic_cast(next); next = cur->next; // Skip callbacks that are not for me. -1 is for every element. - if (cur->extra_data != (long)addr && cur->extra_data != -1) { + if (cur->word_addr != (long)addr && cur->word_addr != -1) { prev = cur; continue; } // For whole array callbacks we need to set the index. - if (cur->extra_data == -1) { + if (cur->word_addr == -1) { cur->cb_data.index = (PLI_INT32) ((int)addr + array->first_addr.value); } if (cur->cb_data.cb_rtn != 0) { - if (cur->cb_data.value) { - if (vpi_array_is_real(array)) { - vpip_real_get_value(array->valsr->get_word(addr), - cur->cb_data.value); - } else { - vpip_vec4_get_value(array->vals4->get_word(addr), - array->vals_width, - array->signed_flag, - cur->cb_data.value); + if (cur->test_value_callback_ready()) { + if (cur->cb_data.value) { + if (vpi_array_is_real(array)) { + vpip_real_get_value(array->valsr->get_word(addr), + cur->cb_data.value); + } else { + vpip_vec4_get_value(array->vals4->get_word(addr), + array->vals_width, + array->signed_flag, + cur->cb_data.value); + } } + + callback_execute(cur); } - callback_execute(cur); prev = cur; } else if (prev == 0) { array->vpi_callbacks = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } else { assert(prev->next == cur); prev->next = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } } } @@ -1507,29 +1610,94 @@ bool array_port_resolv_list_t::resolve(bool mes) return true; } -void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle obj) +class array_word_part_callback : public array_word_value_callback { + public: + explicit array_word_part_callback(p_cb_data data); + ~array_word_part_callback(); + + bool test_value_callback_ready(void); + + private: + char*value_bits_; +}; + +array_word_part_callback::array_word_part_callback(p_cb_data data) +: array_word_value_callback(data) { - struct __vpiArray*parent = 0; - if (struct __vpiArrayWord*word = array_var_word_from_handle(obj)) { - unsigned addr = decode_array_word_pointer(word, parent); - cb->extra_data = addr; + // Get the initial value of the part, to use as a reference. + struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj); + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + apvword->vpi_get_value(&tmp_value); - } else if (struct __vpiArrayVthrA*tword = array_vthr_a_from_handle(obj)) { - parent = tword->array; - cb->extra_data = tword->address; - } + value_bits_ = new char[apvword->part_wid+1]; - assert(parent); - cb->next = parent->vpi_callbacks; - parent->vpi_callbacks = cb; + memcpy(value_bits_, tmp_value.value.str, apvword->part_wid); + value_bits_[apvword->part_wid] = 0; } -void vpip_array_change(struct __vpiCallback*cb, vpiHandle obj) +array_word_part_callback::~array_word_part_callback() { - struct __vpiArray*arr = ARRAY_HANDLE(obj); - cb->extra_data = -1; // This is a callback for every element. - cb->next = arr->vpi_callbacks; - arr->vpi_callbacks = cb; + delete[]value_bits_; +} + +bool array_word_part_callback::test_value_callback_ready(void) +{ + struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(cb_data.obj); + assert(apvword); + + // Get a reference value that can be used to compare with an + // updated value. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + apvword->vpi_get_value(&tmp_value); + + if (memcmp(value_bits_, tmp_value.value.str, apvword->part_wid) == 0) + return false; + + memcpy(value_bits_, tmp_value.value.str, apvword->part_wid); + return true; + +} + +value_callback*vpip_array_word_change(p_cb_data data) +{ + struct __vpiArray*parent = 0; + array_word_value_callback*cbh = 0; + if (struct __vpiArrayWord*word = array_var_word_from_handle(data->obj)) { + unsigned addr = decode_array_word_pointer(word, parent); + cbh = new array_word_value_callback(data); + cbh->word_addr = addr; + + } else if (struct __vpiArrayVthrA*tword = dynamic_cast<__vpiArrayVthrA*>(data->obj)) { + parent = tword->array; + cbh = new array_word_value_callback(data); + cbh->word_addr = tword->address; + + } else if (struct __vpiArrayVthrAPV*apvword = dynamic_cast<__vpiArrayVthrAPV*>(data->obj)) { + parent = apvword->array; + cbh = new array_word_part_callback(data); + cbh->word_addr = apvword->word_sel; + } + + assert(cbh); + assert(parent); + cbh->next = parent->vpi_callbacks; + parent->vpi_callbacks = cbh; + + return cbh; +} + +value_callback* vpip_array_change(p_cb_data data) +{ + array_word_value_callback*cbh = new array_word_value_callback(data); + assert(data->obj); + + struct __vpiArray*arr = dynamic_cast<__vpiArray*>(data->obj); + cbh->word_addr = -1; // This is a callback for every element. + cbh->next = arr->vpi_callbacks; + arr->vpi_callbacks = cbh; + return cbh; } void compile_array_port(char*label, char*array, char*addr) @@ -1561,22 +1729,20 @@ void compile_array_alias(char*label, char*name, char*src) vvp_array_t mem = array_find(src); assert(mem); - struct __vpiArray*obj = (struct __vpiArray*) - malloc(sizeof (struct __vpiArray)); + struct __vpiArray*obj = new __vpiArray; - obj->base.vpi_type = &vpip_arraymem_rt; obj->scope = vpip_peek_current_scope(); obj->name = vpip_name_string(name); obj->array_count = mem->array_count; obj->signed_flag = mem->signed_flag; // Need to set an accurate range of addresses. - vpip_make_dec_const(&obj->first_addr, mem->first_addr.value); - vpip_make_dec_const(&obj->last_addr, mem->last_addr.value); + obj->first_addr.value = mem->first_addr.value; + obj->last_addr.value = mem->last_addr.value; obj->swap_addr = mem->swap_addr; - vpip_make_dec_const(&obj->msb, mem->msb.value); - vpip_make_dec_const(&obj->lsb, mem->lsb.value); + obj->msb.value = mem->msb.value; + obj->lsb.value = mem->lsb.value; // Share the words with the source array. obj->nets = mem->nets; @@ -1592,20 +1758,23 @@ void compile_array_alias(char*label, char*name, char*src) assert(!array_find(label)); array_table->sym_set_value(label, obj); - compile_vpi_symbol(label, &obj->base); - vpip_attach_to_current_scope(&obj->base); + compile_vpi_symbol(label, obj); + vpip_attach_to_current_scope(obj); free(label); free(name); free(src); } +/* + * &A + * This represents a VPI handle for an addressed array. This comes + * from expressions like "label[addr]" where "label" is the array and + * "addr" is the canonical address of the desired word. + */ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1617,16 +1786,20 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned addr) obj->address = addr; obj->wid = 0; - return &(obj->base); + return obj; } +/* + * &A + * This represents a VPI handle for an addressed word, where the word + * address in thread vector space. The tbase/twod/is_signed variables + * are the location and interpretation of the bits. This comes from + * source expressions that look like label[]. + */ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, char*is_signed) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1641,15 +1814,18 @@ vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, delete [] is_signed; - return &(obj->base); + return obj; } +/* + * &A + * This represents a VPI handle for an addressed word, where the + * word address is calculated from the VPI object that symbol + * represents. The expression that leads to this looks like label[symbol]. + */ vpiHandle vpip_make_vthr_A(char*label, char*symbol) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1662,14 +1838,12 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol) obj->address = 0; obj->wid = 0; - return &(obj->base); + return obj; } + vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) { - struct __vpiArrayVthrA*obj = (struct __vpiArrayVthrA*) - malloc(sizeof (struct __vpiArrayVthrA)); - - obj->base.vpi_type = &vpip_array_vthr_A_rt; + struct __vpiArrayVthrA*obj = new __vpiArrayVthrA; array_resolv_list_t*resolv_mem = new array_resolv_list_t(label); @@ -1681,7 +1855,24 @@ vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle) obj->address = 0; obj->wid = 0; - return &(obj->base); + return obj; +} + +vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid) +{ + struct __vpiArrayVthrAPV*obj = new __vpiArrayVthrAPV; + + array_resolv_list_t*resolv_mem + = new array_resolv_list_t(label); + + resolv_mem->array = &obj->array; + resolv_submit(resolv_mem); + + obj->word_sel = index; + obj->part_bit = bit; + obj->part_wid = wid; + + return obj; } void compile_array_cleanup(void) @@ -1709,7 +1900,7 @@ void memory_delete(vpiHandle item) if (arr->nets) { for (unsigned idx = 0; idx < arr->array_count; idx += 1) { if (struct __vpiSignal*sig = - vpip_signal_from_handle(arr->nets[idx])) { + dynamic_cast<__vpiSignal*>(arr->nets[idx])) { // Delete the individual words? constant_delete(sig->id.index); /* These should only be the real words. */ diff --git a/vvp/array.h b/vvp/array.h index d5c1e15a3..567dfe40c 100644 --- a/vvp/array.h +++ b/vvp/array.h @@ -23,6 +23,7 @@ #include "vpi_user.h" typedef struct __vpiArray* vvp_array_t; +class value_callback; /* * This function tries to find the array (by label) in the global @@ -48,8 +49,8 @@ extern double array_get_word_r(vvp_array_t array, unsigned address); /* VPI hooks */ -extern void vpip_array_word_change(struct __vpiCallback*cb, vpiHandle word); -extern void vpip_array_change(struct __vpiCallback*cb, vpiHandle word); +extern value_callback* vpip_array_word_change(p_cb_data data); +extern value_callback* vpip_array_change(p_cb_data data); /* Compile hooks */ extern void compile_varw_real(char*label, vvp_array_t array, diff --git a/vvp/codes.h b/vvp/codes.h index 1ca329810..e7632d5b2 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -1,7 +1,7 @@ #ifndef __codes_H #define __codes_H /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -186,7 +186,7 @@ struct vvp_code_s { vvp_net_t *net; vvp_code_t cptr; vvp_array_t array; - struct __vpiHandle*handle; + class __vpiHandle*handle; struct __vpiScope*scope; }; diff --git a/vvp/compile.cc b/vvp/compile.cc index 23d266b98..955dc5425 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -287,7 +287,7 @@ vvp_net_t* vvp_net_lookup(const char*label) symbol_value_t val = sym_get_value(sym_vpi, label); if (val.ptr) { vpiHandle vpi = (vpiHandle) val.ptr; - switch (vpi->vpi_type->type_code) { + switch (vpi->get_type_code()) { case vpiNet: case vpiReg: case vpiBitVar: @@ -296,23 +296,23 @@ vvp_net_t* vvp_net_lookup(const char*label) case vpiIntVar: case vpiLongIntVar: case vpiIntegerVar: { - __vpiSignal*sig = (__vpiSignal*)vpi; + __vpiSignal*sig = dynamic_cast<__vpiSignal*>(vpi); return sig->node; } case vpiRealVar: { - __vpiRealVar*sig = (__vpiRealVar*)vpi; + __vpiRealVar*sig = dynamic_cast<__vpiRealVar*>(vpi); return sig->net; } case vpiNamedEvent: { - __vpiNamedEvent*tmp = (__vpiNamedEvent*)vpi; + __vpiNamedEvent*tmp = dynamic_cast<__vpiNamedEvent*>(vpi); return tmp->funct; } default: fprintf(stderr, "Unsupported type %d.\n", - vpi->vpi_type->type_code); + vpi->get_type_code()); assert(0); } } @@ -342,14 +342,14 @@ vvp_net_t* vvp_net_lookup(const char*label) * this call is its last chance. If it cannot complete the operation, * it must print an error message and return false. */ -static class resolv_list_s*resolv_list = 0; +static resolv_list_s*resolv_list = 0; resolv_list_s::~resolv_list_s() { free(label_); } -void resolv_submit(class resolv_list_s*cur) +void resolv_submit(resolv_list_s*cur) { if (cur->resolve()) { delete cur; @@ -636,13 +636,13 @@ void compile_cleanup(void) } do { - class resolv_list_s *res = resolv_list; + resolv_list_s *res = resolv_list; resolv_list = 0x0; last = nerrs == lnerrs; lnerrs = nerrs; nerrs = 0; while (res) { - class resolv_list_s *cur = res; + resolv_list_s *cur = res; res = res->next; if (cur->resolve(last)) delete cur; @@ -1397,7 +1397,7 @@ static struct __vpiModPathSrc*make_modpath_src(struct __vpiModPath*path, vvp_net_t*net = new vvp_net_t; struct __vpiModPathSrc* srcobj = vpip_make_modpath_src(path, net) ; - vpip_attach_to_current_scope(vpi_handle(srcobj)); + vpip_attach_to_current_scope(srcobj); net->fun = obj; /* Save the vpiEdge directory into the input path term. */ @@ -1822,6 +1822,7 @@ void compile_param_logic(char*label, char*name, char*value, bool signed_flag, void compile_param_string(char*label, char*name, char*value, long file_idx, long lineno) { + // name and value become owned bi vpip_make_string_param vpiHandle obj = vpip_make_string_param(name, value, file_idx, lineno); compile_vpi_symbol(label, obj); vpip_attach_to_current_scope(obj); diff --git a/vvp/config.h.in b/vvp/config.h.in index f945cfa03..4c19d788f 100644 --- a/vvp/config.h.in +++ b/vvp/config.h.in @@ -1,7 +1,7 @@ #ifndef __config_H #define __config_H /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -86,9 +86,15 @@ typedef uint64_t vvp_time64_t; +#ifdef __MINGW32__ +# define TIME_FMT_O "I64o" +# define TIME_FMT_U "I64u" +# define TIME_FMT_X "I64x" +#else # define TIME_FMT_O PRIo64 # define TIME_FMT_U PRIu64 # define TIME_FMT_X PRIx64 +#endif # if UINT64_T_AND_ULONG_SAME # define UL_AND_TIME64_SAME diff --git a/vvp/delay.cc b/vvp/delay.cc index 2a37c40c1..0b46cf1ab 100644 --- a/vvp/delay.cc +++ b/vvp/delay.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2011 Stephen Williams + * Copyright (c) 2005-2012 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -737,43 +737,41 @@ bool vvp_fun_modpath_edge::test_vec4(const vvp_vector4_t&bit) */ static int modpath_src_get(int, vpiHandle ref) { - struct __vpiModPathSrc*obj = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*obj =dynamic_cast<__vpiModPathSrc*>(ref); assert(obj); return 0; } static void modpath_src_get_value(vpiHandle ref, p_vpi_value) { - assert((ref->vpi_type->type_code == vpiModPathIn)); - struct __vpiModPathSrc* modpathsrc = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc* modpathsrc = dynamic_cast<__vpiModPathSrc*>(ref); assert(modpathsrc); return; } static vpiHandle modpath_src_put_value(vpiHandle ref, s_vpi_value *, int ) { - assert((ref->vpi_type->type_code == vpiModPathIn)); - struct __vpiModPathSrc* modpathsrc = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc* modpathsrc = dynamic_cast<__vpiModPathSrc*>(ref); assert(modpathsrc); return 0; } static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) { - struct __vpiModPathSrc*rfp = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*rfp = dynamic_cast<__vpiModPathSrc*>(ref); assert(rfp); switch (code) { case vpiScope: - return vpi_handle(rfp->dest->scope); + return rfp->dest->scope; case vpiModule: { struct __vpiScope*scope = rfp->dest->scope; - while (scope && scope->base.vpi_type->type_code != vpiModule) + while (scope && scope->get_type_code() != vpiModule) scope = scope->scope; assert(scope); - return vpi_handle(scope); + return scope; } // Handles to path term objects should really be obtained via @@ -782,17 +780,17 @@ static vpiHandle modpath_src_get_handle(int code, vpiHandle ref) // older versions of Icarus Verilog. case vpiModPathIn: - return vpi_handle(&rfp->path_term_in); + return &rfp->path_term_in; case vpiModPathOut: - return vpi_handle(&rfp->dest->path_term_out); + return &rfp->dest->path_term_out; } return 0; } static vpiHandle modpath_src_iterate(int code, vpiHandle ref) { - struct __vpiModPathSrc*rfp = vpip_modpath_src_from_handle(ref); + struct __vpiModPathSrc*rfp = dynamic_cast<__vpiModPathSrc*>(ref); assert(rfp); // Module paths with multiple sources or destinations are @@ -802,12 +800,12 @@ static vpiHandle modpath_src_iterate(int code, vpiHandle ref) switch (code) { case vpiModPathIn: { vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); - args[0] = vpi_handle(&rfp->path_term_in); + args[0] = &rfp->path_term_in; return vpip_make_iterator(1, args, true); } case vpiModPathOut: { vpiHandle*args = (vpiHandle*)calloc(1, sizeof(vpiHandle*)); - args[0] = vpi_handle(&rfp->dest->path_term_out); + args[0] = &rfp->dest->path_term_out; return vpip_make_iterator(1, args, true); } } @@ -816,18 +814,11 @@ static vpiHandle modpath_src_iterate(int code, vpiHandle ref) static vpiHandle modpath_src_index ( vpiHandle ref, int) { - assert(ref->vpi_type->type_code == vpiModPathIn); + assert(ref->get_type_code() == vpiModPathIn); return 0; } -static int modpath_src_free_object( vpiHandle ref ) -{ - assert( (ref->vpi_type->type_code == vpiModPathIn ) ); - free ( ref ) ; - return 1 ; -} - /* * This routine will put specific dimension of delay[] values * into a vpiHandle. In this case, we will put @@ -838,7 +829,7 @@ static void modpath_src_put_delays (vpiHandle ref, p_vpi_delay delays) { vvp_time64_t tmp[12]; int idx; - struct __vpiModPathSrc * src = vpip_modpath_src_from_handle( ref) ; + struct __vpiModPathSrc * src = dynamic_cast<__vpiModPathSrc*>(ref) ; assert(src) ; vvp_fun_modpath_src *fun = dynamic_cast(src->net->fun); @@ -908,7 +899,7 @@ static void modpath_src_put_delays (vpiHandle ref, p_vpi_delay delays) static void modpath_src_get_delays ( vpiHandle ref, p_vpi_delay delays ) { - struct __vpiModPathSrc*src = vpip_modpath_src_from_handle( ref) ; + struct __vpiModPathSrc*src = dynamic_cast<__vpiModPathSrc*>(ref) ; assert(src); vvp_fun_modpath_src *fun = dynamic_cast(src->net->fun); @@ -944,7 +935,7 @@ static void modpath_src_get_delays ( vpiHandle ref, p_vpi_delay delays ) static int pathterm_get(int code, vpiHandle ref) { - struct __vpiModPathTerm*obj = vpip_modpath_term_from_handle(ref); + struct __vpiModPathTerm*obj = dynamic_cast<__vpiModPathTerm*>(ref); assert(obj); switch (code) { @@ -957,7 +948,7 @@ static int pathterm_get(int code, vpiHandle ref) static vpiHandle pathterm_get_handle(int code, vpiHandle ref) { - struct __vpiModPathTerm*obj = vpip_modpath_term_from_handle(ref); + struct __vpiModPathTerm*obj = dynamic_cast<__vpiModPathTerm*>(ref); assert(obj); switch (code) { @@ -973,37 +964,60 @@ static vpiHandle pathterm_get_handle(int code, vpiHandle ref) * vpiModPath object. The __vpiModPath structure contains items that * are common to a bunch of modpaths, including the destination term. */ -static const struct __vpirt vpip_modpath_src_rt = { - vpiModPath, - modpath_src_get, - 0, /* vpi_get_str */ - modpath_src_get_value, - modpath_src_put_value, - modpath_src_get_handle, - modpath_src_iterate, - modpath_src_index, - modpath_src_free_object, - modpath_src_get_delays, - modpath_src_put_delays -}; +inline __vpiModPathSrc::__vpiModPathSrc() +{ } -static const struct __vpirt vpip_modpath_term_rt = { - vpiPathTerm, - pathterm_get, - 0, // vpi_get_str - 0, // vpi_get_value, - 0, // vpi_put_value, - pathterm_get_handle, - 0, // vpi_iterate, - 0, // vpi_index, - 0, // vpi_free_object, - 0, // vpi_get_delays, - 0 // vpi_put_delays -}; +int __vpiModPathSrc::get_type_code(void) const +{ return vpiModPath; } + +int __vpiModPathSrc::vpi_get(int code) +{ return modpath_src_get(code, this); } + +void __vpiModPathSrc::vpi_get_value(p_vpi_value val) +{ modpath_src_get_value(this, val); } + +vpiHandle __vpiModPathSrc::vpi_put_value(p_vpi_value val, int flags) +{ return modpath_src_put_value(this, val, flags); } + +vpiHandle __vpiModPathSrc::vpi_handle(int code) +{ return modpath_src_get_handle(code, this); } + +vpiHandle __vpiModPathSrc::vpi_iterate(int code) +{ return modpath_src_iterate(code, this); } + +vpiHandle __vpiModPathSrc:: vpi_index(int idx) +{ return modpath_src_index(this, idx); } + +void __vpiModPathSrc::vpi_get_delays(p_vpi_delay del) +{ modpath_src_get_delays(this, del); } + +void __vpiModPathSrc::vpi_put_delays(p_vpi_delay del) +{ modpath_src_put_delays(this, del); } + +static int modpath_src_free_object( vpiHandle ref ) +{ + delete ref; + return 1 ; +} + +__vpiHandle::free_object_fun_t __vpiModPathSrc::free_object_fun(void) +{ return &modpath_src_free_object; } + + +inline __vpiModPathTerm::__vpiModPathTerm() +{ } + +int __vpiModPathTerm::get_type_code(void) const +{ return vpiPathTerm; } + +int __vpiModPathTerm::vpi_get(int code) +{ return pathterm_get(code, this); } + +vpiHandle __vpiModPathTerm::vpi_handle(int code) +{ return pathterm_get_handle(code, this); } static void initialize_path_term(struct __vpiModPathTerm&obj) { - obj.base.vpi_type = &vpip_modpath_term_rt; obj.expr = 0; obj.edge = vpiNoEdge; } @@ -1021,7 +1035,7 @@ static unsigned mp_count = 0; struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) { - struct __vpiModPath*obj = (struct __vpiModPath *)calloc(1, sizeof ( struct __vpiModPath ) ); + struct __vpiModPath*obj = new __vpiModPath; obj->scope = vpip_peek_current_scope ( ); initialize_path_term(obj->path_term_out); @@ -1058,40 +1072,12 @@ void modpath_delete() struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path, vvp_net_t *net) { - struct __vpiModPathSrc *obj = (struct __vpiModPathSrc *) calloc (1, sizeof ( struct __vpiModPathSrc ) ) ; + struct __vpiModPathSrc *obj = new __vpiModPathSrc; - obj->base.vpi_type = &vpip_modpath_src_rt; obj->dest = path; + obj->type = 0; obj->net = net; initialize_path_term(obj->path_term_in); return obj; } - - -/* - this routine will safely convert a modpath vpiHandle - to a struct __vpiModPath { } -*/ - -struct __vpiModPathTerm* vpip_modpath_term_from_handle(vpiHandle ref) -{ - if (ref->vpi_type->type_code != vpiPathTerm) - return 0; - - return (struct __vpiModPathTerm*) ref; -} - -/* - this routine will safely convert a modpathsrc vpiHandle - to a struct __vpiModPathSrc { }, This is equivalent to a - vpiModPathIn handle -*/ - -struct __vpiModPathSrc* vpip_modpath_src_from_handle(vpiHandle ref) -{ - if (ref->vpi_type->type_code != vpiModPath) - return 0; - - return (struct __vpiModPathSrc *) ref; -} diff --git a/vvp/enum_type.cc b/vvp/enum_type.cc index 13ad72b4b..caeea4d22 100644 --- a/vvp/enum_type.cc +++ b/vvp/enum_type.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2010-2012 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 @@ -25,54 +25,51 @@ # include # include -struct enumconst_s { - struct __vpiHandle base; +struct enumconst_s : public __vpiHandle { + enumconst_s(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + const char*name; vvp_vector2_t val2; vvp_vector4_t val4; }; -static struct enumconst_s* enumconst_from_handle(vpiHandle obj) -{ - if (obj->vpi_type->type_code == vpiEnumConst) - return (struct enumconst_s*) obj; - else - return 0; -} +struct __vpiEnumTypespec : public __vpiHandle { + __vpiEnumTypespec(); + int get_type_code(void) const; + int vpi_get(int code); + vpiHandle vpi_iterate(int code); -struct __vpiEnumTypespec { - struct __vpiHandle base; std::vector names; int base_type_code; bool is_signed; }; -static struct __vpiEnumTypespec* vpip_enum_typespec_from_handle(vpiHandle obj) + +inline __vpiEnumTypespec::__vpiEnumTypespec() +{ } + +int __vpiEnumTypespec::get_type_code(void) const +{ return vpiEnumTypespec; } + +int __vpiEnumTypespec::vpi_get(int code) { - if (obj->vpi_type->type_code == vpiEnumTypespec) - return (struct __vpiEnumTypespec*) obj; - - return 0; -} - -static int enum_type_get(int code, vpiHandle obj) -{ - struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); - assert(ref); - switch (code) { case vpiSize: - return ref->names.size(); + return names.size(); /* This is not currently set correctly. We always use vpiReg for * four state variables and vpiBitVar for two state variables. * This minimal functionality is needed to get the next() and * prev() methods to work correctly with invalid values. */ case vpiBaseTypespec: - return ref->base_type_code; + return base_type_code; case vpiSigned: - return ref->is_signed; + return is_signed; default: fprintf(stderr, "vvp error: get %d not supported " @@ -82,93 +79,63 @@ static int enum_type_get(int code, vpiHandle obj) } } -static vpiHandle enum_type_iterate(int code, vpiHandle obj) -{ - struct __vpiEnumTypespec*ref = vpip_enum_typespec_from_handle(obj); - assert(ref); +vpiHandle __vpiEnumTypespec::vpi_iterate(int code) +{ if (code == vpiEnumConst) { vpiHandle*args = (vpiHandle*) - calloc(ref->names.size(), sizeof(vpiHandle*)); - for (size_t idx = 0 ; idx < ref->names.size() ; idx += 1) - args[idx] = vpi_handle(&ref->names[idx]); + calloc(names.size(), sizeof(vpiHandle*)); + for (size_t idx = 0 ; idx < names.size() ; idx += 1) + args[idx] = &names[idx]; - return vpip_make_iterator(ref->names.size(), args, true); + return vpip_make_iterator(names.size(), args, true); } return 0; } -static const struct __vpirt enum_type_rt = { - vpiEnumTypespec, - enum_type_get, - 0, //enum_type_get_str, - 0, //enum_type_get_value, - 0, //enum_type_put_value, - 0, //enum_type_handle, - enum_type_iterate, - 0, //enum_type_index, - 0, //enum_type_free_object, - 0, //enum_type_get_delays, - 0, //enum_type_put_delays -}; -static int enum_name_get(int code, vpiHandle obj) +inline enumconst_s::enumconst_s() +{ } + +int enumconst_s::get_type_code(void) const +{ return vpiEnumConst; } + +int enumconst_s::vpi_get(int code) { - struct enumconst_s*ref = enumconst_from_handle(obj); - assert(ref); - switch (code) { case vpiSize: - return ref->val4.size()? ref->val4.size() : ref->val2.size(); + return val4.size()? val4.size() : val2.size(); default: return 0; } } -static char* enum_name_get_str(int code, vpiHandle obj) -{ - struct enumconst_s*ref = enumconst_from_handle(obj); - assert(ref); +char* enumconst_s::vpi_get_str(int code) +{ switch (code) { case vpiName: - return const_cast (ref->name); + return const_cast (name); default: return 0; } } -static void enum_name_get_value(vpiHandle obj, p_vpi_value value) -{ - struct enumconst_s*ref = enumconst_from_handle(obj); - assert(ref); - if (ref->val4.size() > 0) - vpip_vec4_get_value(ref->val4, ref->val4.size(), false, value); +void enumconst_s::vpi_get_value(p_vpi_value val) +{ + if (val4.size() > 0) + vpip_vec4_get_value(val4, val4.size(), false, val); else - vpip_vec2_get_value(ref->val2, ref->val2.size(), false, value); + vpip_vec2_get_value(val2, val2.size(), false, val); } -static const struct __vpirt enum_name_rt = { - vpiEnumConst, - enum_name_get, - enum_name_get_str, - enum_name_get_value, - 0, //enum_name_put_value, - 0, //enum_name_handle, - 0, //enum_name_iterate, - 0, //enum_name_index, - 0, //enum_name_free_object, - 0, //enum_name_get_delays, - 0, //enum_name_put_delays -}; void compile_enum2_type(char*label, long width, bool signed_flag, std::list*names) { struct __vpiEnumTypespec*spec = new struct __vpiEnumTypespec; - spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; spec->base_type_code = vpiBitVar; @@ -177,14 +144,13 @@ void compile_enum2_type(char*label, long width, bool signed_flag, for (list::iterator cur = names->begin() ; cur != names->end() ; ++cur, ++idx) { assert(cur->val4 == 0); - spec->names[idx].base.vpi_type = &enum_name_rt; spec->names[idx].name = cur->text; spec->names[idx].val2 = vvp_vector2_t(cur->val2, width); } assert(idx == spec->names.size()); - compile_vpi_symbol(label, vpi_handle(spec)); - vpip_attach_to_current_scope(vpi_handle(spec)); + compile_vpi_symbol(label, spec); + vpip_attach_to_current_scope(spec); free(label); delete names; @@ -194,7 +160,6 @@ void compile_enum4_type(char*label, long width, bool signed_flag, std::list*names) { struct __vpiEnumTypespec*spec = new struct __vpiEnumTypespec; - spec->base.vpi_type = &enum_type_rt; spec->names = std::vector (names->size()); spec->is_signed = signed_flag; spec->base_type_code = vpiReg; @@ -202,7 +167,6 @@ void compile_enum4_type(char*label, long width, bool signed_flag, size_t idx = 0; for (list::iterator cur = names->begin() ; cur != names->end() ; ++cur, ++idx) { - spec->names[idx].base.vpi_type = &enum_name_rt; spec->names[idx].name = cur->text; assert(cur->val4); spec->names[idx].val4 = vector4_from_text(cur->val4, width); @@ -211,8 +175,8 @@ void compile_enum4_type(char*label, long width, bool signed_flag, } assert(idx == spec->names.size()); - compile_vpi_symbol(label, vpi_handle(spec)); - vpip_attach_to_current_scope(vpi_handle(spec)); + compile_vpi_symbol(label, spec); + vpip_attach_to_current_scope(spec); free(label); delete names; @@ -221,7 +185,7 @@ void compile_enum4_type(char*label, long width, bool signed_flag, #ifdef CHECK_WITH_VALGRIND void enum_delete(vpiHandle item) { - struct __vpiEnumTypespec*obj = (struct __vpiEnumTypespec*) item; + struct __vpiEnumTypespec*obj = dynamic_cast<__vpiEnumTypespec*>(item); for (vector::iterator iter = obj->names.begin(); iter != obj->names.end(); ++ iter ) { diff --git a/vvp/event.cc b/vvp/event.cc index c3f28c000..8797f64f3 100644 --- a/vvp/event.cc +++ b/vvp/event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -71,7 +71,7 @@ bool evctl::dec_and_run() return ecount_ == 0; } -evctl_real::evctl_real(struct __vpiHandle*handle, double value, +evctl_real::evctl_real(__vpiHandle*handle, double value, unsigned long ecount) :evctl(ecount) { @@ -88,7 +88,7 @@ void evctl_real::run_run() vpi_put_value(handle_, &val, 0, vpiNoDelay); } -void schedule_evctl(struct __vpiHandle*handle, double value, +void schedule_evctl(__vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount) { // Get the functor we are going to wait on. @@ -655,7 +655,7 @@ void vvp_fun_event_or_aa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, } } -vvp_named_event::vvp_named_event(struct __vpiHandle*h) +vvp_named_event::vvp_named_event(__vpiHandle*h) { handle_ = h; } @@ -664,7 +664,7 @@ vvp_named_event::~vvp_named_event() { } -vvp_named_event_sa::vvp_named_event_sa(struct __vpiHandle*h) +vvp_named_event_sa::vvp_named_event_sa(__vpiHandle*h) : vvp_named_event(h), threads_(0) { } @@ -688,10 +688,12 @@ void vvp_named_event_sa::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit, vvp_net_t*net = port.ptr(); net->send_vec4(bit, 0); - vpip_run_named_event_callbacks(handle_); + __vpiNamedEvent*obj = dynamic_cast<__vpiNamedEvent*>(handle_); + assert(obj); + obj->run_vpi_callbacks(); } -vvp_named_event_aa::vvp_named_event_aa(struct __vpiHandle*h) +vvp_named_event_aa::vvp_named_event_aa(__vpiHandle*h) : vvp_named_event(h) { context_idx_ = vpip_add_item_to_context(this, vpip_peek_context_scope()); @@ -851,9 +853,9 @@ void compile_named_event(char*label, char*name) } #ifdef CHECK_WITH_VALGRIND -void named_event_delete(struct __vpiHandle*handle) +void named_event_delete(__vpiHandle*handle) { - struct __vpiNamedEvent *obj = (struct __vpiNamedEvent *) handle; + __vpiNamedEvent *obj = (__vpiNamedEvent *) handle; while (obj->callbacks) { struct __vpiCallback*tmp = obj->callbacks->next; diff --git a/vvp/event.h b/vvp/event.h index ad812234b..96841d53a 100644 --- a/vvp/event.h +++ b/vvp/event.h @@ -1,7 +1,7 @@ #ifndef __event_H #define __event_H /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -40,13 +40,13 @@ class evctl { class evctl_real : public evctl { public: - explicit evctl_real(struct __vpiHandle*handle, double value, + explicit evctl_real(class __vpiHandle*handle, double value, unsigned long ecount); virtual ~evctl_real() {} void run_run(); private: - __vpiHandle*handle_; + class __vpiHandle*handle_; double value_; }; @@ -95,7 +95,7 @@ class evctl_array_r : public evctl { double value_; }; -extern void schedule_evctl(struct __vpiHandle*handle, double value, +extern void schedule_evctl(class __vpiHandle*handle, double value, vvp_net_t*event, unsigned long ecount); extern void schedule_evctl(vvp_net_ptr_t ptr, const vvp_vector4_t&value, @@ -357,11 +357,11 @@ class vvp_fun_event_or_aa : public vvp_fun_event_or, public automatic_hooks_s { class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { public: - explicit vvp_named_event(struct __vpiHandle*eh); + explicit vvp_named_event(class __vpiHandle*eh); ~vvp_named_event(); protected: - struct __vpiHandle*handle_; + class __vpiHandle*handle_; }; /* @@ -370,7 +370,7 @@ class vvp_named_event : public vvp_net_fun_t, public waitable_hooks_s { class vvp_named_event_sa : public vvp_named_event { public: - explicit vvp_named_event_sa(struct __vpiHandle*eh); + explicit vvp_named_event_sa(class __vpiHandle*eh); ~vvp_named_event_sa(); vthread_t add_waiting_thread(vthread_t thread); @@ -388,7 +388,7 @@ class vvp_named_event_sa : public vvp_named_event { class vvp_named_event_aa : public vvp_named_event, public automatic_hooks_s { public: - explicit vvp_named_event_aa(struct __vpiHandle*eh); + explicit vvp_named_event_aa(class __vpiHandle*eh); ~vvp_named_event_aa(); void alloc_instance(vvp_context_t context); diff --git a/vvp/file_line.cc b/vvp/file_line.cc index 924f7d710..99a1b2490 100644 --- a/vvp/file_line.cc +++ b/vvp/file_line.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2011-2012 Cary R. (cygcary@yahoo.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +19,12 @@ # include "compile.h" # include "vpi_priv.h" -struct __vpiFileLine { - struct __vpiHandle base; +struct __vpiFileLine : public __vpiHandle { + __vpiFileLine(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + const char *description; unsigned file_idx; unsigned lineno; @@ -31,9 +35,8 @@ bool code_is_instrumented = false; static int file_line_get(int type, vpiHandle ref) { - struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref; - - assert(ref->vpi_type->type_code == _vpiFileLine); + struct __vpiFileLine*rfp = dynamic_cast<__vpiFileLine*>(ref); + assert(rfp); switch (type) { case vpiLineNo: @@ -45,9 +48,8 @@ static int file_line_get(int type, vpiHandle ref) static char *file_line_get_str(int type, vpiHandle ref) { - struct __vpiFileLine*rfp = (struct __vpiFileLine*)ref; - - assert(ref->vpi_type->type_code == _vpiFileLine); + struct __vpiFileLine*rfp = dynamic_cast<__vpiFileLine*>(ref); + assert(rfp); switch (type) { case vpiFile: @@ -61,19 +63,18 @@ static char *file_line_get_str(int type, vpiHandle ref) } } -static const struct __vpirt vpip_file_line_rt = { - _vpiFileLine, - file_line_get, - file_line_get_str, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; +inline __vpiFileLine::__vpiFileLine() +{ } + +int __vpiFileLine::get_type_code(void) const +{ return _vpiFileLine; } + +int __vpiFileLine::vpi_get(int code) +{ return file_line_get(code, this); } + +char* __vpiFileLine::vpi_get_str(int code) +{ return file_line_get_str(code, this); } + vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) { @@ -83,11 +84,10 @@ vpiHandle vpip_build_file_line(char*description, long file_idx, long lineno) show_file_line = true; code_is_instrumented = true; - obj->base.vpi_type = &vpip_file_line_rt; if (description) obj->description = vpip_name_string(description); else obj->description = 0; obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 02d98b942..1109205cd 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -220,6 +220,7 @@ static char* strdupnew(char const *str) /* Handle the specialized variable access functions. */ "&A" { return K_A; } +"&APV" { return K_APV; } "&PV" { return K_PV; } "%"[.$_/a-zA-Z0-9]+ { diff --git a/vvp/logic.cc b/vvp/logic.cc index dd0faafbe..1372f9700 100644 --- a/vvp/logic.cc +++ b/vvp/logic.cc @@ -63,10 +63,11 @@ void vvp_fun_boolean_::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_[port].subvalue(base, wid) .eeq( bit )) + // Set the part for the input. If nothing changes, then break. + bool flag = input_[port] .set_vec(base, bit); + if (flag == false) return; - input_[port] .set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); @@ -151,10 +152,11 @@ void vvp_fun_buf::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_.subvalue(base, wid) .eeq( bit )) + // Set the input part. If nothing changes, then break. + bool flag = input_.set_vec(base, bit); + if (flag == false) return; - input_.set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); @@ -370,16 +372,17 @@ void vvp_fun_muxz::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, { assert(bit.size() == wid); assert(base + wid <= vwid); + bool flag; switch (ptr.port()) { case 0: - if (a_.subvalue(base, wid) .eeq(bit) && has_run_) return; - a_.set_vec(base, bit); + flag = a_.set_vec(base, bit); + if (flag == false && has_run_) return; if (select_ == SEL_PORT1) return; // The other port is selected. break; case 1: - if (b_.subvalue(base, wid) .eeq(bit) && has_run_) return; - b_.set_vec(base, bit); + flag = b_.set_vec(base, bit); + if (flag == false && has_run_) return; if (select_ == SEL_PORT0) return; // The other port is selected. break; case 2: @@ -475,10 +478,11 @@ void vvp_fun_not::recv_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&bit, assert(bit.size() == wid); assert(base + wid <= vwid); - if (input_.subvalue(base, wid) .eeq( bit )) + // Set the part value. If nothing changes, then break. + bool flag = input_.set_vec(base, bit); + if (flag == false) return; - input_.set_vec(base, bit); if (net_ == 0) { net_ = ptr.ptr(); schedule_functor(this); diff --git a/vvp/parse.y b/vvp/parse.y index 6c03a3335..aff881aa2 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -70,7 +70,7 @@ static struct __vpiModPath*modpath_dst = 0; vvp_delay_t*cdelay; }; -%token K_A K_ALIAS K_ALIAS_R +%token K_A K_ALIAS K_ALIAS_R K_APV %token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD %token K_ARITH_MOD_R K_ARITH_MOD_S %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R @@ -971,6 +971,9 @@ symbol_access { $$ = vpip_make_PV($3, $5, $7); } | K_PV '<' T_SYMBOL ',' T_NUMBER T_NUMBER T_STRING ',' T_NUMBER '>' { $$ = vpip_make_PV($3, $5, $6, $7, $9); } + | K_APV '<' T_SYMBOL ',' T_NUMBER ',' T_NUMBER ',' T_NUMBER '>' + { $$ = vpip_make_vthr_APV($3, $5, $7, $9); } + ; /* functor operands can only be a list of symbols. */ symbols diff --git a/vvp/schedule.cc b/vvp/schedule.cc index f2ab78f54..83d627ae2 100644 --- a/vvp/schedule.cc +++ b/vvp/schedule.cc @@ -123,7 +123,7 @@ void vthread_event_s::single_step_display(void) { struct __vpiScope*scope = vthread_scope(thr); cerr << "vthread_event: Resume thread" - << " scope=" << vpip_get_str(vpiFullName, scope) + << " scope=" << scope->vpi_get_str(vpiFullName) << endl; } @@ -156,7 +156,7 @@ void del_thr_event_s::single_step_display(void) { struct __vpiScope*scope = vthread_scope(thr); cerr << "del_thr_event: Reap completed thread" - << " scope=" << vpip_get_str(vpiFullName, scope) << endl; + << " scope=" << scope->vpi_get_str(vpiFullName) << endl; } struct assign_vector4_event_s : public event_s { diff --git a/vvp/sfunc.cc b/vvp/sfunc.cc index d6b9bbf27..9afb148ea 100644 --- a/vvp/sfunc.cc +++ b/vvp/sfunc.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2006-2012 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 @@ -62,10 +62,8 @@ void sfunc_core::recv_vec4(vvp_net_ptr_t, const vvp_vector4_t&/*bit*/, void sfunc_core::recv_vec4_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - assert(vpi_get(vpiConstType,vpi) == vpiBinaryConst); - - struct __vpiBinaryConst*obj - = (struct __vpiBinaryConst*)vpi; + struct __vpiBinaryConst*obj = dynamic_cast<__vpiBinaryConst*>(vpi); + assert(obj); obj->bits = value(port); @@ -76,10 +74,8 @@ void sfunc_core::recv_vec4_from_inputs(unsigned port) void sfunc_core::recv_real_from_inputs(unsigned port) { vpiHandle vpi = argv_[port]; - assert(vpi_get(vpiConstType,vpi) == vpiRealConst); - - struct __vpiRealConst*obj - = (struct __vpiRealConst*)vpi; + __vpiRealConst*obj = dynamic_cast<__vpiRealConst*>(vpi); + assert(obj); obj->value = value_r(port); diff --git a/vvp/stop.cc b/vvp/stop.cc index 438a8785a..647a8a5da 100644 --- a/vvp/stop.cc +++ b/vvp/stop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -74,7 +74,7 @@ static bool interact_flag = true; static void cmd_call(unsigned argc, char*argv[]) { - struct __vpiHandle**table; + __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -101,7 +101,7 @@ static void cmd_call(unsigned argc, char*argv[]) .(dot) string. This represents the handle for the current scope. */ if (stop_current_scope && (strcmp(argv[idx+1], ".") == 0)) - handle = &stop_current_scope->base; + handle = stop_current_scope; /* Is the argument a quoted string? */ if (handle == 0 && argv[idx+1][0] == '"') { @@ -119,7 +119,7 @@ static void cmd_call(unsigned argc, char*argv[]) /* Is the argument a decimal constant? */ if (handle == 0 && strspn(argv[idx+1],"0123456789") == strlen(argv[idx+1])) { - handle = vpip_make_dec_const(strtol(argv[idx+1],0,10)); + handle = new __vpiDecConst(strtol(argv[idx+1],0,10)); add_to_free_list = true; } @@ -130,14 +130,14 @@ static void cmd_call(unsigned argc, char*argv[]) struct __vpiScope*scope; const char*name; - switch (table[tmp]->vpi_type->type_code) { + switch (table[tmp]->get_type_code()) { case vpiModule: case vpiFunction: case vpiTask: case vpiNamedBegin: case vpiNamedFork: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); if (strcmp(scope->name, argv[idx+1]) == 0) handle = table[tmp]; break; @@ -212,7 +212,7 @@ static void cmd_help(unsigned, char*[]); static void cmd_list(unsigned, char*[]) { - struct __vpiHandle**table; + __vpiHandle**table; unsigned ntable; if (stop_current_scope == 0) { @@ -229,29 +229,29 @@ static void cmd_list(unsigned, char*[]) struct __vpiScope*scope; struct __vpiSignal*sig; - switch (table[idx]->vpi_type->type_code) { + switch (table[idx]->get_type_code()) { case vpiModule: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("module : %s\n", scope->name); break; case vpiTask: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("task : %s\n", scope->name); break; case vpiFunction: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("function: %s\n", scope->name); break; case vpiNamedBegin: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("block : %s\n", scope->name); break; case vpiNamedFork: - scope = (struct __vpiScope*) table[idx]; + scope = dynamic_cast<__vpiScope*>(table[idx]); printf("fork : %s\n", scope->name); break; @@ -260,7 +260,7 @@ static void cmd_list(unsigned, char*[]) break; case vpiReg: - sig = (struct __vpiSignal*) table[idx]; + sig = dynamic_cast<__vpiSignal*>(table[idx]); if ((sig->msb == 0) && (sig->lsb == 0)) printf("reg : %s%s\n", vpi_get_str(vpiName, table[idx]), @@ -273,7 +273,7 @@ static void cmd_list(unsigned, char*[]) break; case vpiNet: - sig = (struct __vpiSignal*) table[idx]; + sig = dynamic_cast<__vpiSignal*>(table[idx]); if ((sig->msb == 0) && (sig->lsb == 0)) printf("net : %s%s\n", vpi_get_str(vpiName, table[idx]), @@ -287,7 +287,7 @@ static void cmd_list(unsigned, char*[]) default: printf("%8d: \n", - table[idx]->vpi_type->type_code); + table[idx]->get_type_code()); break; } @@ -314,7 +314,7 @@ static void cmd_push(unsigned argc, char* argv[]) { for (unsigned idx = 1 ; idx < argc ; idx += 1) { - struct __vpiHandle**table; + __vpiHandle**table; unsigned ntable; struct __vpiScope*child = 0; @@ -329,10 +329,10 @@ static void cmd_push(unsigned argc, char* argv[]) child = 0; unsigned tmp; for (tmp = 0 ; tmp < ntable ; tmp += 1) { - if (table[tmp]->vpi_type->type_code != vpiModule) + if (table[tmp]->get_type_code() != vpiModule) continue; - struct __vpiScope*cp = (struct __vpiScope*) table[tmp]; + struct __vpiScope*cp = dynamic_cast<__vpiScope*>(table[tmp]); /* This is a scope, and the name matches, then report that I found the child. */ @@ -392,15 +392,12 @@ static void cmd_where(unsigned, char*[]) struct __vpiScope*cur = stop_current_scope; while (cur) { - switch (cur->base.vpi_type->type_code) { + switch (cur->get_type_code()) { case vpiModule: - printf("module %s\n", - cur->name); + printf("module %s\n", cur->name); break; default: - printf("scope (%d) %s;\n", - cur->base.vpi_type->type_code, - cur->name); + printf("scope (%d) %s;\n", cur->get_type_code(), cur->name); break; } diff --git a/vvp/vpi_callback.cc b/vvp/vpi_callback.cc index 1ff3b9352..3dd441caf 100644 --- a/vvp/vpi_callback.cc +++ b/vvp/vpi_callback.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -34,33 +34,6 @@ # include # include # include - -/* -* The vpi_free_object() call to a callback doesn't actually delete -* anything, we instead allow the object to run its course and delete -* itself. The semantics of vpi_free_object for a callback is that it -* deletes the *handle*, and not the object itself, so given the vvp -* implementation, there is nothing to do here. -*/ -static int free_simple_callback(vpiHandle) -{ - return 1; -} - -const struct __vpirt callback_rt = { - vpiCallback, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - &free_simple_callback, - 0, - 0 -}; - /* * Callback handles are created when the VPI function registers a * callback. The handle is stored by the run time, and it triggered @@ -76,8 +49,10 @@ const struct __vpirt callback_rt = { * event. This member is only used for things like cbReadOnlySync. */ +class sync_callback; + struct sync_cb : public vvp_gen_event_s { - struct __vpiCallback*handle; + sync_callback*handle; bool sync_flag; ~sync_cb () { } @@ -85,28 +60,133 @@ struct sync_cb : public vvp_gen_event_s { virtual void run_run(); }; - -struct __vpiCallback* new_vpi_callback() +inline __vpiCallback::__vpiCallback() { - struct __vpiCallback* obj; - - obj = new __vpiCallback; - - obj->base.vpi_type = &callback_rt; - obj->cb_sync = 0; - obj->next = 0; - return obj; + next = 0; } -void delete_vpi_callback(struct __vpiCallback* ref) +__vpiCallback::~__vpiCallback() { - assert(ref); - assert(ref->base.vpi_type); - assert(ref->base.vpi_type->type_code == vpiCallback); - delete ref->cb_sync; - delete ref; } +int __vpiCallback::get_type_code(void) const +{ return vpiCallback; } + + +value_callback::value_callback(p_cb_data data) +{ + cb_data = *data; + if (data->time) { + cb_time = *(data->time); + } else { + cb_time.type = vpiSuppressTime; + } + cb_data.time = &cb_time; + if (data->value) { + cb_value = *(data->value); + } else { + cb_value.format = vpiSuppressVal; + } + cb_data.value = &cb_value; +} + +/* + * Normally, any assign to a value triggers a value change callback, + * so return a constant true here. This is a stub. + */ +bool value_callback::test_value_callback_ready(void) +{ + return true; +} + +static void vpip_real_value_change(value_callback*cbh, vpiHandle ref) +{ + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); + vvp_vpi_callback*obj = dynamic_cast(rfp->net->fil); + assert(obj); + + obj->add_vpi_callback(cbh); +} + +class value_part_callback : public value_callback { + public: + explicit value_part_callback(p_cb_data data); + ~value_part_callback(); + + bool test_value_callback_ready(void); + + private: + char*value_bits_; + size_t value_off_; +}; + +inline value_part_callback::value_part_callback(p_cb_data data) +: value_callback(data) +{ + struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(data->obj); + assert(pobj); + + vvp_vpi_callback*sig_fil; + sig_fil = dynamic_cast(pobj->net->fil); + assert(sig_fil); + + sig_fil->add_vpi_callback(this); + // Get a reference value that can be used to compare with an + // updated value. Use the filter get_value to get the value, + // and get it in BinStr form so that compares are easy. Note + // that the vpiBinStr format has the MSB first, but the tbase + // is lsb first. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + sig_fil->get_value(&tmp_value); + + value_bits_ = new char[pobj->width+1]; + value_off_ = pobj->parent->vpi_get(vpiSize) - pobj->width - pobj->tbase; + + memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width); + value_bits_[pobj->width] = 0; +} + +value_part_callback::~value_part_callback() +{ + delete[]value_bits_; +} + +bool value_part_callback::test_value_callback_ready(void) +{ + struct __vpiPV*pobj = dynamic_cast<__vpiPV*>(cb_data.obj); + assert(pobj); + + vvp_vpi_callback*sig_fil; + sig_fil = dynamic_cast(pobj->net->fil); + assert(sig_fil); + + // Get a reference value that can be used to compare with an + // updated value. + s_vpi_value tmp_value; + tmp_value.format = vpiBinStrVal; + sig_fil->get_value(&tmp_value); + + if (memcmp(value_bits_, tmp_value.value.str + value_off_, pobj->width) == 0) + return false; + + memcpy(value_bits_, tmp_value.value.str + value_off_, pobj->width); + return true; +} + +/* + * Attach the __vpiCallback to the object that this part select + * selects from. The part select itself is not a vvp_vpi_callback + * object, but it refers to a net that is a vvp_vpi_callback, so + * add the callback to that object. + */ +static value_callback*make_value_change_part(p_cb_data data) +{ + /* Attach the __vpiCallback object to the signal. */ + value_callback*cbh = new value_part_callback(data); + return cbh; +} /* * A value change callback is tripped when a bit of a signal @@ -115,7 +195,7 @@ void delete_vpi_callback(struct __vpiCallback* ref) * does not already have them, create some callback functors to do the * actual value change detection. */ -static struct __vpiCallback* make_value_change(p_cb_data data) +static value_callback* make_value_change(p_cb_data data) { if (vpi_get(vpiAutomatic, data->obj)) { fprintf(stderr, "vpi error: cannot place value change " @@ -125,25 +205,20 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return 0; } - struct __vpiCallback*obj = new_vpi_callback(); - obj->cb_data = *data; - if (data->time) { - obj->cb_time = *(data->time); - } else { - obj->cb_time.type = vpiSuppressTime; - } - obj->cb_data.time = &obj->cb_time; - if (data->value) { - obj->cb_value = *(data->value); - } else { - obj->cb_value.format = vpiSuppressVal; - } - obj->cb_data.value = &obj->cb_value; + // Special case: the target object is a vpiPartSelect + if (data->obj->get_type_code() == vpiPartSelect) + return make_value_change_part(data); + + if (data->obj->get_type_code() == vpiMemoryWord) + return vpip_array_word_change(data); + + if (data->obj->get_type_code() == vpiMemory) + return vpip_array_change(data); + + value_callback*obj = new value_callback(data); assert(data->obj); - assert(data->obj->vpi_type); - - switch (data->obj->vpi_type->type_code) { + switch (data->obj->get_type_code()) { case vpiReg: case vpiNet: @@ -156,7 +231,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) /* Attach the callback to the vvp_fun_signal node by putting it in the vpi_callbacks list. */ struct __vpiSignal*sig; - sig = reinterpret_cast<__vpiSignal*>(data->obj); + sig = dynamic_cast<__vpiSignal*>(data->obj); vvp_net_fil_t*sig_fil; sig_fil = dynamic_cast(sig->node->fil); @@ -171,22 +246,9 @@ static struct __vpiCallback* make_value_change(p_cb_data data) break; case vpiNamedEvent: - struct __vpiNamedEvent*nev; - nev = reinterpret_cast<__vpiNamedEvent*>(data->obj); - obj->next = nev->callbacks; - nev->callbacks = obj; - break; - - case vpiMemoryWord: - vpip_array_word_change(obj, data->obj); - break; - - case vpiMemory: - vpip_array_change(obj, data->obj); - break; - - case vpiPartSelect: - vpip_part_select_value_change(obj, data->obj); + __vpiNamedEvent*nev; + nev = dynamic_cast<__vpiNamedEvent*>(data->obj); + nev->add_vpi_callback(obj); break; case vpiModule: @@ -199,7 +261,7 @@ static struct __vpiCallback* make_value_change(p_cb_data data) default: fprintf(stderr, "make_value_change: sorry: I cannot callback " "values on type code=%d\n", - data->obj->vpi_type->type_code); + data->obj->get_type_code()); delete obj; return 0; } @@ -207,12 +269,41 @@ static struct __vpiCallback* make_value_change(p_cb_data data) return obj; } +class sync_callback : public __vpiCallback { + public: + explicit sync_callback(p_cb_data data); + ~sync_callback(); + + public: + // scheduled event + struct sync_cb* cb_sync; + // user supplied callback data + struct t_vpi_time cb_time; + + private: +}; + +inline sync_callback::sync_callback(p_cb_data data) +{ + cb_sync = 0; + + cb_data = *data; + assert(data->time); + cb_time = *(data->time); + cb_data.time = &cb_time; +} + +sync_callback::~sync_callback() +{ + delete cb_sync; +} + void sync_cb::run_run() { if (handle == 0) return; - struct __vpiCallback*cur = handle; + sync_callback*cur = handle; cur->cb_data.time->type = vpiSimTime; vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); @@ -226,18 +317,12 @@ void sync_cb::run_run() vpi_mode_flag = VPI_MODE_NONE; } - delete_vpi_callback(cur); + delete cur; } -static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) +static sync_callback* make_sync(p_cb_data data, bool readonly_flag) { - struct __vpiCallback*obj = new_vpi_callback(); - obj->cb_data = *data; - assert(data->time); - obj->cb_time = *(data->time); - obj->cb_data.time = &obj->cb_time; - - obj->next = 0; + sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; cb->sync_flag = readonly_flag? true : false; @@ -271,14 +356,7 @@ static struct __vpiCallback* make_sync(p_cb_data data, bool readonly_flag) static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) { - struct __vpiCallback*obj = new_vpi_callback(); - obj->cb_data = *data; - assert(data->time); - obj->cb_time = *(data->time); - obj->cb_data.time = &obj->cb_time; - - obj->next = 0; - + sync_callback*obj = new sync_callback(data); struct sync_cb*cb = new sync_cb; cb->sync_flag = false; cb->handle = obj; @@ -321,13 +399,21 @@ static struct __vpiCallback* make_afterdelay(p_cb_data data, bool simtime_flag) * callbacks. */ -static struct __vpiCallback*NextSimTime = 0; -static struct __vpiCallback*EndOfCompile = NULL; -static struct __vpiCallback*StartOfSimulation = NULL; -static struct __vpiCallback*EndOfSimulation = NULL; +class simulator_callback : public __vpiCallback { + public: + inline explicit simulator_callback(struct t_cb_data*data) + { cb_data = *data; } + + public: +}; + +static simulator_callback*NextSimTime = 0; +static simulator_callback*EndOfCompile = 0; +static simulator_callback*StartOfSimulation = 0; +static simulator_callback*EndOfSimulation = 0; void vpiEndOfCompile(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks, executing them and @@ -338,16 +424,16 @@ void vpiEndOfCompile(void) { while (EndOfCompile) { cur = EndOfCompile; - EndOfCompile = cur->next; + EndOfCompile = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; } void vpiStartOfSim(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks, executing them and @@ -358,16 +444,16 @@ void vpiStartOfSim(void) { while (StartOfSimulation) { cur = StartOfSimulation; - StartOfSimulation = cur->next; + StartOfSimulation = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; } void vpiPostsim(void) { - struct __vpiCallback* cur; + simulator_callback* cur; /* * Walk the list of register callbacks @@ -377,12 +463,12 @@ void vpiPostsim(void) { while (EndOfSimulation) { cur = EndOfSimulation; - EndOfSimulation = cur->next; + EndOfSimulation = dynamic_cast(cur->next); /* Only set the time if it is not NULL. */ if (cur->cb_data.time) vpip_time_to_timestruct(cur->cb_data.time, schedule_simtime()); (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } vpi_mode_flag = VPI_MODE_NONE; @@ -394,21 +480,20 @@ void vpiPostsim(void) { */ void vpiNextSimTime(void) { - struct __vpiCallback* cur; + simulator_callback* cur; while (NextSimTime) { cur = NextSimTime; - NextSimTime = cur->next; + NextSimTime = dynamic_cast(cur->next); (cur->cb_data.cb_rtn)(&cur->cb_data); - delete_vpi_callback(cur); + delete cur; } } -static struct __vpiCallback* make_prepost(p_cb_data data) +static simulator_callback* make_prepost(p_cb_data data) { - struct __vpiCallback*obj = new_vpi_callback(); - obj->cb_data = *data; + simulator_callback*obj = new simulator_callback(data); /* Insert at head of list */ switch (data->reason) { @@ -473,7 +558,7 @@ vpiHandle vpi_register_cb(p_cb_data data) break; } - return obj? &obj->base : 0; + return obj; } /* @@ -483,11 +568,8 @@ vpiHandle vpi_register_cb(p_cb_data data) */ PLI_INT32 vpi_remove_cb(vpiHandle ref) { - assert(ref); - assert(ref->vpi_type); - assert(ref->vpi_type->type_code == vpiCallback); - - struct __vpiCallback*obj = (struct __vpiCallback*)ref; + struct __vpiCallback*obj = dynamic_cast<__vpiCallback*>(ref); + assert(obj); obj->cb_data.cb_rtn = 0; return 1; @@ -543,7 +625,7 @@ void vvp_vpi_callback::attach_as_word(vvp_array_t arr, unsigned long addr) array_word_ = addr; } -void vvp_vpi_callback::add_vpi_callback(__vpiCallback*cb) +void vvp_vpi_callback::add_vpi_callback(value_callback*cb) { cb->next = vpi_callbacks_; vpi_callbacks_ = cb; @@ -570,31 +652,33 @@ void vvp_vpi_callback::run_vpi_callbacks() { if (array_) array_word_change(array_, array_word_); - struct __vpiCallback *next = vpi_callbacks_; - struct __vpiCallback *prev = 0; + value_callback *next = vpi_callbacks_; + value_callback *prev = 0; while (next) { - struct __vpiCallback*cur = next; - next = cur->next; + value_callback*cur = next; + next = dynamic_cast(cur->next); if (cur->cb_data.cb_rtn != 0) { - if (cur->cb_data.value) - get_value(cur->cb_data.value); + if (cur->test_value_callback_ready()) { + if (cur->cb_data.value) + get_value(cur->cb_data.value); - callback_execute(cur); + callback_execute(cur); + } prev = cur; } else if (prev == 0) { vpi_callbacks_ = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } else { assert(prev->next == cur); prev->next = next; cur->next = 0; - delete_vpi_callback(cur); + delete cur; } } } diff --git a/vvp/vpi_const.cc b/vvp/vpi_const.cc index 82464b112..f7ca58757 100644 --- a/vvp/vpi_const.cc +++ b/vvp/vpi_const.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -29,19 +29,71 @@ # include # include "ivl_alloc.h" -static int string_get(int code, vpiHandle ref) -{ - struct __vpiStringConst*rfp; +class __vpiStringConst : public __vpiHandle { + public: + __vpiStringConst(char*val); + ~__vpiStringConst(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + private: + void process_string_(); + private: + char*value_; + size_t value_len_; +}; + +inline __vpiStringConst::__vpiStringConst(char*v) +: value_(v) +{ + process_string_(); +} + +/* + * Strings are described at the level of the vvp source as a string + * with literal characters or octal escapes. No other escapes are + * included, they are processed already by the compiler that generated + * the vvp source. + */ +void __vpiStringConst::process_string_(void) +{ + char*chr = value_; + char*dp = value_; + + while (*chr) { + char next_char = *chr; + + /* Process octal escapes that I might find. */ + if (*chr == '\\') { + for (int idx = 1 ; idx <= 3 ; idx += 1) { + assert(chr[idx] != 0); + assert(chr[idx] < '8'); + assert(chr[idx] >= '0'); + next_char = next_char*8 + chr[idx] - '0'; + } + chr += 3; + } + *dp++ = next_char; + chr += 1; + } + *dp = 0; + value_len_ = dp - value_; +} + +__vpiStringConst::~__vpiStringConst() +{ + delete[]value_; +} + +int __vpiStringConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiStringConst::vpi_get(int code) +{ switch (code) { case vpiSize: - rfp = (struct __vpiStringConst*)ref; - - assert((ref->vpi_type->type_code == vpiConstant) - || ((ref->vpi_type->type_code == vpiParameter))); - - //fprintf(stderr, "String:|%s|, Length: %d\n", rfp->value, strlen(rfp->value)); - return strlen(rfp->value)*8; + return strlen(value_)*8; case vpiSigned: return 0; @@ -65,18 +117,14 @@ static int string_get(int code, vpiHandle ref) } } -static void string_value(vpiHandle ref, p_vpi_value vp) +void __vpiStringConst::vpi_get_value(p_vpi_value vp) { unsigned uint_value; p_vpi_vecval vecp; - struct __vpiStringConst*rfp = (struct __vpiStringConst*)ref; - int size = strlen(rfp->value); + unsigned size = strlen(value_); char*rbuf = 0; char*cp; - assert((ref->vpi_type->type_code == vpiConstant) - || ((ref->vpi_type->type_code == vpiParameter))); - switch (vp->format) { case vpiObjTypeVal: /* String parameters by default have vpiStringVal values. */ @@ -84,7 +132,7 @@ static void string_value(vpiHandle ref, p_vpi_value vp) case vpiStringVal: rbuf = need_result_buf(size + 1, RBUF_VAL); - strcpy(rbuf, (char*)rfp->value); + strcpy(rbuf, value_); vp->value.str = rbuf; break; @@ -97,9 +145,9 @@ static void string_value(vpiHandle ref, p_vpi_value vp) } rbuf = need_result_buf(size + 1, RBUF_VAL); uint_value = 0; - for(int i=0; ivalue[i]); + uint_value += (unsigned char)(value_[i]); } sprintf(rbuf, "%u", uint_value); vp->value.str = rbuf; @@ -108,9 +156,9 @@ static void string_value(vpiHandle ref, p_vpi_value vp) case vpiBinStrVal: rbuf = need_result_buf(8 * size + 1, RBUF_VAL); cp = rbuf; - for(int i=0; i=0; bit--){ - *cp++ = "01"[ (rfp->value[i]>>bit)&1 ]; + for(unsigned i=0; i=0; bit -= 1){ + *cp++ = "01"[ (value_[i]>>bit)&1 ]; } } *cp = 0; @@ -120,9 +168,9 @@ static void string_value(vpiHandle ref, p_vpi_value vp) case vpiHexStrVal: rbuf = need_result_buf(2 * size + 1, RBUF_VAL); cp = rbuf; - for(int i=0; i=0; nibble--){ - *cp++ = "0123456789abcdef"[ (rfp->value[i]>>(nibble*4))&15 ]; + for(unsigned i=0; i=0; nibble -= 1){ + *cp++ = "0123456789abcdef"[ (value_[i]>>(nibble*4))&15 ]; } } *cp = 0; @@ -136,10 +184,10 @@ static void string_value(vpiHandle ref, p_vpi_value vp) case vpiIntVal: vp->value.integer = 0; - for(int i=0; i=0; bit--){ + for(unsigned i=0; i=0; bit -= 1){ vp->value.integer <<= 1; - vp->value.integer += (rfp->value[i]>>bit)&1; + vp->value.integer += (value_[i]>>bit)&1; } } break; @@ -152,8 +200,8 @@ static void string_value(vpiHandle ref, p_vpi_value vp) uint_value = 0; vecp = vp->value.vector; vecp->aval = vecp->bval = 0; - for(int i=0; iaval |= rfp->value[i] << uint_value*8; + for(unsigned i=0; iaval |= value_[i] << uint_value*8; uint_value += 1; if (uint_value > 3) { uint_value = 0; @@ -174,184 +222,116 @@ static void string_value(vpiHandle ref, p_vpi_value vp) } } -static const struct __vpirt vpip_string_rt = { - vpiConstant, - string_get, - 0, - string_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 + +struct __vpiStringConstTEMP : public __vpiStringConst { + inline __vpiStringConstTEMP(char*v) : __vpiStringConst(v) { } + free_object_fun_t free_object_fun(void); }; static int free_temp_string(vpiHandle obj) { - struct __vpiStringConst*rfp = (struct __vpiStringConst*)obj; - assert(obj->vpi_type->type_code == vpiConstant); - - delete [] rfp->value; - free(rfp); + struct __vpiStringConstTEMP*rfp = dynamic_cast<__vpiStringConstTEMP*>(obj); + delete rfp; return 1; } -static const struct __vpirt vpip_string_temp_rt = { - vpiConstant, - string_get, - 0, - string_value, - 0, - 0, - 0, - 0, - free_temp_string, - 0, - 0 -}; - -/* - * Strings are described at the level of the vvp source as a string - * with literal characters or octal escapes. No other escapes are - * included, they are processed already by the compiler that generated - * the vvp source. - */ -static void vpip_process_string(struct __vpiStringConst*obj) -{ - char*chr = obj->value; - char*dp = obj->value; - - while (*chr) { - char next_char = *chr; - - /* Process octal escapes that I might find. */ - if (*chr == '\\') { - for (int idx = 1 ; idx <= 3 ; idx += 1) { - assert(chr[idx] != 0); - assert(chr[idx] < '8'); - assert(chr[idx] >= '0'); - next_char = next_char*8 + chr[idx] - '0'; - } - chr += 3; - } - *dp++ = next_char; - chr += 1; - } - *dp = 0; - obj->value_len = dp - obj->value; -} +__vpiHandle::free_object_fun_t __vpiStringConstTEMP::free_object_fun(void) +{ return &free_temp_string; } vpiHandle vpip_make_string_const(char*text, bool persistent_flag) { - struct __vpiStringConst*obj; + __vpiStringConst*obj; - obj = (struct __vpiStringConst*) - malloc(sizeof (struct __vpiStringConst)); - obj->base.vpi_type = persistent_flag - ? &vpip_string_rt - : &vpip_string_temp_rt; - obj->value = text; - obj->value_len = 0; - vpip_process_string(obj); + obj = persistent_flag? new __vpiStringConst(text) : new __vpiStringConstTEMP(text); - return &obj->base; + return obj; } -struct __vpiStringParam : public __vpiStringConst { - const char*basename; +class __vpiStringParam : public __vpiStringConst { + public: + __vpiStringParam(char*txt, char*name); + ~__vpiStringParam(); + int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); + struct __vpiScope* scope; unsigned file_idx; unsigned lineno; + private: + const char*basename_; }; -static int string_param_get(int code, vpiHandle ref) +inline __vpiStringParam::__vpiStringParam(char*txt, char*nam) +: __vpiStringConst(txt) { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return string_get(code, ref); + basename_ = nam; } -static char* string_param_get_str(int code, vpiHandle obj) +__vpiStringParam::~__vpiStringParam() { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj; + delete[]basename_; +} - assert(obj->vpi_type->type_code == vpiParameter); +int __vpiStringParam::get_type_code(void) const +{ return vpiParameter; } +int __vpiStringParam::vpi_get(int code) +{ + if (code == vpiLineNo) + return lineno; + + return __vpiStringConst::vpi_get(code); +} + + +char*__vpiStringParam::vpi_get_str(int code) +{ if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); + return simple_set_rbuf_str(file_names[file_idx]); } - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + return generic_get_str(code, scope, basename_, NULL); } -static vpiHandle string_param_handle(int code, vpiHandle obj) + +vpiHandle __vpiStringParam::vpi_handle(int code) { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); - switch (code) { case vpiScope: - return &rfp->scope->base; + return scope; case vpiModule: - return vpip_module(rfp->scope); + return vpip_module(scope); default: return 0; } } -static const struct __vpirt vpip_string_param_rt = { - vpiParameter, - string_param_get, - string_param_get_str, - string_value, - 0, - string_param_handle, - 0, - 0, - 0, - 0, - 0 -}; - - vpiHandle vpip_make_string_param(char*name, char*text, long file_idx, long lineno) { - struct __vpiStringParam*obj; - - obj = (struct __vpiStringParam*) - malloc(sizeof (struct __vpiStringParam)); - obj->base.vpi_type = &vpip_string_param_rt; - obj->value = text; - obj->value_len = 0; - obj->basename = name; + __vpiStringParam*obj = new __vpiStringParam(text, name); obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - vpip_process_string(obj); - - return &obj->base; + return obj; } -static int binary_get(int code, vpiHandle ref) -{ - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref; - assert(ref->vpi_type->type_code == vpiConstant - || ref->vpi_type->type_code == vpiParameter); + +inline __vpiBinaryConst::__vpiBinaryConst() +{ } + +int __vpiBinaryConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiBinaryConst::vpi_get(int code) +{ switch (code) { case vpiConstType: return vpiBinaryConst; @@ -360,10 +340,10 @@ static int binary_get(int code, vpiHandle ref) return 0; // Not implemented for now! case vpiSigned: - return rfp->signed_flag? 1 : 0; + return signed_flag? 1 : 0; case vpiSize: - return rfp->bits.size(); + return bits.size(); case vpiAutomatic: return 0; @@ -382,15 +362,9 @@ static int binary_get(int code, vpiHandle ref) } -static void binary_value(vpiHandle ref, p_vpi_value vp) +void __vpiBinaryConst::vpi_get_value(p_vpi_value val) { - assert(ref->vpi_type->type_code == vpiConstant - || ref->vpi_type->type_code == vpiParameter); - - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)ref; - - - switch (vp->format) { + switch (val->format) { case vpiObjTypeVal: case vpiBinStrVal: @@ -402,31 +376,17 @@ static void binary_value(vpiHandle ref, p_vpi_value vp) case vpiVectorVal: case vpiStringVal: case vpiRealVal: - vpip_vec4_get_value(rfp->bits, rfp->bits.size(), - rfp->signed_flag, vp); + vpip_vec4_get_value(bits, bits.size(), signed_flag, val); break; default: fprintf(stderr, "vvp error: format %d not supported " - "by vpiBinaryConst\n", (int)vp->format); - vp->format = vpiSuppressVal; + "by vpiBinaryConst\n", (int)val->format); + val->format = vpiSuppressVal; break; } } -static const struct __vpirt vpip_binary_rt = { - vpiConstant, - binary_get, - 0, - binary_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; /* * Make a VPI constant from a vector string. The string is normally a @@ -435,10 +395,7 @@ static const struct __vpirt vpip_binary_rt = { */ vpiHandle vpip_make_binary_const(unsigned wid, const char*bits) { - struct __vpiBinaryConst*obj; - - obj = new __vpiBinaryConst; - obj->base.vpi_type = &vpip_binary_rt; + struct __vpiBinaryConst*obj = new __vpiBinaryConst; obj->signed_flag = 0; obj->sized_flag = 0; @@ -451,7 +408,7 @@ vpiHandle vpip_make_binary_const(unsigned wid, const char*bits) obj->bits = vector4_from_text(bp, wid); - return &(obj->base); + return obj; } vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) @@ -482,92 +439,93 @@ vvp_vector4_t vector4_from_text(const char*bits, unsigned wid) } struct __vpiBinaryParam : public __vpiBinaryConst { - const char*basename; + __vpiBinaryParam(const vvp_vector4_t&b, char*name); + ~__vpiBinaryParam(); + int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); + struct __vpiScope*scope; unsigned file_idx; unsigned lineno; + private: + char*basename_; }; -static int binary_param_get(int code, vpiHandle ref) +inline __vpiBinaryParam::__vpiBinaryParam(const vvp_vector4_t&b, char*nam) { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return binary_get(code, ref); + bits = b; + basename_ = nam; } -static char* binary_param_get_str(int code, vpiHandle obj) +__vpiBinaryParam::~__vpiBinaryParam() { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); - - if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); - } - - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + delete[]basename_; } -static vpiHandle binary_param_handle(int code, vpiHandle obj) +int __vpiBinaryParam::get_type_code(void) const +{ return vpiParameter; } + +int __vpiBinaryParam::vpi_get(int code) { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)obj; + if (code == vpiLineNo) + return lineno; - assert(obj->vpi_type->type_code == vpiParameter); + return __vpiBinaryConst::vpi_get(code); +} +char*__vpiBinaryParam::vpi_get_str(int code) +{ + if (code == vpiFile) + return simple_set_rbuf_str(file_names[file_idx]); + + return generic_get_str(code, scope, basename_, NULL); +} + + +vpiHandle __vpiBinaryParam::vpi_handle(int code) +{ switch (code) { case vpiScope: - return &rfp->scope->base; + return scope; case vpiModule: - return vpip_module(rfp->scope); + return vpip_module(scope); default: return 0; } } -static const struct __vpirt vpip_binary_param_rt = { - vpiParameter, - binary_param_get, - binary_param_get_str, - binary_value, - 0, - binary_param_handle, - 0, - 0, - 0, - 0, - 0 -}; vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno) { - struct __vpiBinaryParam*obj = new __vpiBinaryParam; + struct __vpiBinaryParam*obj = new __vpiBinaryParam(bits, name); - obj->base.vpi_type = &vpip_binary_param_rt; - obj->bits = bits; obj->signed_flag = signed_flag? 1 : 0; obj->sized_flag = 0; - obj->basename = name; obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } -static int dec_get(int code, vpiHandle) -{ +__vpiDecConst::__vpiDecConst(int val) +{ + value = val; +} + +int __vpiDecConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiDecConst::vpi_get(int code) +{ switch (code) { case vpiConstType: return vpiDecConst; @@ -595,10 +553,8 @@ static int dec_get(int code, vpiHandle) } -static void dec_value(vpiHandle ref, p_vpi_value vp) +void __vpiDecConst::vpi_get_value(p_vpi_value vp) { - struct __vpiDecConst*rfp = (struct __vpiDecConst*)ref; - assert(ref->vpi_type->type_code == vpiConstant); char*rbuf = need_result_buf(64 + 1, RBUF_VAL); char*cp = rbuf; @@ -606,19 +562,19 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) case vpiObjTypeVal: case vpiIntVal: { - vp->value.integer = rfp->value; + vp->value.integer = value; break; } case vpiDecStrVal: - sprintf(rbuf, "%d", rfp->value); + sprintf(rbuf, "%d", value); vp->value.str = rbuf; break; case vpiBinStrVal: for(int bit=31; bit<=0;bit--){ - *cp++ = "01"[ (rfp->value>>bit)&1 ]; + *cp++ = "01"[ (value>>bit)&1 ]; } *cp = 0; @@ -626,13 +582,13 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) break; case vpiHexStrVal: - sprintf(rbuf, "%08x", rfp->value); + sprintf(rbuf, "%08x", value); vp->value.str = rbuf; break; case vpiOctStrVal: - sprintf(rbuf, "%011x", rfp->value); + sprintf(rbuf, "%011x", value); vp->value.str = rbuf; break; @@ -645,41 +601,16 @@ static void dec_value(vpiHandle ref, p_vpi_value vp) } } -static const struct __vpirt vpip_dec_rt = { - vpiConstant, - dec_get, - 0, - dec_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; -vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value) +inline __vpiRealConst::__vpiRealConst(double val) +: value(val) +{ } + +int __vpiRealConst::get_type_code(void) const +{ return vpiConstant; } + +int __vpiRealConst::vpi_get(int code) { - obj->base.vpi_type = &vpip_dec_rt; - obj->value = value; - - return &(obj->base); -} - -vpiHandle vpip_make_dec_const(int value) -{ - struct __vpiDecConst*obj; - - obj = (struct __vpiDecConst*) - malloc(sizeof (struct __vpiDecConst)); - return vpip_make_dec_const(obj, value); -} - - -static int real_get(int code, vpiHandle) -{ - switch (code) { case vpiLineNo: return 0; // Not implemented for now! @@ -709,123 +640,91 @@ static int real_get(int code, vpiHandle) } } -static void real_value(vpiHandle ref, p_vpi_value vp) -{ - struct __vpiRealConst*rfp = (struct __vpiRealConst*)ref; - assert((ref->vpi_type->type_code == vpiConstant) || - (ref->vpi_type->type_code == vpiParameter)); - vpip_real_get_value(rfp->value, vp); +void __vpiRealConst::vpi_get_value(p_vpi_value val) +{ + vpip_real_get_value(value, val); } -static const struct __vpirt vpip_real_rt = { - vpiConstant, - real_get, - 0, - real_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; - -vpiHandle vpip_make_real_const(struct __vpiRealConst*obj, double value) -{ - obj->base.vpi_type = &vpip_real_rt; - obj->value = value; - return &(obj->base); -} vpiHandle vpip_make_real_const(double value) { - struct __vpiRealConst*obj; - obj =(struct __vpiRealConst*) malloc(sizeof (struct __vpiRealConst)); - return vpip_make_real_const(obj, value); + __vpiRealConst*obj = new __vpiRealConst(value); + return obj; } struct __vpiRealParam : public __vpiRealConst { - const char*basename; + __vpiRealParam(double val, char*name); + ~__vpiRealParam(); + int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + vpiHandle vpi_handle(int code); + struct __vpiScope* scope; unsigned file_idx; unsigned lineno; + private: + const char*basename_; }; -static int real_param_get(int code, vpiHandle ref) + +inline __vpiRealParam::__vpiRealParam(double val, char*name) +: __vpiRealConst(val) { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)ref; - - assert(ref->vpi_type->type_code == vpiParameter); - - if (code == vpiLineNo) { - return rfp->lineno; - } - - return real_get(code, ref); + basename_ = name; } -static char* real_param_get_str(int code, vpiHandle obj) +__vpiRealParam::~__vpiRealParam() { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)obj; - - assert(obj->vpi_type->type_code == vpiParameter); - - if (code == vpiFile) { - return simple_set_rbuf_str(file_names[rfp->file_idx]); - } - - return generic_get_str(code, &rfp->scope->base, rfp->basename, NULL); + delete[]basename_; } -static vpiHandle real_param_handle(int code, vpiHandle obj) + +int __vpiRealParam::get_type_code(void) const +{ return vpiParameter; } + +int __vpiRealParam::vpi_get(int code) { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)obj; + if (code == vpiLineNo) + return lineno; - assert(obj->vpi_type->type_code == vpiParameter); + return __vpiRealConst::vpi_get(code); +} +char* __vpiRealParam::vpi_get_str(int code) +{ + if (code == vpiFile) + return simple_set_rbuf_str(file_names[file_idx]); + + return generic_get_str(code, scope, basename_, NULL); +} + +vpiHandle __vpiRealParam::vpi_handle(int code) +{ switch (code) { case vpiScope: - return &rfp->scope->base; + return scope; case vpiModule: - return vpip_module(rfp->scope); + return vpip_module(scope); default: return 0; } } -static const struct __vpirt vpip_real_param_rt = { - vpiParameter, - real_param_get, - real_param_get_str, - real_value, - 0, - real_param_handle, - 0, - 0, - 0, - 0, - 0 -}; vpiHandle vpip_make_real_param(char*name, double value, long file_idx, long lineno) { - struct __vpiRealParam*obj; + struct __vpiRealParam*obj = new __vpiRealParam(value, name); - obj = (struct __vpiRealParam*) - malloc(sizeof (struct __vpiRealParam)); - obj->base.vpi_type = &vpip_real_param_rt; - obj->value = value; - obj->basename = name; obj->scope = vpip_peek_current_scope(); obj->file_idx = (unsigned) file_idx; obj->lineno = (unsigned) lineno; - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -834,20 +733,20 @@ void constant_delete(vpiHandle item) assert(item->vpi_type->type_code == vpiConstant); switch(vpi_get(vpiConstType, item)) { case vpiStringConst: { - struct __vpiStringConst*rfp = (struct __vpiStringConst*)item; + struct __vpiStringConst*rfp = dynamic_cast<__vpiStringConst*>(item); delete [] rfp->value; free(rfp); break; } case vpiDecConst: { - struct __vpiDecConst*rfp = (struct __vpiDecConst*)item; + struct __vpiDecConst*rfp = dynamic_cast<__vpiDecConst*>(item); free(rfp); break; } case vpiBinaryConst: { - struct __vpiBinaryConst*rfp = (struct __vpiBinaryConst*)item; + struct __vpiBinaryConst*rfp = dynamic_cast<__vpiBinaryConst*>(item); delete rfp; break; } case vpiRealConst: { - struct __vpiRealConst*rfp = (struct __vpiRealConst*)item; + struct __vpiRealConst*rfp = dynamic_cast<__vpiRealConst*>(item); free(rfp); break; } default: @@ -859,20 +758,16 @@ void parameter_delete(vpiHandle item) { switch(vpi_get(vpiConstType, item)) { case vpiStringConst: { - struct __vpiStringParam*rfp = (struct __vpiStringParam*)item; - delete [] rfp->basename; - delete [] rfp->value; - free(rfp); + struct __vpiStringParam*rfp = dynamic_cast<__vpiStringParam*>(item); + delete rfp; break; } case vpiBinaryConst: { - struct __vpiBinaryParam*rfp = (struct __vpiBinaryParam*)item; - delete [] rfp->basename; + struct __vpiBinaryParam*rfp = dynamic_cast<__vpiBinaryParam*>(item); delete rfp; break; } case vpiRealConst: { - struct __vpiRealParam*rfp = (struct __vpiRealParam*)item; - delete [] rfp->basename; - free(rfp); + struct __vpiRealParam*rfp = dynamic_cast<__vpiRealParam*>(item); + delete rfp; break; } default: assert(0); diff --git a/vvp/vpi_event.cc b/vvp/vpi_event.cc index 49c01cab0..3b650dc91 100644 --- a/vvp/vpi_event.cc +++ b/vvp/vpi_event.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2012 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 @@ -25,77 +25,57 @@ # include # include "ivl_alloc.h" -static int named_event_get(int code, vpiHandle ref) +inline __vpiNamedEvent::__vpiNamedEvent(__vpiScope*sc, const char*nam) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); + scope_ = sc; + name_ = vpip_name_string(nam); + callbacks_ = 0; +} - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; +int __vpiNamedEvent::get_type_code(void) const +{ return vpiNamedEvent; } +int __vpiNamedEvent::vpi_get(int code) +{ switch (code) { case vpiAutomatic: - return (int) obj->scope->is_automatic; + return (int) scope_->is_automatic; } return 0; } -static char* named_event_get_str(int code, vpiHandle ref) +char* __vpiNamedEvent::vpi_get_str(int code) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; - if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); } - return generic_get_str(code, &obj->scope->base, obj->name, NULL); + return generic_get_str(code, scope_, name_, NULL); } -static vpiHandle named_event_get_handle(int code, vpiHandle ref) + +vpiHandle __vpiNamedEvent::vpi_handle(int code) { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; - switch (code) { case vpiScope: - return &obj->scope->base; + return scope_; case vpiModule: - return vpip_module(obj->scope); + return vpip_module(scope_); } return 0; } -static const struct __vpirt vpip_named_event_rt = { - vpiNamedEvent, - - named_event_get, - named_event_get_str, - 0, - 0, - named_event_get_handle, - 0, - 0, - 0, - 0, - 0 -}; vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) { - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*) - malloc(sizeof(struct __vpiNamedEvent)); + __vpiNamedEvent*obj = new __vpiNamedEvent(vpip_peek_current_scope(), name); - obj->base.vpi_type = &vpip_named_event_rt; - obj->name = vpip_name_string(name); - obj->scope = vpip_peek_current_scope(); obj->funct = funct; - obj->callbacks = 0; - return &obj->base; + return obj; } /* @@ -111,13 +91,9 @@ vpiHandle vpip_make_named_event(const char*name, vvp_net_t*funct) * We can not use vpi_free_object() here since it does not really * delete the callback. */ -void vpip_run_named_event_callbacks(vpiHandle ref) +void __vpiNamedEvent::run_vpi_callbacks() { - assert((ref->vpi_type->type_code==vpiNamedEvent)); - - struct __vpiNamedEvent*obj = (struct __vpiNamedEvent*)ref; - - struct __vpiCallback*next = obj->callbacks; + struct __vpiCallback*next = callbacks_; struct __vpiCallback*prev = 0; while (next) { struct __vpiCallback*cur = next; @@ -128,7 +104,7 @@ void vpip_run_named_event_callbacks(vpiHandle ref) prev = cur; } else if (prev == 0) { - obj->callbacks = next; + callbacks_ = next; cur->next = 0; delete cur; diff --git a/vvp/vpi_iter.cc b/vvp/vpi_iter.cc index f548e796a..723803b8b 100644 --- a/vvp/vpi_iter.cc +++ b/vvp/vpi_iter.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2012 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 @@ -28,8 +28,8 @@ static int iterator_free_object(vpiHandle ref) { - struct __vpiIterator*hp = (struct __vpiIterator*)ref; - assert(ref->vpi_type->type_code == vpiIterator); + struct __vpiIterator*hp = dynamic_cast<__vpiIterator*>(ref); + assert(hp); if (hp->free_args_flag) free(hp->args); @@ -38,33 +38,26 @@ static int iterator_free_object(vpiHandle ref) return 1; } -static const struct __vpirt vpip_iterator_rt = { - vpiIterator, - 0, // vpi_get_ - 0, // vpi_get_str_ - 0, // vpi_get_value_ - 0, // vpi_put_value_ - 0, // handle_ - 0, // iterate_ - 0, // index_ - &iterator_free_object, - 0, // vpi_get_delay - 0 // vpi_put_delay -}; +inline __vpiIterator::__vpiIterator() +{ } + +int __vpiIterator::get_type_code(void) const +{ return vpiIterator; } + +__vpiHandle::free_object_fun_t __vpiIterator::free_object_fun(void) +{ return &iterator_free_object; } vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, bool free_args_flag) { - struct __vpiIterator*res = (struct __vpiIterator*) - calloc(1, sizeof(struct __vpiIterator)); - res->base.vpi_type = &vpip_iterator_rt; + struct __vpiIterator*res = new __vpiIterator; res->args = args; res->nargs = nargs; res->next = 0; res->free_args_flag = free_args_flag; - return &(res->base); + return res; } /* @@ -79,25 +72,14 @@ vpiHandle vpi_scan(vpiHandle ref) return 0; } - if (ref->vpi_type->type_code != vpiIterator) { - fprintf(stderr, "ERROR: vpi_scan argument is " - "inappropriate vpiType code %d\n", - ref->vpi_type->type_code); - assert(0); - return 0; + if (struct __vpiIterator*hp = dynamic_cast<__vpiIterator*>(ref)) { + if (hp->next == hp->nargs) { + vpi_free_object(ref); + return 0; + } + + return hp->args[hp->next++]; } - struct __vpiIterator*hp = (struct __vpiIterator*)ref; - assert(ref); - assert(ref->vpi_type->type_code == vpiIterator); - - if (ref->vpi_type->index_) - return (ref->vpi_type->index_(ref, 0)); - - if (hp->next == hp->nargs) { - vpi_free_object(ref); - return 0; - } - - return hp->args[hp->next++]; + return ref->vpi_index(0); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index f1c2ab814..309993783 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2012 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 @@ -34,6 +34,48 @@ FILE*vpi_trace = 0; static s_vpi_vlog_info vpi_vlog_info; static s_vpi_error_info vpip_last_error = { 0, 0, 0, 0, 0, 0, 0 }; +__vpiHandle::~__vpiHandle() +{ } + +int __vpiHandle::vpi_get(int) +{ return vpiUndefined; } + +char* __vpiHandle::vpi_get_str(int) +{ return 0; } + +void __vpiHandle::vpi_get_value(p_vpi_value) +{ } + +vpiHandle __vpiHandle::vpi_put_value(p_vpi_value, int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_handle(int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_iterate(int) +{ return 0; } + +vpiHandle __vpiHandle::vpi_index(int) +{ return 0; } + +void __vpiHandle::vpi_get_delays(p_vpi_delay) +{ } + +void __vpiHandle::vpi_put_delays(p_vpi_delay) +{ } + +/* + * The default behavior for the vpi_free_object to an object is to + * suppress the actual operation. This is because handles are + * generally allocated semi-permanently within vvp context. Dynamic + * objects will override the free_object_fun method to return an + * appropriately effective function. + */ +static int suppress_free(vpiHandle) +{ return 1; } +__vpiHandle::free_object_fun_t __vpiHandle::free_object_fun(void) +{ return &suppress_free; } + /* * The vpip_string function creates a constant string from the pass * input. This constant string is permanently allocated from an @@ -67,11 +109,11 @@ struct __vpiScope* vpip_scope(__vpiRealVar*sig) vpiHandle vpip_module(struct __vpiScope*scope) { - while(scope && scope->base.vpi_type->type_code != vpiModule) { + while(scope && scope->get_type_code() != vpiModule) { scope = scope->scope; } assert(scope); - return &scope->base; + return scope; } const char *vpip_string(const char*str) @@ -165,17 +207,13 @@ PLI_INT32 vpi_compare_objects(vpiHandle obj1, vpiHandle obj2) */ void vpi_get_systf_info(vpiHandle ref, p_vpi_systf_data data) { - assert((ref->vpi_type->type_code == vpiUserSystf) || - (ref->vpi_type->type_code == vpiSysTaskCall) || - (ref->vpi_type->type_code == vpiSysFuncCall)); - - struct __vpiUserSystf* rfp; - if (ref->vpi_type->type_code == vpiUserSystf) { - rfp = (struct __vpiUserSystf*)ref; - } else { - struct __vpiSysTaskCall*call = (struct __vpiSysTaskCall*)ref; + struct __vpiUserSystf* rfp = dynamic_cast<__vpiUserSystf*>(ref); + if (rfp == 0) { + struct __vpiSysTaskCall*call = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(call); rfp = call->defn; } + /* Assert that vpiUserDefn is true! */ assert(rfp->is_user_defn); @@ -204,10 +242,8 @@ PLI_INT32 vpi_free_object(vpiHandle ref) } assert(ref); - if (ref->vpi_type->vpi_free_object_ == 0) - rtn = 1; - else - rtn = ref->vpi_type->vpi_free_object_(ref); + __vpiHandle::free_object_fun_t fun = ref->free_object_fun(); + rtn = fun (ref); if (vpi_trace) fprintf(vpi_trace, " --> %d\n", rtn); @@ -327,25 +363,16 @@ PLI_INT32 vpi_get(int property, vpiHandle ref) if (property == vpiType) { if (vpi_trace) { fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n", - ref, vpi_type_values(ref->vpi_type->type_code)); + ref, vpi_type_values(ref->get_type_code())); } - if (ref->vpi_type->type_code == vpiMemory && is_net_array(ref)) + if (ref->get_type_code() == vpiMemory && is_net_array(ref)) return vpiNetArray; else - return ref->vpi_type->type_code; + return ref->get_type_code(); } - if (ref->vpi_type->vpi_get_ == 0) { - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get(%s, %p) --X\n", - vpi_property_str(property), ref); - } - - return vpiUndefined; - } - - int res = (ref->vpi_type->vpi_get_)(property, ref); + int res = ref->vpi_get(property); if (vpi_trace) { fprintf(vpi_trace, "vpi_get(%s, %p) --> %d\n", @@ -380,30 +407,22 @@ char* vpi_get_str(PLI_INT32 property, vpiHandle ref) if (property == vpiType) { if (vpi_trace) { fprintf(vpi_trace, "vpi_get(vpiType, %p) --> %s\n", - ref, vpi_type_values(ref->vpi_type->type_code)); + ref, vpi_type_values(ref->get_type_code())); } PLI_INT32 type; - if (ref->vpi_type->type_code == vpiMemory && is_net_array(ref)) + if (ref->get_type_code() == vpiMemory && is_net_array(ref)) type = vpiNetArray; else - type = ref->vpi_type->type_code; + type = ref->get_type_code(); return (char *)vpi_type_values(type); } - if (ref->vpi_type->vpi_get_str_ == 0) { - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get_str(%s, %p) --X\n", - vpi_property_str(property), ref); - } - return 0; - } - - char*res = (char*)(ref->vpi_type->vpi_get_str_)(property, ref); + char*res = ref->vpi_get_str(property); if (vpi_trace) { fprintf(vpi_trace, "vpi_get_str(%s, %p) --> %s\n", - vpi_property_str(property), ref, res); + vpi_property_str(property), ref, res? res : ""); } return res; @@ -418,24 +437,24 @@ int vpip_time_units_from_handle(vpiHandle obj) if (obj == 0) return vpip_get_time_precision(); - switch (obj->vpi_type->type_code) { + switch (obj->get_type_code()) { case vpiSysTaskCall: - task = (struct __vpiSysTaskCall*)obj; + task = dynamic_cast<__vpiSysTaskCall*>(obj); return task->scope->time_units; case vpiModule: - scope = (struct __vpiScope*)obj; + scope = dynamic_cast<__vpiScope*>(obj); return scope->time_units; case vpiNet: case vpiReg: - signal = vpip_signal_from_handle(obj); + signal = dynamic_cast<__vpiSignal*>(obj); scope = vpip_scope(signal); return scope->time_units; default: fprintf(stderr, "ERROR: vpip_time_units_from_handle called with " - "object handle type=%u\n", obj->vpi_type->type_code); + "object handle type=%u\n", obj->get_type_code()); assert(0); return 0; } @@ -450,24 +469,24 @@ int vpip_time_precision_from_handle(vpiHandle obj) if (obj == 0) return vpip_get_time_precision(); - switch (obj->vpi_type->type_code) { + switch (obj->get_type_code()) { case vpiSysTaskCall: - task = (struct __vpiSysTaskCall*)obj; + task = dynamic_cast<__vpiSysTaskCall*>(obj); return task->scope->time_precision; case vpiModule: - scope = (struct __vpiScope*)obj; + scope = dynamic_cast<__vpiScope*>(obj); return scope->time_precision; case vpiNet: case vpiReg: - signal = vpip_signal_from_handle(obj); + signal = dynamic_cast<__vpiSignal*>(obj); scope = vpip_scope(signal); return scope->time_precision; default: fprintf(stderr, "ERROR: vpip_time_precision_from_handle called " - "with object handle type=%u\n", obj->vpi_type->type_code); + "with object handle type=%u\n", obj->get_type_code()); assert(0); return 0; } @@ -671,7 +690,7 @@ void vpip_vec4_get_value(const vvp_vector4_t&word_val, unsigned width, vp->format = vpiVectorVal; case vpiVectorVal: { - unsigned hwid = (width - 1)/32 + 1; + unsigned hwid = (width + 31)/32; rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); s_vpi_vecval *op = (p_vpi_vecval)rbuf; @@ -736,7 +755,7 @@ void vpip_vec2_get_value(const vvp_vector2_t&word_val, unsigned width, break; case vpiVectorVal: { - unsigned hwid = (width - 1)/32 + 1; + unsigned hwid = (width + 31)/32; rbuf = need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); s_vpi_vecval *op = (p_vpi_vecval)rbuf; @@ -879,38 +898,34 @@ void vpi_get_value(vpiHandle expr, s_vpi_value*vp) { assert(expr); assert(vp); - if (expr->vpi_type->vpi_get_value_) { - (expr->vpi_type->vpi_get_value_)(expr, vp); - if (vpi_trace) switch (vp->format) { + expr->vpi_get_value(vp); + + if (vpi_trace) switch (vp->format) { case vpiStringVal: fprintf(vpi_trace,"vpi_get_value(%p=<%d>) -> string=\"%s\"\n", - expr, expr->vpi_type->type_code, vp->value.str); + expr, expr->get_type_code(), vp->value.str); break; case vpiBinStrVal: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> binstr=%s\n", - expr->vpi_type->type_code, vp->value.str); + expr->get_type_code(), vp->value.str); break; case vpiIntVal: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> int=%d\n", - expr->vpi_type->type_code, (int)vp->value.integer); + expr->get_type_code(), (int)vp->value.integer); + break; + + case vpiSuppressVal: + fprintf(vpi_trace, "vpi_get_value(<%d>...) -> \n", + expr->get_type_code()); break; default: fprintf(vpi_trace, "vpi_get_value(<%d>...) -> <%d>=?\n", - expr->vpi_type->type_code, (int)vp->format); + expr->get_type_code(), (int)vp->format); } - return; - } - - if (vpi_trace) { - fprintf(vpi_trace, "vpi_get_value(<%d>...) -> \n", - expr->vpi_type->type_code); - } - - vp->format = vpiSuppressVal; } struct vpip_put_value_event : vvp_gen_event_s { @@ -923,7 +938,7 @@ struct vpip_put_value_event : vvp_gen_event_s { void vpip_put_value_event::run_run() { - handle->vpi_type->vpi_put_value_ (handle, &value, flags); + handle->vpi_put_value(&value, flags); switch (value.format) { /* Free the copied string. */ case vpiBinStrVal: @@ -933,23 +948,59 @@ void vpip_put_value_event::run_run() case vpiStringVal: free(value.value.str); break; - /* If these are ever copied then free them too. */ + /* Free the copied time structure. */ case vpiTimeVal: + free(value.value.time); + break; + /* Free the copied vector structure. */ case vpiVectorVal: + free(value.value.vector); + break; + /* Free the copied strength structure. */ case vpiStrengthVal: + free(value.value.strength); + break; + /* Everything else is static in the structure. */ default: break; } } +/* Make a copy of a pointer to a time structure. */ +static t_vpi_time *timedup(t_vpi_time *val) +{ + t_vpi_time *rtn; + rtn = (t_vpi_time *) malloc(sizeof(t_vpi_time)); + *rtn = *val; + return rtn; +} + +/* Make a copy of a pointer to a vector value structure. */ +static t_vpi_vecval *vectordup(t_vpi_vecval *val, PLI_INT32 size) +{ + unsigned num_bytes; + t_vpi_vecval *rtn; + assert(size > 0); + num_bytes = ((size + 31)/32)*sizeof(t_vpi_vecval); + rtn = (t_vpi_vecval *) malloc(num_bytes); + memcpy(rtn, val, num_bytes); + return rtn; +} + +/* Make a copy of a pointer to a strength structure. */ +static t_vpi_strengthval *strengthdup(t_vpi_strengthval *val) +{ + t_vpi_strengthval *rtn; + rtn = (t_vpi_strengthval *) malloc(sizeof(t_vpi_strengthval)); + *rtn = *val; + return rtn; +} + vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, s_vpi_time*when, PLI_INT32 flags) { assert(obj); - if (obj->vpi_type->vpi_put_value_ == 0) - return 0; - flags &= ~vpiReturnEvent; if (flags!=vpiNoDelay && flags!=vpiForceFlag && flags!=vpiReleaseFlag) { @@ -987,8 +1038,10 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, vpip_put_value_event*put = new vpip_put_value_event; put->handle = obj; put->value = *vp; + /* Since this is a scheduled put event we must copy any pointer + * data to keep it available until the event is actually run. */ switch (put->value.format) { - /* If this is scheduled make a copy of the string. */ + /* Copy the string items. */ case vpiBinStrVal: case vpiOctStrVal: case vpiDecStrVal: @@ -996,10 +1049,21 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, case vpiStringVal: put->value.value.str = strdup(put->value.value.str); break; - /* Do these also need to be copied? */ + /* Copy a time pointer item. */ case vpiTimeVal: + put->value.value.time = timedup(put->value.value.time); + break; + /* Copy a vector pointer item. */ case vpiVectorVal: + put->value.value.vector = vectordup(put->value.value.vector, + vpi_get(vpiSize, obj)); + break; + /* Copy a strength pointer item. */ case vpiStrengthVal: + put->value.value.strength = + strengthdup(put->value.value.strength); + break; + /* Everything thing else is already in the structure. */ default: break; } @@ -1008,7 +1072,7 @@ vpiHandle vpi_put_value(vpiHandle obj, s_vpi_value*vp, return 0; } - (obj->vpi_type->vpi_put_value_)(obj, vp, flags); + obj->vpi_put_value(vp, flags); return 0; } @@ -1024,11 +1088,11 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) if (vpi_trace) { fprintf(vpi_trace, "vpi_handle(vpiSysTfCall, 0) " - "-> %p (%s)\n", &vpip_cur_task->base, + "-> %p (%s)\n", vpip_cur_task, vpip_cur_task->defn->info.tfname); } - return &vpip_cur_task->base; + return vpip_cur_task; } if (ref == 0) { @@ -1037,18 +1101,7 @@ vpiHandle vpi_handle(PLI_INT32 type, vpiHandle ref) return 0; } - if (ref->vpi_type->handle_ == 0) { - - if (vpi_trace) { - fprintf(vpi_trace, "vpi_handle(%d, %p) -X\n", - (int)type, ref); - } - - return 0; - } - - assert(ref->vpi_type->handle_); - vpiHandle res = (ref->vpi_type->handle_)(type, ref); + vpiHandle res = ref->vpi_handle(type); if (vpi_trace) { fprintf(vpi_trace, "vpi_handle(%d, %p) -> %p\n", @@ -1099,8 +1152,8 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref) if (ref == 0) rtn = vpi_iterate_global(type); - else if (ref->vpi_type->iterate_) - rtn = (ref->vpi_type->iterate_)(type, ref); + else + rtn = ref->vpi_iterate(type); if (vpi_trace) { fprintf(vpi_trace, "vpi_iterate(%d, %p) ->%s\n", @@ -1113,18 +1166,13 @@ vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref) vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx) { assert(ref); - - if (ref->vpi_type->index_ == 0) - return 0; - - assert(ref->vpi_type->index_); - return (ref->vpi_type->index_)(ref, idx); + return ref->vpi_index(idx); } static vpiHandle find_name(const char *name, vpiHandle handle) { vpiHandle rtn = 0; - struct __vpiScope*ref = (struct __vpiScope*)handle; + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(handle); /* check module names */ if (!strcmp(name, vpi_get_str(vpiName, handle))) @@ -1260,16 +1308,12 @@ void vpi_get_delays(vpiHandle expr, p_vpi_delay delays) assert(expr); assert(delays); - if (expr->vpi_type->vpi_get_delays_) - { - (expr->vpi_type->vpi_get_delays_)(expr, delays); + expr->vpi_get_delays(delays); - if (vpi_trace) - { - fprintf(vpi_trace, - "vpi_get_delays(%p, %p) -->\n", expr, delays); - } - } + if (vpi_trace) { + fprintf(vpi_trace, + "vpi_get_delays(%p, %p) -->\n", expr, delays); + } } @@ -1278,16 +1322,12 @@ void vpi_put_delays(vpiHandle expr, p_vpi_delay delays) assert(expr ); assert(delays ); - if (expr->vpi_type->vpi_put_delays_) - { - (expr->vpi_type->vpi_put_delays_)(expr, delays); + expr->vpi_put_delays(delays); - if (vpi_trace) - { - fprintf(vpi_trace, - "vpi_put_delays(%p, %p) -->\n", expr, delays); - } - } + if (vpi_trace) { + fprintf(vpi_trace, + "vpi_put_delays(%p, %p) -->\n", expr, delays); + } } diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index b6b244fde..2f4237957 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -1,7 +1,7 @@ #ifndef __vpi_priv_H #define __vpi_priv_H /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -85,53 +85,35 @@ extern vpi_mode_t vpi_mode_flag; /* * This structure is the very base of a vpiHandle. Every handle - * structure starts with this structure, so that the library can + * structure is derived from this class so that the library can * internally pass the derived types as pointers to one of these. */ -struct __vpiHandle { - const struct __vpirt *vpi_type; +class __vpiHandle { + public: + inline __vpiHandle() { } + // The destructor is virtual so that dynamic types will work. + virtual ~__vpiHandle(); + + virtual int get_type_code(void) const =0; + virtual int vpi_get(int code); + virtual char* vpi_get_str(int code); + + virtual void vpi_get_value(p_vpi_value val); + virtual vpiHandle vpi_put_value(p_vpi_value val, int flags); + virtual vpiHandle vpi_handle(int code); + virtual vpiHandle vpi_iterate(int code); + virtual vpiHandle vpi_index(int idx); + virtual void vpi_get_delays(p_vpi_delay del); + virtual void vpi_put_delays(p_vpi_delay del); + + // Objects may have destroyer functions of their own. If so, + // then this virtual method will return a POINTER to that + // function. The pointer is used to "delete" the object, which + // is why the function itself cannot be a method. + typedef int (*free_object_fun_t)(vpiHandle); + virtual free_object_fun_t free_object_fun(void); }; -/* - * Objects with this structure are used to represent a type of - * vpiHandle. A specific object becomes of this type by holding a - * pointer to an instance of this structure. - */ -struct __vpirt { - int type_code; - - /* These methods extract information from the handle. */ - int (*vpi_get_)(int, vpiHandle); - char* (*vpi_get_str_)(int, vpiHandle); - void (*vpi_get_value_)(vpiHandle, p_vpi_value); - vpiHandle (*vpi_put_value_)(vpiHandle, p_vpi_value, int flags); - - /* These methods follow references. */ - vpiHandle (*handle_)(int, vpiHandle); - vpiHandle (*iterate_)(int, vpiHandle); - vpiHandle (*index_)(vpiHandle, int); - - /* This implements the vpi_free_object method. */ - int (*vpi_free_object_)(vpiHandle); - - /* - These two methods are used to read/write delay - values from/into modpath records - */ - void (*vpi_get_delays_)(vpiHandle, p_vpi_delay); - void (*vpi_put_delays_)(vpiHandle, p_vpi_delay); -}; - -/* - * In general a vpi object is a structure that contains the member - * "base" that is a __vpiHandle object. This template can convert any - * of those structures into a vpiHandle object. - */ -template vpiHandle vpi_handle(T obj) -{ return &obj->base; } - -template char*vpip_get_str(int code, T obj) -{ return obj->base.vpi_type->vpi_get_str_(code, vpi_handle(obj)); } /* * The vpiHandle for an iterator has this structure. The definition of @@ -144,8 +126,11 @@ template char*vpip_get_str(int code, T obj) * The free_args_flag member is true if when this iterator object is * released it must also free the args array. */ -struct __vpiIterator { - struct __vpiHandle base; +struct __vpiIterator : public __vpiHandle { + __vpiIterator(); + int get_type_code(void) const; + free_object_fun_t free_object_fun(void); + vpiHandle *args; unsigned nargs; unsigned next; @@ -157,42 +142,76 @@ extern vpiHandle vpip_make_iterator(unsigned nargs, vpiHandle*args, /* * This represents callback handles. There are some private types that - * are defined and used in vpi_callback.cc. + * are defined and used in vpi_callback.cc. The __vpiCallback are + * always used in association with vvp_vpi_callback objects. */ -struct __vpiCallback { - struct __vpiHandle base; - - // user supplied callback data - struct t_cb_data cb_data; - struct t_vpi_time cb_time; - struct t_vpi_value cb_value; - - // scheduled event - struct sync_cb* cb_sync; - - // The callback holder may use this for various purposes. - long extra_data; +struct __vpiCallback : public __vpiHandle { + __vpiCallback(); + ~__vpiCallback(); + int get_type_code(void) const; // Used for listing callbacks. struct __vpiCallback*next; + + // user supplied callback data + struct t_cb_data cb_data; +}; + +class value_callback : public __vpiCallback { + public: + explicit value_callback(p_cb_data data); + // Return true if the callback really is ready to be called + virtual bool test_value_callback_ready(void); + + public: + // user supplied callback data + struct t_vpi_time cb_time; + struct t_vpi_value cb_value; }; -extern struct __vpiCallback* new_vpi_callback(); -extern void delete_vpi_callback(struct __vpiCallback* ref); extern void callback_execute(struct __vpiCallback*cur); -struct __vpiSystemTime { - struct __vpiHandle base; - struct __vpiScope *scope; +struct __vpiSystemTime : public __vpiHandle { + __vpiSystemTime(); + int get_type_code(void) const; + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_handle(int code); + + struct __vpiScope*scope; }; +struct __vpiScopedTime : public __vpiSystemTime { + __vpiScopedTime(); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); +}; +struct __vpiScopedSTime : public __vpiSystemTime { + __vpiScopedSTime(); + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); +}; +struct __vpiScopedRealtime : public __vpiSystemTime { + __vpiScopedRealtime(); + int vpi_get(int code); + char*vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); +}; + + /* * Scopes are created by .scope statements in the source. These * objects hold the items and properties that are knowingly bound to a * scope. */ -struct __vpiScope { - struct __vpiHandle base; +struct __vpiScope : public __vpiHandle { + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + struct __vpiScope *scope; /* The scope has a name. */ const char*name; @@ -204,11 +223,11 @@ struct __vpiScope { bool is_automatic; bool is_cell; /* The scope has a system time of its own. */ - struct __vpiSystemTime scoped_time; - struct __vpiSystemTime scoped_stime; - struct __vpiSystemTime scoped_realtime; + struct __vpiScopedTime scoped_time; + struct __vpiScopedSTime scoped_stime; + struct __vpiScopedRealtime scoped_realtime; /* Keep an array of internal scope items. */ - struct __vpiHandle**intern; + class __vpiHandle**intern; unsigned nintern; /* Keep an array of items to be automatically allocated */ struct automatic_hooks_s**item; @@ -221,6 +240,9 @@ struct __vpiScope { std::set threads; signed int time_units :8; signed int time_precision :8; + + protected: + inline __vpiScope() { } }; extern struct __vpiScope* vpip_peek_current_scope(void); @@ -230,7 +252,7 @@ extern struct __vpiScope* vpip_peek_context_scope(void); extern unsigned vpip_add_item_to_context(automatic_hooks_s*item, struct __vpiScope*scope); extern vpiHandle vpip_make_root_iterator(void); -extern void vpip_make_root_iterator(struct __vpiHandle**&table, +extern void vpip_make_root_iterator(class __vpiHandle**&table, unsigned&ntable); /* @@ -238,8 +260,14 @@ extern void vpip_make_root_iterator(struct __vpiHandle**&table, * distinguished by the vpiType code. They also have a parent scope, * a declared name and declaration indices. */ -struct __vpiSignal { - struct __vpiHandle base; +struct __vpiSignal : public __vpiHandle { + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + #ifdef CHECK_WITH_VALGRIND struct __vpiSignal *pool; #endif @@ -258,6 +286,15 @@ struct __vpiSignal { unsigned is_netarray : 1; // This is word of a net array /* The represented value is here. */ vvp_net_t*node; + + public: + static void*operator new(std::size_t size); + static void operator delete(void*); // not implemented + protected: + inline __vpiSignal() { } + private: // Not implemented + static void*operator new[] (std::size_t size); + static void operator delete[](void*); }; extern unsigned vpip_size(__vpiSignal *sig); extern struct __vpiScope* vpip_scope(__vpiSignal*sig); @@ -275,8 +312,15 @@ extern vpiHandle vpip_make_net4(const char*name, int msb, int lsb, * This is used by system calls to represent a bit/part select of * a simple variable or constant array word. */ -struct __vpiPV { - struct __vpiHandle base; +struct __vpiPV : public __vpiHandle { + __vpiPV(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle parent; vvp_net_t*net; vpiHandle sbase; @@ -290,26 +334,30 @@ extern vpiHandle vpip_make_PV(char*name, vpiHandle handle, int width); extern vpiHandle vpip_make_PV(char*name, int tbase, int twid, char*is_signed, int width); -extern struct __vpiPV* vpip_PV_from_handle(vpiHandle obj); -extern void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle obj); +struct __vpiModPathTerm : public __vpiHandle { + __vpiModPathTerm(); + int get_type_code(void) const; + int vpi_get(int code); + vpiHandle vpi_handle(int code); - -/* - * This function safely converts a vpiHandle back to a - * __vpiSignal. Return a nil if the type is not appropriate. - */ -extern __vpiSignal* vpip_signal_from_handle(vpiHandle obj); - - -struct __vpiModPathTerm { - struct __vpiHandle base; vpiHandle expr; /* The value returned by vpi_get(vpiEdge, ...); */ int edge; }; -struct __vpiModPathSrc { - struct __vpiHandle base; +struct __vpiModPathSrc : public __vpiHandle { + __vpiModPathSrc(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + vpiHandle vpi_index(int idx); + void vpi_get_delays(p_vpi_delay del); + void vpi_put_delays(p_vpi_delay del); + free_object_fun_t free_object_fun(void); + struct __vpiModPath *dest; int type; @@ -340,9 +388,6 @@ struct __vpiModPath { vvp_net_t *input_net ; }; -extern struct __vpiModPathTerm* vpip_modpath_term_from_handle(vpiHandle ref); -extern struct __vpiModPathSrc* vpip_modpath_src_from_handle(vpiHandle ref); - /* * The Function is used to create the vpiHandle @@ -360,22 +405,35 @@ extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ; * passed in will be saved, so the caller must allocate it (or not * free it) after it is handed to this function. */ -struct __vpiNamedEvent { - struct __vpiHandle base; - /* base name of the event object */ - const char*name; - /* Parent scope of this object. */ - struct __vpiScope*scope; +class __vpiNamedEvent : public __vpiHandle { + + public: + __vpiNamedEvent(__vpiScope*scope, const char*name); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + vpiHandle vpi_handle(int code); + + inline void add_vpi_callback(__vpiCallback*cb) + { cb->next = callbacks_; + callbacks_ = cb; + } + + void run_vpi_callbacks(void); + /* The functor, used for %set operations. */ vvp_net_t*funct; + + private: + /* base name of the event object */ + const char*name_; + /* Parent scope of this object. */ + struct __vpiScope*scope_; /* List of callbacks interested in this event. */ - struct __vpiCallback*callbacks; + __vpiCallback*callbacks_; }; extern vpiHandle vpip_make_named_event(const char*name, vvp_net_t*f); -extern void vpip_run_named_event_callbacks(vpiHandle ref); -extern void vpip_real_value_change(struct __vpiCallback*cbh, - vpiHandle ref); /* * Memory is an array of bits that is accessible in N-bit chunks, with @@ -389,8 +447,16 @@ extern bool is_net_array(vpiHandle obj); /* * These are the various variable types. */ -struct __vpiRealVar { - struct __vpiHandle base; +struct __vpiRealVar : public __vpiHandle { + __vpiRealVar(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + vpiHandle vpi_iterate(int code); + union { // The scope or parent array that contains me. vpiHandle parent; struct __vpiScope* scope; @@ -406,7 +472,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 @@ -426,8 +492,10 @@ extern struct __vpiRealVar* vpip_realvar_from_handle(vpiHandle obj); * additional part is the vbit/vwid that is used by the put of the * system function call to place the values in the vthread bit space. */ -struct __vpiUserSystf { - struct __vpiHandle base; +struct __vpiUserSystf : public __vpiHandle { + __vpiUserSystf(); + int get_type_code(void) const; + s_vpi_systf_data info; bool is_user_defn; }; @@ -437,8 +505,8 @@ extern vpiHandle vpip_make_systf_iterator(void); extern struct __vpiUserSystf* vpip_find_systf(const char*name); -struct __vpiSysTaskCall { - struct __vpiHandle base; +struct __vpiSysTaskCall : public __vpiHandle { + struct __vpiScope* scope; struct __vpiUserSystf*defn; unsigned nargs; @@ -452,30 +520,31 @@ struct __vpiSysTaskCall { unsigned file_idx; unsigned lineno; bool put_value; + protected: + inline __vpiSysTaskCall() { } }; extern struct __vpiSysTaskCall*vpip_cur_task; /* - * These are implemented in vpi_const.cc. These are vpiHandles for - * constants. - * * The persistent flag to vpip_make_string_const causes the created * handle to be persistent. This is necessary for cases where the * string handle may be reused, which is the normal case. + * + * When constructing with a string, the class takes possession of the + * text value string, and will delete it in the constructor. */ -struct __vpiStringConst { - struct __vpiHandle base; - char*value; - size_t value_len; -}; vpiHandle vpip_make_string_const(char*text, bool persistent =true); vpiHandle vpip_make_string_param(char*name, char*value, long file_idx, long lineno); -struct __vpiBinaryConst { - struct __vpiHandle base; +struct __vpiBinaryConst : public __vpiHandle { + __vpiBinaryConst(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + vvp_vector4_t bits; /* TRUE if this constant is signed. */ int signed_flag :1; @@ -488,16 +557,22 @@ vpiHandle vpip_make_binary_param(char*name, const vvp_vector4_t&bits, bool signed_flag, long file_idx, long lineno); -struct __vpiDecConst { - struct __vpiHandle base; +struct __vpiDecConst : public __vpiHandle { + __vpiDecConst(int val =0); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + int value; }; -vpiHandle vpip_make_dec_const(int value); -vpiHandle vpip_make_dec_const(struct __vpiDecConst*obj, int value); - -struct __vpiRealConst { - struct __vpiHandle base; +class __vpiRealConst : public __vpiHandle { + public: + __vpiRealConst(double); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + public: double value; }; @@ -519,6 +594,7 @@ vpiHandle vpip_make_vthr_A(char*label, char*symbol); vpiHandle vpip_make_vthr_A(char*label, unsigned tbase, unsigned twid, char*is_signed); vpiHandle vpip_make_vthr_A(char*label, vpiHandle handle); +vpiHandle vpip_make_vthr_APV(char*label, unsigned index, unsigned bit, unsigned wid); /* * This function is called before any compilation to load VPI diff --git a/vvp/vpi_real.cc b/vvp/vpi_real.cc index 72812ecca..09f9a96b5 100644 --- a/vvp/vpi_real.cc +++ b/vvp/vpi_real.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2012 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 @@ -30,20 +30,10 @@ # include # include "ivl_alloc.h" -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 = vpip_realvar_from_handle(ref); + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); switch (code) { case vpiArray: @@ -64,9 +54,8 @@ static int real_var_get(int code, vpiHandle ref) static char* real_var_get_str(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); if (code == vpiFile) { // Not implemented for now! return simple_set_rbuf_str(file_names[0]); @@ -84,16 +73,15 @@ static char* real_var_get_str(int code, vpiHandle ref) ixs = NULL; } - char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs); + char *rbuf = generic_get_str(code, vpip_scope(rfp), nm, ixs); free(nm); return rbuf; } static vpiHandle real_var_get_handle(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); switch (code) { @@ -104,7 +92,7 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref) return rfp->is_netarray ? rfp->id.index : 0; case vpiScope: - return &(vpip_scope(rfp)->base); + return vpip_scope(rfp); case vpiModule: return vpip_module(vpip_scope(rfp)); @@ -115,13 +103,11 @@ static vpiHandle real_var_get_handle(int code, vpiHandle ref) static vpiHandle real_var_iterate(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiRealVar); - - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); if (code == vpiIndex) { - return rfp->is_netarray ? (rfp->id.index->vpi_type->iterate_) - (code, rfp->id.index) : 0; + return rfp->is_netarray ? rfp->id.index->vpi_iterate(code) : 0; } return 0; @@ -129,10 +115,9 @@ static vpiHandle real_var_iterate(int code, vpiHandle ref) static void real_var_get_value(vpiHandle ref, s_vpi_value*vp) { - assert(ref->vpi_type->type_code == vpiRealVar); + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); + assert(rfp); - struct __vpiRealVar*rfp - = (struct __vpiRealVar*)ref; vvp_signal_value*fil = dynamic_cast(rfp->net->fil); @@ -141,67 +126,60 @@ static void real_var_get_value(vpiHandle ref, s_vpi_value*vp) static vpiHandle real_var_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiRealVar); - double result = real_from_vpi_value(vp); - struct __vpiRealVar*rfp = (struct __vpiRealVar*)ref; + struct __vpiRealVar*rfp = dynamic_cast<__vpiRealVar*>(ref); assert(rfp); vvp_net_ptr_t destination (rfp->net, 0); vvp_send_real(destination, result, vthread_get_wt_context()); return 0; } -static const struct __vpirt vpip_real_var_rt = { - vpiRealVar, +inline __vpiRealVar::__vpiRealVar() +{ } - real_var_get, - real_var_get_str, - real_var_get_value, - real_var_put_value, +int __vpiRealVar::get_type_code(void) const +{ return vpiRealVar; } - real_var_get_handle, - real_var_iterate, - 0, - 0, - 0, - 0 -}; +int __vpiRealVar::vpi_get(int code) +{ return real_var_get(code, this); } -void vpip_real_value_change(struct __vpiCallback*cbh, - vpiHandle ref) -{ - struct __vpiRealVar*rfp - = (struct __vpiRealVar*)ref; - vvp_vpi_callback*obj = dynamic_cast(rfp->net->fil); - assert(obj); +char* __vpiRealVar::vpi_get_str(int code) +{ return real_var_get_str(code, this); } - obj->add_vpi_callback(cbh); -} +void __vpiRealVar::vpi_get_value(p_vpi_value val) +{ real_var_get_value(this, val); } + +vpiHandle __vpiRealVar::vpi_put_value(p_vpi_value val, int flags) +{ return real_var_put_value(this, val, flags); } + +vpiHandle __vpiRealVar::vpi_handle(int code) +{ return real_var_get_handle(code, this); } + +vpiHandle __vpiRealVar::vpi_iterate(int code) +{ return real_var_iterate(code, this); } vpiHandle vpip_make_real_var(const char*name, vvp_net_t*net) { - struct __vpiRealVar*obj = (struct __vpiRealVar*) - malloc(sizeof(struct __vpiRealVar)); + struct __vpiRealVar*obj = new __vpiRealVar; - obj->base.vpi_type = &vpip_real_var_rt; obj->id.name = name ? vpip_name_string(name) : 0; obj->is_netarray = 0; obj->net = net; obj->within.scope = vpip_peek_current_scope(); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND void real_delete(vpiHandle item) { - struct __vpiRealVar*obj = (struct __vpiRealVar*) item; + struct __vpiRealVar*obj = dynamic_cast<__vpiRealVar*>(item); assert(obj->net->fil); obj->net->fil->clear_all_callbacks(); vvp_net_delete(obj->net); - free(obj); + delete obj; } #endif diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 33bb34ace..a93e2aa0a 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -41,7 +41,7 @@ vpiHandle vpip_make_root_iterator(void) vpip_root_table_ptr, false); } -void vpip_make_root_iterator(struct __vpiHandle**&table, unsigned&ntable) +void vpip_make_root_iterator(__vpiHandle**&table, unsigned&ntable) { table = vpip_root_table_ptr; ntable = vpip_root_table_cnt; @@ -117,20 +117,10 @@ void root_table_delete(void) } #endif -static bool handle_is_scope(vpiHandle obj) -{ - return (obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork); -} - static int scope_get(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - - assert(handle_is_scope(obj)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(obj); switch (code) { case vpiCellInstance: @@ -189,9 +179,8 @@ static const char* scope_get_type(int code) static char* scope_get_str(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - - assert(handle_is_scope(obj)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(ref); char buf[4096]; // XXX is a fixed buffer size really reliable? const char *p=0; @@ -231,21 +220,16 @@ static char* scope_get_str(int code, vpiHandle obj) static vpiHandle scope_get_handle(int code, vpiHandle obj) { - assert((obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork)); - - struct __vpiScope*rfp = (struct __vpiScope*)obj; + struct __vpiScope*rfp = dynamic_cast<__vpiScope*>(obj); + assert(rfp); switch (code) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiModule: - return &rfp->scope->base; + return rfp->scope; } return 0; @@ -291,7 +275,7 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) vpiHandle*args; for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1) - if (compare_types(code, ref->intern[idx]->vpi_type->type_code)) + if (compare_types(code, ref->intern[idx]->get_type_code())) mcnt += 1; if (mcnt == 0) @@ -299,7 +283,7 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) args = (vpiHandle*)calloc(mcnt, sizeof(vpiHandle)); for (unsigned idx = 0 ; idx < ref->nintern ; idx += 1) - if (compare_types(code, ref->intern[idx]->vpi_type->type_code)) + if (compare_types(code, ref->intern[idx]->get_type_code())) args[ncnt++] = ref->intern[idx]; assert(ncnt == mcnt); @@ -315,85 +299,49 @@ static vpiHandle module_iter_subset(int code, struct __vpiScope*ref) */ static vpiHandle module_iter(int code, vpiHandle obj) { - struct __vpiScope*ref = (struct __vpiScope*)obj; - assert((obj->vpi_type->type_code == vpiModule) - || (obj->vpi_type->type_code == vpiFunction) - || (obj->vpi_type->type_code == vpiTask) - || (obj->vpi_type->type_code == vpiNamedBegin) - || (obj->vpi_type->type_code == vpiNamedFork)); + struct __vpiScope*ref = dynamic_cast<__vpiScope*>(obj); + assert(ref); return module_iter_subset(code, ref); } -static const struct __vpirt vpip_scope_module_rt = { - vpiModule, - scope_get, - scope_get_str, - 0, - 0, - scope_get_handle, - module_iter, - 0, - 0, - 0, - 0 +int __vpiScope::vpi_get(int code) +{ return scope_get(code, this); } + +char*__vpiScope::vpi_get_str(int code) +{ return scope_get_str(code, this); } + +vpiHandle __vpiScope::vpi_handle(int code) +{ return scope_get_handle(code, this); } + +vpiHandle __vpiScope::vpi_iterate(int code) +{ return module_iter(code, this); } + + +struct vpiScopeModule : public __vpiScope { + inline vpiScopeModule() { } + int get_type_code(void) const { return vpiModule; } }; -static const struct __vpirt vpip_scope_task_rt = { - vpiTask, - scope_get, - scope_get_str, - 0, - 0, - scope_get_handle, - module_iter, - 0, - 0, - 0, - 0 +struct vpiScopeTask : public __vpiScope { + inline vpiScopeTask() { } + int get_type_code(void) const { return vpiTask; } }; -static const struct __vpirt vpip_scope_function_rt = { - vpiFunction, - scope_get, - scope_get_str, - 0, - 0, - scope_get_handle, - module_iter, - 0, - 0, - 0, - 0 +struct vpiScopeFunction : public __vpiScope { + inline vpiScopeFunction() { } + int get_type_code(void) const { return vpiFunction; } }; -static const struct __vpirt vpip_scope_begin_rt = { - vpiNamedBegin, - scope_get, - scope_get_str, - 0, - 0, - scope_get_handle, - module_iter, - 0, - 0, - 0, - 0 +struct vpiScopeBegin : public __vpiScope { + inline vpiScopeBegin() { } + int get_type_code(void) const { return vpiNamedBegin; } }; -static const struct __vpirt vpip_scope_fork_rt = { - vpiNamedFork, - scope_get, - scope_get_str, - 0, - 0, - scope_get_handle, - module_iter, - 0, - 0, - 0, - 0 +struct vpiScopeFork : public __vpiScope { + inline vpiScopeFork() { } + int get_type_code(void) const { return vpiNamedFork; } }; /* @@ -429,40 +377,36 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, char*parent, long file_idx, long lineno, long def_file_idx, long def_lineno, long is_cell) { - struct __vpiScope*scope = new struct __vpiScope; count_vpi_scopes += 1; - char*base_type = 0; + char*base_type; + bool is_automatic; if (strncmp(type,"auto",4) == 0) { - scope->is_automatic = true; + is_automatic = true; base_type = &type[4]; } else { - scope->is_automatic = false; + is_automatic = false; base_type = &type[0]; } - if (is_cell) scope->is_cell = true; - else scope->is_cell = false; - + struct __vpiScope*scope; if (strcmp(base_type,"module") == 0) { - scope->base.vpi_type = &vpip_scope_module_rt; + scope = new vpiScopeModule; } else if (strcmp(base_type,"function") == 0) { - scope->base.vpi_type = &vpip_scope_function_rt; + scope = new vpiScopeFunction; } else if (strcmp(base_type,"task") == 0) { - scope->base.vpi_type = &vpip_scope_task_rt; + scope = new vpiScopeTask; } else if (strcmp(base_type,"fork") == 0) { - scope->base.vpi_type = &vpip_scope_fork_rt; + scope = new vpiScopeFork; } else if (strcmp(base_type,"begin") == 0) { - scope->base.vpi_type = &vpip_scope_begin_rt; + scope = new vpiScopeBegin; } else if (strcmp(base_type,"generate") == 0) { - scope->base.vpi_type = &vpip_scope_begin_rt; + scope = new vpiScopeBegin; } else { - scope->base.vpi_type = &vpip_scope_module_rt; + scope = new vpiScopeModule; assert(0); } - assert(scope->base.vpi_type); - scope->name = vpip_name_string(name); if (tname) scope->tname = vpip_name_string(tname); else scope->tname = vpip_name_string(""); @@ -470,6 +414,7 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, scope->lineno = (unsigned) lineno; scope->def_file_idx = (unsigned) def_file_idx; scope->def_lineno = (unsigned) def_lineno; + scope->is_automatic = is_automatic; scope->intern = 0; scope->nintern = 0; scope->item = 0; @@ -477,9 +422,12 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, scope->live_contexts = 0; scope->free_contexts = 0; + if (is_cell) scope->is_cell = true; + else scope->is_cell = false; + current_scope = scope; - compile_vpi_symbol(label, &scope->base); + compile_vpi_symbol(label, scope); free(label); free(type); @@ -490,9 +438,9 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, static vpiHandle obj; compile_vpi_lookup(&obj, parent); assert(obj); - struct __vpiScope*sp = (struct __vpiScope*) obj; - vpip_attach_to_scope(sp, &scope->base); - scope->scope = (struct __vpiScope*)obj; + struct __vpiScope*sp = dynamic_cast<__vpiScope*>(obj); + vpip_attach_to_scope(sp, scope); + scope->scope = dynamic_cast<__vpiScope*>(obj); /* Inherit time units and precision from the parent scope. */ scope->time_units = sp->time_units; @@ -504,7 +452,7 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, unsigned cnt = vpip_root_table_cnt + 1; vpip_root_table_ptr = (vpiHandle*) realloc(vpip_root_table_ptr, cnt * sizeof(vpiHandle)); - vpip_root_table_ptr[vpip_root_table_cnt] = &scope->base; + vpip_root_table_ptr[vpip_root_table_cnt] = scope; vpip_root_table_cnt = cnt; /* Root scopes inherit time_units and precision from the diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 65011380b..3478fed40 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -131,6 +131,10 @@ char *generic_get_str(int code, vpiHandle ref, const char *name, const char *ind return res; } +static vpiHandle fill_in_net4(struct __vpiSignal*obj, + const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node); + /* * The standard formating/conversion routines. * They work with full or partial signals. @@ -463,7 +467,7 @@ static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid, { long end = base + (signed)wid; unsigned int obit = 0; - unsigned hwid = (wid - 1)/32 + 1; + unsigned hwid = (wid + 31)/32; s_vpi_vecval *op = (p_vpi_vecval) need_result_buf(hwid * sizeof(s_vpi_vecval), RBUF_VAL); @@ -505,31 +509,12 @@ static void format_vpiVectorVal(vvp_signal_value*sig, int base, unsigned wid, } } -struct __vpiSignal* vpip_signal_from_handle(vpiHandle ref) -{ - switch (ref->vpi_type->type_code) { - case vpiNet: - case vpiReg: - /* This handles both reg and logic */ - case vpiIntegerVar: - case vpiByteVar: - case vpiShortIntVar: - case vpiIntVar: - case vpiLongIntVar: - case vpiBitVar: - return (struct __vpiSignal*)ref; - - default: - return 0; - } -} - /* * implement vpi_get for vpiReg objects. */ static int signal_get(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); switch (code) { @@ -559,7 +544,7 @@ static int signal_get(int code, vpiHandle ref) return rfp->lsb - rfp->msb + 1; case vpiNetType: - if (ref->vpi_type->type_code==vpiNet) + if (ref->get_type_code()==vpiNet) return vpiWire; else return vpiUndefined; @@ -589,7 +574,7 @@ static int signal_get(int code, vpiHandle ref) static char* signal_get_str(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); if (code == vpiFile) { // Not implemented for now! @@ -611,14 +596,14 @@ static char* signal_get_str(int code, vpiHandle ref) } /* The scope information is added here for vpiFullName. */ - char *rbuf = generic_get_str(code, &(vpip_scope(rfp)->base), nm, ixs); + char *rbuf = generic_get_str(code, vpip_scope(rfp), nm, ixs); free(nm); return rbuf; } static vpiHandle signal_get_handle(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); switch (code) { @@ -630,7 +615,7 @@ static vpiHandle signal_get_handle(int code, vpiHandle ref) return rfp->is_netarray? rfp->id.index : 0; case vpiScope: - return &(vpip_scope(rfp)->base); + return vpip_scope(rfp); case vpiModule: return vpip_module(vpip_scope(rfp)); @@ -641,7 +626,7 @@ static vpiHandle signal_get_handle(int code, vpiHandle ref) static vpiHandle signal_iterate(int code, vpiHandle ref) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); if (code == vpiIndex) { @@ -667,7 +652,7 @@ static unsigned signal_width(const struct __vpiSignal*rfp) */ static void signal_get_value(vpiHandle ref, s_vpi_value*vp) { - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); unsigned wid = signal_width(rfp); @@ -773,7 +758,7 @@ static vvp_vector4_t from_stringval(const char*str, unsigned wid) static vpiHandle signal_put_value(vpiHandle ref, s_vpi_value*vp, int flags) { unsigned wid; - struct __vpiSignal*rfp = vpip_signal_from_handle(ref); + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); /* If this is a release, then we are not really putting a @@ -875,116 +860,62 @@ vvp_vector4_t vec4_from_vpi_value(s_vpi_value*vp, unsigned wid) return val; } -static const struct __vpirt vpip_reg_rt = { - vpiReg, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +int __vpiSignal::vpi_get(int code) +{ return signal_get(code, this); } + +char* __vpiSignal::vpi_get_str(int code) +{ return signal_get_str(code, this); } + +void __vpiSignal::vpi_get_value(p_vpi_value val) +{ signal_get_value(this, val); } + +vpiHandle __vpiSignal::vpi_put_value(p_vpi_value val, int flags) +{ return signal_put_value(this, val, flags); } + +vpiHandle __vpiSignal::vpi_handle(int code) +{ return signal_get_handle(code, this); } + +vpiHandle __vpiSignal::vpi_iterate(int code) +{ return signal_iterate(code, this); } + +struct signal_reg : public __vpiSignal { + inline signal_reg() { } + int get_type_code(void) const { return vpiReg; } }; -static const struct __vpirt vpip_integer_rt = { - vpiIntegerVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_integer : public __vpiSignal { + inline signal_integer() { } + int get_type_code(void) const { return vpiIntegerVar; } }; -static const struct __vpirt vpip_net_rt = { - vpiNet, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_net : public __vpiSignal { + inline signal_net() { } + int get_type_code(void) const { return vpiNet; } }; -static const struct __vpirt vpip_byte_rt = { - vpiByteVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_byte : public __vpiSignal { + inline signal_byte() { } + int get_type_code(void) const { return vpiByteVar; } }; -static const struct __vpirt vpip_bitvar_rt = { - vpiBitVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_bitvar : public __vpiSignal { + inline signal_bitvar() { } + int get_type_code(void) const { return vpiBitVar; } }; -static const struct __vpirt vpip_shortint_rt = { - vpiShortIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_shortint : public __vpiSignal { + inline signal_shortint() { } + int get_type_code(void) const { return vpiShortIntVar; } }; -static const struct __vpirt vpip_int_rt = { - vpiIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_int : public __vpiSignal { + inline signal_int() { } + int get_type_code(void) const { return vpiIntVar; } }; -static const struct __vpirt vpip_longint_rt = { - vpiLongIntVar, - signal_get, - signal_get_str, - signal_get_value, - signal_put_value, - signal_get_handle, - signal_iterate, - 0, - 0, - 0, - 0 +struct signal_longint : public __vpiSignal { + inline signal_longint() { } + int get_type_code(void) const { return vpiLongIntVar; } }; @@ -995,9 +926,8 @@ static const struct __vpirt vpip_longint_rt = { */ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb,lsb, true, vec); - obj->vpi_type = &vpip_integer_rt; - return obj; + __vpiSignal*obj = new signal_integer; + return fill_in_net4(obj, name, msb, lsb, true, vec); } /* @@ -1006,37 +936,37 @@ vpiHandle vpip_make_int4(const char*name, int msb, int lsb, vvp_net_t*vec) vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb, lsb, signed_flag, vec); + __vpiSignal*obj; // All unsigned 2-state variables are a vpiBitVar. All 2-state // variables with a non-zero lsb are also a vpiBitVar. if ((! signed_flag) || (lsb != 0) ) { - obj->vpi_type = &vpip_bitvar_rt; + obj = new signal_bitvar; } else { // These could also be bit declarations with matching // information, but for now they get the apparent type. switch (msb) { case 7: - obj->vpi_type = &vpip_byte_rt; + obj = new signal_byte; break; case 15: - obj->vpi_type = &vpip_shortint_rt; + obj = new signal_shortint; break; case 31: - obj->vpi_type = &vpip_int_rt; + obj = new signal_int; break; case 63: - obj->vpi_type = &vpip_longint_rt; + obj = new signal_longint; break; default: // Every other type of bit vector is a vpiBitVar with // array dimensions. - obj->vpi_type = &vpip_bitvar_rt; + obj = new signal_bitvar; break; } } - return obj; + return fill_in_net4(obj, name, msb, lsb, signed_flag, vec); } /* @@ -1045,9 +975,8 @@ vpiHandle vpip_make_int2(const char*name, int msb, int lsb, bool signed_flag, vpiHandle vpip_make_var4(const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*vec) { - vpiHandle obj = vpip_make_net4(name, msb,lsb, signed_flag, vec); - obj->vpi_type = &vpip_reg_rt; - return obj; + __vpiSignal*obj = new signal_reg; + return fill_in_net4(obj, name, msb, lsb, signed_flag, vec); } #ifdef CHECK_WITH_VALGRIND @@ -1057,30 +986,35 @@ static unsigned long signal_count = 0; static unsigned long signal_dels = 0; #endif -static struct __vpiSignal* allocate_vpiSignal(void) +struct vpiSignal_plug { + unsigned char space[sizeof (struct __vpiSignal)]; +}; + +void* __vpiSignal::operator new(size_t siz) { - static struct __vpiSignal*alloc_array = 0; + assert(siz == sizeof(struct vpiSignal_plug)); + static struct vpiSignal_plug*alloc_array = 0; static unsigned alloc_index = 0; const unsigned alloc_count = 512; if ((alloc_array == 0) || (alloc_index == alloc_count)) { - alloc_array = (struct __vpiSignal*) - calloc(alloc_count, sizeof(struct __vpiSignal)); + alloc_array = (struct vpiSignal_plug*) + calloc(alloc_count, sizeof(struct vpiSignal_plug)); alloc_index = 0; #ifdef CHECK_WITH_VALGRIND VALGRIND_MAKE_MEM_NOACCESS(alloc_array, alloc_count * - sizeof(struct __vpiSignal)); + sizeof(struct vpiSignal_plug)); VALGRIND_CREATE_MEMPOOL(alloc_array, 0, 1); signal_pool_count += 1; - signal_pool = (__vpiSignal **) realloc(signal_pool, - signal_pool_count*sizeof(__vpiSignal **)); + signal_pool = (vpiSignal_plug **) realloc(signal_pool, + signal_pool_count*sizeof(vpiSignal_plug **)); signal_pool[signal_pool_count-1] = alloc_array; #endif } - struct __vpiSignal*cur = alloc_array + alloc_index; + struct vpiSignal_plug*cur = alloc_array + alloc_index; #ifdef CHECK_WITH_VALGRIND - VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct __vpiSignal)); + VALGRIND_MEMPOOL_ALLOC(alloc_array, cur, sizeof(struct vpiSignal_plug)); cur->pool = alloc_array; signal_count += 1; #endif @@ -1088,6 +1022,11 @@ static struct __vpiSignal* allocate_vpiSignal(void) return cur; } +void __vpiSignal::operator delete(void*) +{ + assert(0); +} + #ifdef CHECK_WITH_VALGRIND void signal_delete(vpiHandle item) { @@ -1125,11 +1064,10 @@ void signal_pool_delete() * The name is the PLI name for the object. If it is an array it is * []. */ -vpiHandle vpip_make_net4(const char*name, int msb, int lsb, - bool signed_flag, vvp_net_t*node) +static vpiHandle fill_in_net4(struct __vpiSignal*obj, + const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node) { - struct __vpiSignal*obj = allocate_vpiSignal(); - obj->base.vpi_type = &vpip_net_rt; obj->id.name = name? vpip_name_string(name) : 0; obj->msb = msb; obj->lsb = lsb; @@ -1144,7 +1082,14 @@ vpiHandle vpip_make_net4(const char*name, int msb, int lsb, count_vpi_nets += 1; - return &obj->base; + return obj; +} + +vpiHandle vpip_make_net4(const char*name, int msb, int lsb, + bool signed_flag, vvp_net_t*node) +{ + struct __vpiSignal*obj = new signal_net; + return fill_in_net4(obj, name, msb, lsb, signed_flag, node); } static int PV_get_base(struct __vpiPV*rfp) @@ -1205,8 +1150,8 @@ static int PV_get_base(struct __vpiPV*rfp) static int PV_get(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); int rval = 0; switch (code) { @@ -1246,8 +1191,8 @@ static int PV_get(int code, vpiHandle ref) static char* PV_get_str(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); switch (code) { case vpiFile: // Not implemented for now! @@ -1276,8 +1221,8 @@ static char* PV_get_str(int code, vpiHandle ref) static void PV_get_value(vpiHandle ref, p_vpi_value vp) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); vvp_signal_value*sig = dynamic_cast(rfp->net->fil); assert(sig); @@ -1334,8 +1279,8 @@ static void PV_get_value(vpiHandle ref, p_vpi_value vp) static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); vvp_signal_value*sig = dynamic_cast(rfp->net->fil); assert(sig); @@ -1347,6 +1292,7 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) vvp_vector4_t val = vec4_from_vpi_value(vp, width); + fprintf(stderr, "XXXX PV_put_value(..)\n"); /* * If the base is less than zero then trim off any unneeded * lower bits. @@ -1382,8 +1328,8 @@ static vpiHandle PV_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle PV_get_handle(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code==vpiPartSelect); - struct __vpiPV*rfp = (struct __vpiPV*)ref; + struct __vpiPV*rfp = dynamic_cast<__vpiPV*>(ref); + assert(rfp); switch (code) { case vpiParent: @@ -1396,32 +1342,30 @@ static vpiHandle PV_get_handle(int code, vpiHandle ref) return 0; } -static const struct __vpirt vpip_PV_rt = { - vpiPartSelect, - PV_get, - PV_get_str, - PV_get_value, - PV_put_value, - PV_get_handle, - 0, - 0, - 0, - 0, - 0 -}; +inline __vpiPV::__vpiPV() +{ } -struct __vpiPV* vpip_PV_from_handle(vpiHandle obj) -{ - if (obj->vpi_type->type_code == vpiPartSelect) - return (__vpiPV*) obj; - else - return 0; -} +int __vpiPV::get_type_code(void) const +{ return vpiPartSelect; } + +int __vpiPV::vpi_get(int code) +{ return PV_get(code, this); } + +char* __vpiPV::vpi_get_str(int code) +{ return PV_get_str(code, this); } + +void __vpiPV::vpi_get_value(p_vpi_value val) +{ PV_get_value(this, val); } + +vpiHandle __vpiPV::vpi_put_value(p_vpi_value val, int flags) +{ return PV_put_value(this, val, flags); } + +vpiHandle __vpiPV::vpi_handle(int code) +{ return PV_get_handle(code, this); } vpiHandle vpip_make_PV(char*var, int base, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = 0; obj->tbase = base; @@ -1430,13 +1374,12 @@ vpiHandle vpip_make_PV(char*var, int base, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, char*symbol, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); compile_vpi_lookup(&obj->sbase, symbol); obj->tbase = 0; @@ -1445,13 +1388,12 @@ vpiHandle vpip_make_PV(char*var, char*symbol, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = handle; obj->tbase = 0; @@ -1460,13 +1402,12 @@ vpiHandle vpip_make_PV(char*var, vpiHandle handle, int width) obj->net = 0; functor_ref_lookup(&obj->net, var); - return &obj->base; + return obj; } vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width) { - struct __vpiPV*obj = (struct __vpiPV*) malloc(sizeof(struct __vpiPV)); - obj->base.vpi_type = &vpip_PV_rt; + struct __vpiPV*obj = new __vpiPV; obj->parent = vvp_lookup_handle(var); obj->sbase = 0; obj->tbase = tbase; @@ -1478,26 +1419,13 @@ vpiHandle vpip_make_PV(char*var, int tbase, int twid, char*is_signed, int width) delete [] is_signed; - return &obj->base; -} - -void vpip_part_select_value_change(struct __vpiCallback*cbh, vpiHandle ref) -{ - struct __vpiPV*obj = vpip_PV_from_handle(ref); - assert(obj); - - vvp_vpi_callback*sig_fil; - sig_fil = dynamic_cast(obj->net->fil); - assert(sig_fil); - - /* Attach the __vpiCallback object to the signal. */ - sig_fil->add_vpi_callback(cbh); + return obj; } #ifdef CHECK_WITH_VALGRIND void PV_delete(vpiHandle item) { - struct __vpiPV *obj = (__vpiPV *) item; + struct __vpiPV *obj = dynamic_cast<__vpiPV*>(item); if (obj->sbase) { switch (obj->sbase->vpi_type->type_code) { case vpiMemoryWord: @@ -1513,6 +1441,6 @@ void PV_delete(vpiHandle item) } assert(obj->net->fil); obj->net->fil->clear_all_callbacks(); - free(obj); + delete obj; } #endif diff --git a/vvp/vpi_tasks.cc b/vvp/vpi_tasks.cc index 7eee8f9c7..9c6029649 100644 --- a/vvp/vpi_tasks.cc +++ b/vvp/vpi_tasks.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -35,34 +35,25 @@ # include # include "ivl_alloc.h" -static const struct __vpirt vpip_systf_def_rt = { - vpiUserSystf, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; +inline __vpiUserSystf::__vpiUserSystf() +{ } + +int __vpiUserSystf::get_type_code(void) const +{ return vpiUserSystf; } + static vpiHandle systask_handle(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiScope: - return &rfp->scope->base; + return rfp->scope; case vpiUserSystf: /* Assert that vpiUserDefn is true! */ assert(rfp->defn->is_user_defn); - return &rfp->defn->base; + return rfp->defn; default: return 0; @@ -71,10 +62,7 @@ static vpiHandle systask_handle(int type, vpiHandle ref) static int systask_get(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { /* This is not the correct way to get this information, but @@ -99,9 +87,7 @@ static int systask_get(int type, vpiHandle ref) // support getting vpiSize for a system function call static int sysfunc_get(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert(ref->vpi_type->type_code == vpiSysFuncCall); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiSize: @@ -124,10 +110,7 @@ static int sysfunc_get(int type, vpiHandle ref) static char *systask_get_str(int type, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); switch (type) { case vpiFile: @@ -147,9 +130,7 @@ static char *systask_get_str(int type, vpiHandle ref) */ static vpiHandle systask_iter(int, vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); if (rfp->nargs == 0) return 0; @@ -157,21 +138,15 @@ static vpiHandle systask_iter(int, vpiHandle ref) return vpip_make_iterator(rfp->nargs, rfp->args, false); } -static const struct __vpirt vpip_systask_rt = { - vpiSysTaskCall, - systask_get, - systask_get_str, - 0, - 0, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct systask_def : public __vpiSysTaskCall { + inline systask_def() { } + int get_type_code(void) const { return vpiSysTaskCall; } + int vpi_get(int code) { return systask_get(code, this); } + char*vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_handle(int code) { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code){ return systask_iter(code, this); } }; - /* * A value *can* be put to a vpiSysFuncCall object. This is how the * return value is set. The value that is given should be converted to @@ -180,9 +155,8 @@ static const struct __vpirt vpip_systask_rt = { */ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(rfp); rfp->put_value = true; @@ -310,9 +284,7 @@ static vpiHandle sysfunc_put_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -338,9 +310,7 @@ static vpiHandle sysfunc_put_real_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -443,9 +413,7 @@ static vpiHandle sysfunc_put_4net_value(vpiHandle ref, p_vpi_value vp, int) static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); rfp->put_value = true; @@ -467,86 +435,85 @@ static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int) return 0; } -static vpiHandle sysfunc_put_no_value(vpiHandle ref, p_vpi_value, int) +static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int) { - assert(ref->vpi_type->type_code == vpiSysFuncCall); - return 0; } - -static const struct __vpirt vpip_sysfunc_rt = { - vpiSysFuncCall, - sysfunc_get, - systask_get_str, - 0, - sysfunc_put_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct sysfunc_def : public __vpiSysTaskCall { + inline sysfunc_def() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_real_rt = { - vpiSysFuncCall, - sysfunc_get, - systask_get_str, - 0, - sysfunc_put_real_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct sysfunc_real : public __vpiSysTaskCall { + inline sysfunc_real() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_real_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_4net_rt = { - vpiSysFuncCall, - sysfunc_get, - systask_get_str, - 0, - sysfunc_put_4net_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct sysfunc_4net : public __vpiSysTaskCall { + inline sysfunc_4net() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_4net_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_rnet_rt = { - vpiSysFuncCall, - sysfunc_get, - systask_get_str, - 0, - sysfunc_put_rnet_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct sysfunc_rnet : public __vpiSysTaskCall { + inline sysfunc_rnet() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_rnet_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; -static const struct __vpirt vpip_sysfunc_no_rt = { - vpiSysFuncCall, - sysfunc_get, - systask_get_str, - 0, - sysfunc_put_no_value, - systask_handle, - systask_iter, - 0, - 0, - 0, - 0 +struct sysfunc_no : public __vpiSysTaskCall { + inline sysfunc_no() { } + int get_type_code(void) const { return vpiSysFuncCall; } + int vpi_get(int code) { return sysfunc_get(code, this); } + char* vpi_get_str(int code) { return systask_get_str(code, this); } + vpiHandle vpi_put_value(p_vpi_value val, int flags) + { return sysfunc_put_no_value(this, val, flags); } + vpiHandle vpi_handle(int code) + { return systask_handle(code, this); } + vpiHandle vpi_iterate(int code) + { return systask_iter(code, this); } }; /* **** Manipulate the internal data structures. **** */ +/* + * We keep a table of all the __vpiUserSystf objects that are created + * so that the user can iterate over them. The def_table is an array + * of pointers to __vpiUserSystf objects. This table can be searched + * by name using the vpi_find_systf function, and they can be + * collected into an iterator using the vpip_make_systf_iterator function. + */ static struct __vpiUserSystf**def_table = 0; static unsigned def_count = 0; @@ -556,8 +523,7 @@ static struct __vpiUserSystf* allocate_def(void) def_table = (struct __vpiUserSystf**) malloc(sizeof (struct __vpiUserSystf*)); - def_table[0] = (struct __vpiUserSystf*) - calloc(1, sizeof(struct __vpiUserSystf)); + def_table[0] = new __vpiUserSystf; def_count = 1; return def_table[0]; @@ -566,8 +532,7 @@ static struct __vpiUserSystf* allocate_def(void) def_table = (struct __vpiUserSystf**) realloc(def_table, (def_count+1)*sizeof (struct __vpiUserSystf*)); - def_table[def_count] = (struct __vpiUserSystf*) - calloc(1, sizeof(struct __vpiUserSystf)); + def_table[def_count] = new __vpiUserSystf; return def_table[def_count++]; } @@ -577,7 +542,7 @@ void def_table_delete(void) { for (unsigned idx = 0; idx < def_count; idx += 1) { free(const_cast(def_table[idx]->info.tfname)); - free(def_table[idx]); + delete def_table[idx]; } free(def_table); def_table = 0; @@ -585,15 +550,18 @@ void def_table_delete(void) } #endif -struct __vpiSystfIterator { - struct __vpiHandle base; +struct __vpiSystfIterator : public __vpiHandle { + __vpiSystfIterator(); + int get_type_code(void) const; + vpiHandle vpi_index(int idx); + free_object_fun_t free_object_fun(void); + unsigned next; }; static vpiHandle systf_iterator_scan(vpiHandle ref, int) { - assert(ref->vpi_type->type_code == vpiIterator); - struct __vpiSystfIterator*obj = (struct __vpiSystfIterator*) ref; + struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref); if (obj->next >= def_count) { vpi_free_object(ref); @@ -610,30 +578,27 @@ static vpiHandle systf_iterator_scan(vpiHandle ref, int) } } obj->next += 1; - return &(def_table[use_index])->base; + return def_table[use_index]; } static int systf_iterator_free_object(vpiHandle ref) { - assert(ref->vpi_type->type_code == vpiIterator); - struct __vpiSystfIterator*obj = (struct __vpiSystfIterator*) ref; - free(obj); + struct __vpiSystfIterator*obj = dynamic_cast<__vpiSystfIterator*>(ref); + delete obj; return 1; } -static const struct __vpirt vpip_systf_iterator_rt = { - vpiIterator, - 0, - 0, - 0, - 0, - 0, - 0, - systf_iterator_scan, - systf_iterator_free_object, - 0, - 0 -}; +inline __vpiSystfIterator::__vpiSystfIterator() +{ } + +int __vpiSystfIterator::get_type_code(void) const +{ return vpiIterator; } + +vpiHandle __vpiSystfIterator::vpi_index(int idx) +{ return systf_iterator_scan(this, idx); } + +__vpiHandle::free_object_fun_t __vpiSystfIterator::free_object_fun(void) +{ return &systf_iterator_free_object; } vpiHandle vpip_make_systf_iterator(void) { @@ -648,11 +613,9 @@ vpiHandle vpip_make_systf_iterator(void) } if (!have_user_defn) return 0; - struct __vpiSystfIterator*res; - res = (struct __vpiSystfIterator*) calloc(1, sizeof (*res)); - res->base.vpi_type = &vpip_systf_iterator_rt; + struct __vpiSystfIterator*res = new __vpiSystfIterator; res->next = idx; - return &res->base; + return res; } struct __vpiUserSystf* vpip_find_systf(const char*name) @@ -667,8 +630,8 @@ struct __vpiUserSystf* vpip_find_systf(const char*name) void vpip_make_systf_system_defined(vpiHandle ref) { assert(ref); - assert(ref->vpi_type->type_code == vpiUserSystf); - struct __vpiUserSystf*obj = (__vpiUserSystf*) ref; + struct __vpiUserSystf*obj = dynamic_cast<__vpiUserSystf*>(ref); + assert(obj); obj->is_user_defn = false; } @@ -770,7 +733,7 @@ static void cleanup_vpi_call_args(unsigned argc, vpiHandle*argv) * vbit is also a non-zero value, the address in thread space of the result. */ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, - class vvp_net_t*fnet, + vvp_net_t*fnet, bool func_as_task_err, bool func_as_task_warn, unsigned argc, vpiHandle*argv, long file_idx, long lineno) @@ -821,28 +784,28 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, assert(0); } - struct __vpiSysTaskCall*obj = new struct __vpiSysTaskCall; + struct __vpiSysTaskCall*obj = 0; switch (defn->info.type) { case vpiSysTask: - obj->base.vpi_type = &vpip_systask_rt; + obj = new systask_def; break; case vpiSysFunc: if (fnet && vwid == -vpiRealConst) { - obj->base.vpi_type = &vpip_sysfunc_rnet_rt; + obj = new sysfunc_rnet; } else if (fnet && vwid > 0) { - obj->base.vpi_type = &vpip_sysfunc_4net_rt; + obj = new sysfunc_4net; } else if (vwid == -vpiRealConst) { - obj->base.vpi_type = &vpip_sysfunc_real_rt; + obj = new sysfunc_real; } else if (vwid > 0) { - obj->base.vpi_type = &vpip_sysfunc_rt; + obj = new sysfunc_def; } else if (vwid == 0 && fnet == 0) { - obj->base.vpi_type = &vpip_sysfunc_no_rt; + obj = new sysfunc_no; } else { assert(0); @@ -864,13 +827,13 @@ vpiHandle vpip_build_vpi_call(const char*name, unsigned vbit, int vwid, compile_compiletf(obj); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND void vpi_call_delete(vpiHandle item) { - struct __vpiSysTaskCall*obj = (struct __vpiSysTaskCall *) item; + struct __vpiSysTaskCall*obj = dynamic_cast<__vpiSysTaskCall*>(item); /* The object can be NULL if there was an error. */ if (!obj) return; for (unsigned arg = 0; arg < obj->nargs; arg += 1) { @@ -918,10 +881,7 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) { vpip_current_vthread = thr; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); - - vpip_cur_task = (struct __vpiSysTaskCall*)ref; + vpip_cur_task = dynamic_cast<__vpiSysTaskCall*>(ref); if (vpip_cur_task->defn->info.calltf) { assert(vpi_mode_flag == VPI_MODE_NONE); @@ -931,7 +891,7 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref) vpi_mode_flag = VPI_MODE_NONE; /* If the function call did not set a value then put a * default value (0). */ - if (ref->vpi_type->type_code == vpiSysFuncCall && + if (ref->get_type_code() == vpiSysFuncCall && !vpip_cur_task->put_value) { s_vpi_value val; if (vpip_cur_task->vwid == -vpiRealConst) { @@ -959,7 +919,6 @@ vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) switch (ss->type) { case vpiSysTask: case vpiSysFunc: - cur->base.vpi_type = &vpip_systf_def_rt; break; default: fprintf(stderr, "Unsupported type %d.\n", (int)ss->type); @@ -970,26 +929,23 @@ vpiHandle vpi_register_systf(const struct t_vpi_systf_data*ss) cur->info.tfname = strdup(ss->tfname); cur->is_user_defn = true; - return &cur->base; + return cur; } PLI_INT32 vpi_put_userdata(vpiHandle ref, void*data) { - if (ref->vpi_type->type_code != vpiSysTaskCall - && ref->vpi_type->type_code != vpiSysFuncCall) + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + if (rfp == 0) return 0; - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - rfp->userdata = data; return 1; } void* vpi_get_userdata(vpiHandle ref) { - struct __vpiSysTaskCall*rfp = (struct __vpiSysTaskCall*)ref; - assert((ref->vpi_type->type_code == vpiSysTaskCall) - || (ref->vpi_type->type_code == vpiSysFuncCall)); + struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref); + assert(rfp); return rfp->userdata; } diff --git a/vvp/vpi_time.cc b/vvp/vpi_time.cc index 167fbe6d8..0b5c55424 100644 --- a/vvp/vpi_time.cc +++ b/vvp/vpi_time.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -94,122 +94,6 @@ vvp_time64_t vpip_scaled_real_to_time64(double val, struct __vpiScope*scope) return delay; } -static int timevar_time_get(int code, vpiHandle) -{ - switch (code) { - case vpiSize: - return 64; - - case vpiSigned: - return 0; - - case vpiFuncType: - return vpiTimeFunc; - - case vpiAutomatic: - return 0; - - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static int timevar_stime_get(int code, vpiHandle ref) -{ - switch (code) { - case vpiSize: - return 32; - - default: - return timevar_time_get(code, ref); - } -} - -static char* timevar_time_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$time"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_stime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$stime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_simtime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$simtime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static char* timevar_realtime_get_str(int code, vpiHandle) -{ - switch (code) { - case vpiName: - return simple_set_rbuf_str("$realtime"); - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static int timevar_realtime_get(int code, vpiHandle) -{ - switch (code) { - case vpiSize: - return 1; - - case vpiSigned: - return 0; - - case vpiFuncType: - return vpiRealFunc; - - case vpiAutomatic: - return 0; - - default: - fprintf(stderr, "Code: %d\n", code); - assert(0); - return 0; - } -} - -static vpiHandle timevar_handle(int code, vpiHandle ref) -{ - struct __vpiSystemTime*rfp - = reinterpret_cast(ref); - - switch (code) { - case vpiScope: - return &rfp->scope->base; - default: - return 0; - } -} - static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func, bool is_stime) { @@ -217,8 +101,7 @@ static void timevar_get_value(vpiHandle ref, s_vpi_value*vp, bool is_int_func, the caller. */ static struct t_vpi_time time_value; - struct __vpiSystemTime*rfp - = reinterpret_cast(ref); + struct __vpiSystemTime*rfp = dynamic_cast<__vpiSystemTime*>(ref); unsigned long num_bits; vvp_time64_t x, simtime = schedule_simtime(); int units = rfp->scope? rfp->scope->time_units : vpi_time_precision; @@ -313,61 +196,156 @@ static void timevar_get_rvalue(vpiHandle ref, s_vpi_value*vp) timevar_get_value(ref, vp, false, false); } -static const struct __vpirt vpip_system_time_rt = { - vpiSysFuncCall, - timevar_time_get, - timevar_time_get_str, - timevar_get_ivalue, - 0, - timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; +__vpiScopedTime::__vpiScopedTime() +{ } -static const struct __vpirt vpip_system_stime_rt = { - vpiSysFuncCall, - timevar_stime_get, - timevar_stime_get_str, - timevar_get_svalue, - 0, - timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; +char* __vpiScopedTime::vpi_get_str(int code) +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$time"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} -static const struct __vpirt vpip_system_simtime_rt = { - vpiSysFuncCall, - timevar_time_get, - timevar_simtime_get_str, - timevar_get_ivalue, - 0, - timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; -static const struct __vpirt vpip_system_realtime_rt = { - vpiSysFuncCall, - timevar_realtime_get, - timevar_realtime_get_str, - timevar_get_rvalue, - 0, - timevar_handle, - 0, - 0, - 0, - 0, - 0 -}; +void __vpiScopedTime::vpi_get_value(p_vpi_value val) +{ timevar_get_ivalue(this, val); } + + +__vpiScopedSTime::__vpiScopedSTime() +{ } + +int __vpiScopedSTime::vpi_get(int code) +{ + switch (code) { + case vpiSize: + return 32; + + default: + return __vpiSystemTime::vpi_get(code); + } +} + + +char* __vpiScopedSTime::vpi_get_str(int code) +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$stime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + + +void __vpiScopedSTime::vpi_get_value(p_vpi_value val) +{ timevar_get_svalue(this, val); } + +__vpiSystemTime::__vpiSystemTime() +{ + scope = 0; +} + +int __vpiSystemTime::get_type_code(void) const +{ return vpiSysFuncCall; } + +int __vpiSystemTime::vpi_get(int code) +{ + switch (code) { + case vpiSize: + return 64; + + case vpiSigned: + return 0; + + case vpiFuncType: + return vpiTimeFunc; + + case vpiAutomatic: + return 0; + + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + + +char* __vpiSystemTime::vpi_get_str(int code) +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$simtime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + + +void __vpiSystemTime::vpi_get_value(p_vpi_value val) +{ timevar_get_ivalue(this, val); } + +vpiHandle __vpiSystemTime::vpi_handle(int code) +{ + switch (code) { + case vpiScope: + return scope; + default: + return 0; + } +} + + +__vpiScopedRealtime::__vpiScopedRealtime() +{ } + +int __vpiScopedRealtime::vpi_get(int code) +{ + switch (code) { + case vpiSize: + return 1; + + case vpiSigned: + return 0; + + case vpiFuncType: + return vpiRealFunc; + + case vpiAutomatic: + return 0; + + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + + +char* __vpiScopedRealtime::vpi_get_str(int code) +{ + switch (code) { + case vpiName: + return simple_set_rbuf_str("$realtime"); + default: + fprintf(stderr, "Code: %d\n", code); + assert(0); + return 0; + } +} + + +void __vpiScopedRealtime::vpi_get_value(p_vpi_value val) +{ timevar_get_rvalue(this, val); } /* * Create a handle to represent a call to $time/$stime/$simtime. The @@ -378,26 +356,21 @@ vpiHandle vpip_sim_time(struct __vpiScope*scope, bool is_stime) { if (scope) { if (is_stime) { - scope->scoped_stime.base.vpi_type = &vpip_system_stime_rt; scope->scoped_stime.scope = scope; - return &scope->scoped_stime.base; + return &scope->scoped_stime; } else { - scope->scoped_time.base.vpi_type = &vpip_system_time_rt; scope->scoped_time.scope = scope; - return &scope->scoped_time.base; + return &scope->scoped_time; } } else { - global_simtime.base.vpi_type = &vpip_system_simtime_rt; - global_simtime.scope = 0; - return &global_simtime.base; + return &global_simtime; } } vpiHandle vpip_sim_realtime(struct __vpiScope*scope) { - scope->scoped_realtime.base.vpi_type = &vpip_system_realtime_rt; scope->scoped_realtime.scope = scope; - return &scope->scoped_realtime.base; + return &scope->scoped_realtime; } int vpip_get_time_precision(void) diff --git a/vvp/vpi_vthr_vector.cc b/vvp/vpi_vthr_vector.cc index 785ccbbe1..e69ad7d47 100644 --- a/vvp/vpi_vthr_vector.cc +++ b/vvp/vpi_vthr_vector.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2001 Stephan Boettcher * * This source code is free software; you can redistribute it @@ -35,8 +35,14 @@ # include # include "ivl_alloc.h" -struct __vpiVThrVec { - struct __vpiHandle base; +struct __vpiVThrVec : public __vpiHandle { + __vpiVThrVec(); + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + unsigned bas; unsigned wid; unsigned signed_flag : 1; @@ -77,11 +83,8 @@ extern const char oct_digits[64]; */ static int vthr_vec_get(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); switch (code) { @@ -106,11 +109,8 @@ static int vthr_vec_get(int code, vpiHandle ref) static char* vthr_vec_get_str(int code, vpiHandle ref) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); switch (code) { @@ -177,11 +177,8 @@ static void vthr_vec_StringVal(struct __vpiVThrVec*rfp, s_vpi_value*vp) */ static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg) - || (ref->vpi_type->type_code==vpiConstant)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); char *rbuf; unsigned wid = rfp->wid; @@ -363,10 +360,8 @@ static void vthr_vec_get_value(vpiHandle ref, s_vpi_value*vp) */ static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int) { - assert((ref->vpi_type->type_code==vpiNet) - || (ref->vpi_type->type_code==vpiReg)); - - struct __vpiVThrVec*rfp = (struct __vpiVThrVec*)ref; + struct __vpiVThrVec*rfp = dynamic_cast<__vpiVThrVec*>(ref); + assert(rfp); unsigned wid = rfp->wid; @@ -443,19 +438,23 @@ static vpiHandle vthr_vec_put_value(vpiHandle ref, s_vpi_value*vp, int) // The code fully supports vpiReg, vpi_Net, but we do not // create such things, yet. Lacking a name, for example. -static const struct __vpirt vpip_vthr_const_rt = { - vpiConstant, - vthr_vec_get, - vthr_vec_get_str, - vthr_vec_get_value, - vthr_vec_put_value, - 0, - 0, - 0, - 0, - 0, - 0 -}; +inline __vpiVThrVec::__vpiVThrVec() +{ } + +int __vpiVThrVec::get_type_code(void) const +{ return vpiConstant; } + +int __vpiVThrVec::vpi_get(int code) +{ return vthr_vec_get(code, this); } + +char* __vpiVThrVec::vpi_get_str(int code) +{ return vthr_vec_get_str(code, this); } + +void __vpiVThrVec::vpi_get_value(p_vpi_value val) +{ vthr_vec_get_value(this, val); } + +vpiHandle __vpiVThrVec::vpi_put_value(p_vpi_value val, int flags) +{ return vthr_vec_put_value(this, val, flags); } /* * Construct a vpiReg object. Give the object specified dimensions, @@ -463,9 +462,7 @@ static const struct __vpirt vpip_vthr_const_rt = { */ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag) { - struct __vpiVThrVec*obj = (struct __vpiVThrVec*) - malloc(sizeof(struct __vpiVThrVec)); - obj->base.vpi_type = &vpip_vthr_const_rt; + struct __vpiVThrVec*obj = new __vpiVThrVec; assert(base < 65536); obj->bas = base; assert(wid < 65536); @@ -473,7 +470,7 @@ vpiHandle vpip_make_vthr_vector(unsigned base, unsigned wid, bool signed_flag) obj->signed_flag = signed_flag? 1 : 0; obj->name = vpip_name_string("T<>"); - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -486,13 +483,17 @@ void thread_vthr_delete(vpiHandle item) static void thread_vthr_delete_real(vpiHandle item) { - struct __vpiVThrVec*obj = (struct __vpiVThrVec*)item; - free (obj); + struct __vpiVThrVec*obj = dynamic_cast<__vpiVThrVec*>(item); + delete obj; } #endif -struct __vpiVThrWord { - struct __vpiHandle base; +struct __vpiVThrWord : public __vpiHandle { + __vpiVThrWord(); + int get_type_code(void) const; + int vpi_get(int code); + void vpi_get_value(p_vpi_value val); + const char* name; int subtype; unsigned index; @@ -500,9 +501,7 @@ struct __vpiVThrWord { static int vthr_word_get(int code, vpiHandle ref) { - assert(ref->vpi_type->type_code==vpiConstant); - - struct __vpiVThrWord*rfp = (struct __vpiVThrWord*)ref; + struct __vpiVThrWord*rfp = dynamic_cast<__vpiVThrWord*>(ref); switch (code) { @@ -521,9 +520,7 @@ static int vthr_word_get(int code, vpiHandle ref) static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) { - assert(ref->vpi_type->type_code==vpiConstant); - - struct __vpiVThrWord*obj = (struct __vpiVThrWord*)ref; + struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(ref); char *rbuf = need_result_buf(66, RBUF_VAL); double val = 0.0; @@ -591,34 +588,30 @@ static void vthr_real_get_value(vpiHandle ref, s_vpi_value*vp) } } -static const struct __vpirt vpip_vthr_const_real_rt = { - vpiConstant, - vthr_word_get, - 0, - vthr_real_get_value, - 0, - 0, - 0, - 0, - 0, - 0, - 0 -}; +inline __vpiVThrWord::__vpiVThrWord() +{ } + +int __vpiVThrWord::get_type_code(void) const +{ return vpiConstant; } + +int __vpiVThrWord::vpi_get(int code) +{ return vthr_word_get(code, this); } + +void __vpiVThrWord::vpi_get_value(p_vpi_value val) +{ vthr_real_get_value(this, val); } vpiHandle vpip_make_vthr_word(unsigned base, const char*type) { - struct __vpiVThrWord*obj = (struct __vpiVThrWord*) - malloc(sizeof(struct __vpiVThrWord)); + struct __vpiVThrWord*obj = new __vpiVThrWord; assert(type[0] == 'r'); - obj->base.vpi_type = &vpip_vthr_const_real_rt; obj->name = vpip_name_string("W<>"); obj->subtype = vpiRealConst; assert(base < 65536); obj->index = base; - return &obj->base; + return obj; } #ifdef CHECK_WITH_VALGRIND @@ -629,8 +622,8 @@ void thread_word_delete(vpiHandle item) static void thread_word_delete_real(vpiHandle item) { - struct __vpiVThrWord*obj = (struct __vpiVThrWord*)item; - free(obj); + struct __vpiVThrWord*obj = dynamic_cast<__vpiVThrWord*>(item); + delete obj; } void vpi_handle_delete() diff --git a/vvp/vthread.cc b/vvp/vthread.cc index a949d00e9..86e1d44ff 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2012 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 @@ -1173,7 +1173,7 @@ bool of_ASSIGN_WR(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - struct __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1192,7 +1192,7 @@ bool of_ASSIGN_WRD(vthread_t thr, vvp_code_t cp) del.type = vpiSimTime; vpip_time_to_timestruct(&del, delay); - struct __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -1206,7 +1206,7 @@ bool of_ASSIGN_WRE(vthread_t thr, vvp_code_t cp) { assert(thr->event != 0); unsigned index = cp->bit_idx[0]; - struct __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; // If the count is zero then just put the value. if (thr->ecount == 0) { @@ -2549,7 +2549,7 @@ bool of_FORK(vthread_t thr, vvp_code_t cp) /* If the new child was created to evaluate a function, run it immediately, then return to this thread. */ - if (cp->scope->base.vpi_type->type_code == vpiFunction) { + if (cp->scope->get_type_code() == vpiFunction) { child->is_scheduled = 1; vthread_run(child); running_thread = thr; @@ -3184,7 +3184,7 @@ bool of_LOAD_VP0_S(vthread_t thr, vvp_code_t cp) bool of_LOAD_WR(vthread_t thr, vvp_code_t cp) { - struct __vpiHandle*tmp = cp->handle; + __vpiHandle*tmp = cp->handle; t_vpi_value val; val.format = vpiRealVal; @@ -3574,8 +3574,6 @@ bool of_PAD(vthread_t thr, vvp_code_t cp) vvp_vector4_t tmp (cp->number, pad_bit); thr->bits4.set_vec(cp->bit_idx[0], tmp); return true; - - return true; } /* diff --git a/vvp/vvp_cleanup.h b/vvp/vvp_cleanup.h index c223f46dc..9fcc2f7a5 100644 --- a/vvp/vvp_cleanup.h +++ b/vvp/vvp_cleanup.h @@ -1,7 +1,7 @@ #ifndef __vvp_cleanup_H #define __vvp_cleanup_H /* - * Copyright (c) 2009-2011 Cary R. (cygcary@yahoo.com) + * Copyright (c) 2009-2012 Cary R. (cygcary@yahoo.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 @@ -39,19 +39,19 @@ extern void vpi_handle_delete(void); extern void vvp_net_pool_delete(void); extern void ufunc_pool_delete(void); -extern void A_delete(struct __vpiHandle *item); -extern void PV_delete(struct __vpiHandle *item); -extern void constant_delete(struct __vpiHandle *item); +extern void A_delete(class __vpiHandle *item); +extern void PV_delete(class __vpiHandle *item); +extern void constant_delete(class __vpiHandle *item); extern void contexts_delete(struct __vpiScope *scope); -extern void enum_delete(struct __vpiHandle *item); -extern void memory_delete(struct __vpiHandle *item); -extern void named_event_delete(struct __vpiHandle *item); -extern void parameter_delete(struct __vpiHandle *item); -extern void signal_delete(struct __vpiHandle *item); -extern void real_delete(struct __vpiHandle *item); -extern void thread_vthr_delete(struct __vpiHandle *item); -extern void thread_word_delete(struct __vpiHandle *item); -extern void vpi_call_delete(struct __vpiHandle *item); +extern void enum_delete(class __vpiHandle *item); +extern void memory_delete(class __vpiHandle *item); +extern void named_event_delete(class __vpiHandle *item); +extern void parameter_delete(class __vpiHandle *item); +extern void signal_delete(class __vpiHandle *item); +extern void real_delete(class __vpiHandle *item); +extern void thread_vthr_delete(class __vpiHandle *item); +extern void thread_word_delete(class __vpiHandle *item); +extern void vpi_call_delete(class __vpiHandle *item); extern void exec_ufunc_delete(vvp_code_t euf_code); extern void vthreads_delete(struct __vpiScope*scope); extern void vvp_net_delete(vvp_net_t *item); diff --git a/vvp/vvp_island.cc b/vvp/vvp_island.cc index 49c167e75..f799d9809 100644 --- a/vvp/vvp_island.cc +++ b/vvp/vvp_island.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2008-2010,2012 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 @@ -94,6 +94,9 @@ void vvp_island::add_port(const char*key, vvp_net_t*net) if (ports_ == 0) ports_ = new symbol_map_s; + // each port should have a unique label + assert(ports_->sym_get_value(key) == 0); + ports_->sym_set_value(key, net); } diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index d0128940e..569f83ba7 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -449,7 +449,7 @@ int edge(vvp_bit4_t from, vvp_bit4_t to) void vvp_send_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&val) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -461,7 +461,7 @@ void vvp_send_vec8(vvp_net_ptr_t ptr, const vvp_vector8_t&val) void vvp_send_real(vvp_net_ptr_t ptr, double val, vvp_context_t context) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -473,7 +473,7 @@ void vvp_send_real(vvp_net_ptr_t ptr, double val, vvp_context_t context) void vvp_send_long(vvp_net_ptr_t ptr, long val) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -486,7 +486,7 @@ void vvp_send_long(vvp_net_ptr_t ptr, long val) void vvp_send_long_pv(vvp_net_ptr_t ptr, long val, unsigned base, unsigned wid) { - while (class vvp_net_t*cur = ptr.ptr()) { + while (vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; if (cur->fun) @@ -1023,9 +1023,10 @@ void vvp_vector4_t::setarray(unsigned adr, unsigned wid, const unsigned long*val * into the addressed part of this vector. Use bit masking and word * copies to go as fast as reasonably possible. */ -void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) +bool vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) { assert(adr+that.size_ <= size_); + bool diff_flag = false; if (size_ <= BITS_PER_WORD) { @@ -1046,12 +1047,16 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) hmask = (1UL << (adr+that.size_)) - 1; unsigned long mask = hmask & ~lmask; - abits_val_ = - (abits_val_ & ~mask) - | ((that.abits_val_< BITS_PER_WORD) { unsigned tail = doff + that.size_ - BITS_PER_WORD; mask = (1UL << tail) - 1; dptr += 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~mask) - | ((that.abits_val_ >> (that.size_-tail)) & mask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~mask) - | ((that.bbits_val_ >> (that.size_-tail)) & mask); + tmp = (that.abits_val_ >> (that.size_-tail)) & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_val_ >> (that.size_-tail)) & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } else if (adr%BITS_PER_WORD == 0) { @@ -1102,8 +1116,14 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) unsigned sptr = 0; unsigned dptr = adr / BITS_PER_WORD; while (remain >= BITS_PER_WORD) { - abits_ptr_[dptr] = that.abits_ptr_[sptr]; - bbits_ptr_[dptr] = that.bbits_ptr_[sptr]; + if (abits_ptr_[dptr] != that.abits_ptr_[sptr]) { + diff_flag = true; + abits_ptr_[dptr] = that.abits_ptr_[sptr]; + } + if (bbits_ptr_[dptr] != that.bbits_ptr_[sptr]) { + diff_flag = true; + bbits_ptr_[dptr] = that.bbits_ptr_[sptr]; + } dptr += 1; sptr += 1; remain -= BITS_PER_WORD; @@ -1111,12 +1131,18 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) if (remain > 0) { unsigned long mask = (1UL << remain) - 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~mask) - | (that.abits_ptr_[sptr] & mask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~mask) - | (that.bbits_ptr_[sptr] & mask); + unsigned long tmp; + + tmp = that.abits_ptr_[sptr] & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = that.bbits_ptr_[sptr] & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } else { @@ -1131,20 +1157,30 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) unsigned long lmask = (1UL << doff) - 1; unsigned ndoff = BITS_PER_WORD - doff; while (remain >= BITS_PER_WORD) { - abits_ptr_[dptr] = - (abits_ptr_[dptr] & lmask) - | ((that.abits_ptr_[sptr] << doff) & ~lmask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & lmask) - | ((that.bbits_ptr_[sptr] << doff) & ~lmask); + unsigned long tmp; + + tmp = (that.abits_ptr_[sptr] << doff) & ~lmask; + if ((abits_ptr_[dptr] & ~lmask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & lmask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] << doff) & ~lmask; + if ((bbits_ptr_[dptr] & ~lmask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & lmask) | tmp; + } dptr += 1; - abits_ptr_[dptr] = - (abits_ptr_[dptr] & ~lmask) - | ((that.abits_ptr_[sptr] >> ndoff) & lmask); - bbits_ptr_[dptr] = - (bbits_ptr_[dptr] & ~lmask) - | ((that.bbits_ptr_[sptr] >> ndoff) & lmask); + tmp = (that.abits_ptr_[sptr] >> ndoff) & lmask; + if ((abits_ptr_[dptr] & lmask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~lmask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] >> ndoff) & lmask; + if ((bbits_ptr_[dptr] & lmask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~lmask) | tmp; + } remain -= BITS_PER_WORD; sptr += 1; @@ -1159,11 +1195,18 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) hmask = (1UL << (doff+remain)) - 1; unsigned long mask = hmask & ~lmask; + unsigned long tmp; - abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) - | ((that.abits_ptr_[sptr] << doff) & mask); - bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) - | ((that.bbits_ptr_[sptr] << doff) & mask); + tmp = (that.abits_ptr_[sptr] << doff) & mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] << doff) & mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } if ((doff + remain) > BITS_PER_WORD) { unsigned tail = doff + remain - BITS_PER_WORD; @@ -1173,14 +1216,22 @@ void vvp_vector4_t::set_vec(unsigned adr, const vvp_vector4_t&that) mask = (1UL << tail) - 1; dptr += 1; - abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | - ((that.abits_ptr_[sptr] >> (remain-tail))&mask); - bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | - ((that.bbits_ptr_[sptr] >> (remain-tail))&mask); + + tmp = (that.abits_ptr_[sptr] >> (remain-tail))&mask; + if ((abits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + abits_ptr_[dptr] = (abits_ptr_[dptr] & ~mask) | tmp; + } + tmp = (that.bbits_ptr_[sptr] >> (remain-tail))&mask; + if ((bbits_ptr_[dptr] & mask) != tmp) { + diff_flag = true; + bbits_ptr_[dptr] = (bbits_ptr_[dptr] & ~mask) | tmp; + } } } } + return diff_flag; } void vvp_vector4_t::mov(unsigned dst, unsigned src, unsigned cnt) diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index 5fd8525cc..e3456bbc7 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -234,8 +234,10 @@ class vvp_vector4_t { unsigned long*subarray(unsigned idx, unsigned size) const; void setarray(unsigned idx, unsigned size, const unsigned long*val); + // Set a 4-value bit or subvector into the vector. Return true + // if any bits of the vector change as a result of this operation. void set_bit(unsigned idx, vvp_bit4_t val); - void set_vec(unsigned idx, const vvp_vector4_t&that); + bool set_vec(unsigned idx, const vvp_vector4_t&that); // Get the bits from another vector, but keep my size. void copy_bits(const vvp_vector4_t&that); @@ -1188,11 +1190,10 @@ class vvp_net_fun_t { /* * A vvp_net_fil_t is a filter object that filters an output from a - * vvp_net_t. The send_*() methods of the vvp_net_t object call the + * vvp_net_t. The send_*() methods of the vvp_net_t object invoke the * filter of the output being transmitted. The filter function will - * decide if this value is to be propagated, and return true or - * false. If false, then send_*() continues as usual. If false, output - * propagation is stopped. + * decide if this value is to be propagated, and how, and return a + * prop_t enumeration to reflect the choice. * * The filter object also provides an implementation hooks for * force/release. @@ -1546,10 +1547,9 @@ inline void vvp_send_vec4_pv(vvp_net_ptr_t ptr, const vvp_vector4_t&val, } } -inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, - unsigned base, unsigned wid, unsigned vwid) +inline void vvp_send_vec8_pv(vvp_net_ptr_t ptr, const vvp_vector8_t&val, + unsigned base, unsigned wid, unsigned vwid) { - vvp_net_ptr_t ptr = out_; while (class vvp_net_t*cur = ptr.ptr()) { vvp_net_ptr_t next = cur->port[ptr.port()]; @@ -1623,6 +1623,28 @@ inline void vvp_net_t::send_vec8(const vvp_vector8_t&val) } } +inline void vvp_net_t::send_vec8_pv(const vvp_vector8_t&val, + unsigned base, unsigned wid, unsigned vwid) +{ + if (fil == 0) { + vvp_send_vec8_pv(out_, val, base, wid, vwid); + return; + } + + assert(val.size() == wid); + vvp_vector8_t rep; + switch (fil->filter_vec8(val, rep, base, vwid)) { + case vvp_net_fil_t::STOP: + break; + case vvp_net_fil_t::PROP: + vvp_send_vec8_pv(out_, val, base, wid, vwid); + break; + case vvp_net_fil_t::REPL: + vvp_send_vec8_pv(out_, rep, base, wid, vwid); + break; + } +} + inline void vvp_net_t::send_real(double val, vvp_context_t context) { if (fil && ! fil->filter_real(val)) diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 1da9edb85..ce47a0959 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -30,9 +30,26 @@ # include +/* + * The filter_mask_ method takes as an input the value to propagate, + * the mask of what is being forced, and returns a propagation + * mode. In the process, it may update the filtered output value. + * + * The input value is the subvector "val" that is placed as "base" in + * the output. The val may be shorter then the target vector. + * + * The "force" vector in the value being force, with the force_mask_ + * member a bit mask of which parts of the force vector really apply. + */ template vvp_net_fil_t::prop_t vvp_net_fil_t::filter_mask_(const T&val, const T&force, T&filter, unsigned base) { if (!test_force_mask_is_zero()) { + // Some bits are being forced. Go through the + // force_mask_ and force value to see which bits are + // propagated and which are kept from the forced + // value. Update the filter with the filtered result and + // return REPL to indicate that some bits have changed, + // or STOP if no bits change. bool propagate_flag = force_propagate_; force_propagate_ = false; assert(force_mask_.size() == force.size()); @@ -639,7 +656,8 @@ vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec4(const vvp_vector4_t&bit, vvp_ve if (bits4_ .eeq( bit ) && !needs_init_) return STOP; bits4_ = bit; } else { - bits4_.set_vec(base, bit); + bool rc = bits4_.set_vec(base, bit); + if (rc == false && !needs_init_) return STOP; } needs_init_ = false; @@ -651,12 +669,21 @@ vvp_net_fil_t::prop_t vvp_wire_vec4::filter_vec8(const vvp_vector8_t&bit, unsigned base, unsigned vwid) { - // For now there is no support for a non-zero base. - assert(0 == base); assert(bits4_.size() == vwid); - assert(bits4_.size() == bit.size()); - bits4_ = reduce4(bit); - return filter_mask_(bit, vvp_vector8_t(force4_,6,6), rep, 0); + + // Keep track of the value being driven from this net, even if + // it is not ultimately what survives the force filter. + vvp_vector4_t bit4 (reduce4(bit)); + if (base==0 && bit4.size()==vwid) { + if (bits4_ .eeq( bit4 ) && !needs_init_) return STOP; + bits4_ = bit4; + } else { + bool rc = bits4_.set_vec(base, bit4); + if (rc == false && !needs_init_) return STOP; + } + + needs_init_ = false; + return filter_mask_(bit, vvp_vector8_t(force4_,6,6), rep, base); } unsigned vvp_wire_vec4::filter_size() const diff --git a/vvp/vvp_vpi_callback.h b/vvp/vvp_vpi_callback.h index 6a9cc2f35..3b2a3802a 100644 --- a/vvp/vvp_vpi_callback.h +++ b/vvp/vvp_vpi_callback.h @@ -22,6 +22,8 @@ # include "config.h" # include "vpi_user.h" +class value_callback; + /* * Things derived from vvp_vpi_callback may have callbacks * attached. This is how vpi callbacks are attached to the vvp @@ -38,7 +40,7 @@ class vvp_vpi_callback { void attach_as_word(struct __vpiArray* arr, unsigned long addr); - void add_vpi_callback(struct __vpiCallback*); + void add_vpi_callback(value_callback*); #ifdef CHECK_WITH_VALGRIND /* This has only been tested at EOS. */ void clear_all_callbacks(void); @@ -54,7 +56,7 @@ class vvp_vpi_callback { void run_vpi_callbacks(); private: - struct __vpiCallback*vpi_callbacks_; + value_callback*vpi_callbacks_; struct __vpiArray* array_; unsigned long array_word_; };